Prepare startContainer() to have more action

Currently startContainer() is used to create and to run a container.
In the next patch it will be used to restore a container.

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
Andrei Vagin 2017-03-02 10:48:00 +03:00
parent 1a8b0aced5
commit a4fcbfb704
5 changed files with 37 additions and 113 deletions

View File

@ -62,7 +62,7 @@ command(s) that get executed on start, edit the args parameter of the spec. See
if err != nil {
return err
}
status, err := startContainer(context, spec, true)
status, err := startContainer(context, spec, CT_ACT_CREATE, nil)
if err != nil {
return err
}

View File

@ -135,6 +135,7 @@ func execProcess(context *cli.Context) (int, error) {
consoleSocket: context.String("console-socket"),
detach: detach,
pidFile: context.String("pid-file"),
action: CT_ACT_RUN,
}
return r.run(p)
}

View File

@ -5,13 +5,8 @@ package main
import (
"fmt"
"os"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/specconv"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
)
@ -92,111 +87,22 @@ using the runc checkpoint command.`,
return fmt.Errorf("runc restore requires root")
}
imagePath := context.String("image-path")
id := context.Args().First()
if id == "" {
return errEmptyID
}
if imagePath == "" {
imagePath = getDefaultImagePath(context)
}
bundle := context.String("bundle")
if bundle != "" {
if err := os.Chdir(bundle); err != nil {
return err
}
}
spec, err := loadSpec(specConfig)
spec, err := setupSpec(context)
if err != nil {
return err
}
config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
CgroupName: id,
UseSystemdCgroup: context.GlobalBool("systemd-cgroup"),
NoPivotRoot: context.Bool("no-pivot"),
Spec: spec,
})
options := criuOptions(context)
status, err := startContainer(context, spec, CT_ACT_RESTORE, options)
if err != nil {
return err
}
status, err := restoreContainer(context, spec, config, imagePath)
if err == nil {
os.Exit(status)
}
return err
// exit with the container's exit status so any external supervisor is
// notified of the exit with the correct exit status.
os.Exit(status)
return nil
},
}
func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Config, imagePath string) (int, error) {
var (
rootuid = 0
rootgid = 0
id = context.Args().First()
)
factory, err := loadFactory(context)
if err != nil {
return -1, err
}
container, err := factory.Load(id)
if err != nil {
container, err = factory.Create(id, config)
if err != nil {
return -1, err
}
}
options := criuOptions(context)
status, err := container.Status()
if err != nil {
logrus.Error(err)
}
if status == libcontainer.Running {
fatalf("Container with id %s already running", id)
}
setManageCgroupsMode(context, options)
if err = setEmptyNsMask(context, options); err != nil {
return -1, err
}
// ensure that the container is always removed if we were the process
// that created it.
detach := context.Bool("detach")
if !detach {
defer destroy(container)
}
process := &libcontainer.Process{}
tty, err := setupIO(process, rootuid, rootgid, false, detach, "")
if err != nil {
return -1, err
}
notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id)
if notifySocket != nil {
notifySocket.setupSpec(context, spec)
notifySocket.setupSocket()
}
handler := newSignalHandler(!context.Bool("no-subreaper"), notifySocket)
if err := container.Restore(process, options); err != nil {
return -1, err
}
// We don't need to do a tty.recvtty because config.Terminal is always false.
defer tty.Close()
if err := tty.ClosePostStart(); err != nil {
return -1, err
}
if pidFile := context.String("pid-file"); pidFile != "" {
if err := createPidFile(pidFile, process); err != nil {
_ = process.Signal(syscall.SIGKILL)
_, _ = process.Wait()
return -1, err
}
}
return handler.forward(process, tty, detach)
}
func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
imagePath := getCheckpointImagePath(context)
if err := os.MkdirAll(imagePath, 0655); err != nil {

2
run.go
View File

@ -73,7 +73,7 @@ command(s) that get executed on start, edit the args parameter of the spec. See
if err != nil {
return err
}
status, err := startContainer(context, spec, false)
status, err := startContainer(context, spec, CT_ACT_RUN, nil)
if err == nil {
// exit with the container's exit status so any external supervisor is
// notified of the exit with the correct exit status.

View File

@ -220,8 +220,9 @@ type runner struct {
pidFile string
consoleSocket string
container libcontainer.Container
create bool
action CtAct
notifySocket *notifySocket
criuOpts *libcontainer.CriuOpts
}
func (r *runner) run(config *specs.Process) (int, error) {
@ -253,12 +254,8 @@ func (r *runner) run(config *specs.Process) (int, error) {
return -1, err
}
var (
detach = r.detach || r.create
startFn = r.container.Start
detach = r.detach || (r.action == CT_ACT_CREATE)
)
if !r.create {
startFn = r.container.Run
}
// Setting up IO is a two stage process. We need to modify process to deal
// with detaching containers, and then we get a tty after the container has
// started.
@ -269,7 +266,18 @@ func (r *runner) run(config *specs.Process) (int, error) {
return -1, err
}
defer tty.Close()
if err = startFn(process); err != nil {
switch r.action {
case CT_ACT_CREATE:
err = r.container.Start(process)
case CT_ACT_RESTORE:
err = r.container.Restore(process, r.criuOpts)
case CT_ACT_RUN:
err = r.container.Run(process)
default:
panic("Unknown action")
}
if err != nil {
r.destroy()
return -1, err
}
@ -313,7 +321,7 @@ func (r *runner) terminate(p *libcontainer.Process) {
}
func (r *runner) checkTerminal(config *specs.Process) error {
detach := r.detach || r.create
detach := r.detach || (r.action == CT_ACT_CREATE)
// Check command-line for sanity.
if detach && config.Terminal && r.consoleSocket == "" {
return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket")
@ -337,7 +345,15 @@ func validateProcessSpec(spec *specs.Process) error {
return nil
}
func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, error) {
type CtAct uint8
const (
CT_ACT_CREATE CtAct = iota + 1
CT_ACT_RUN
CT_ACT_RESTORE
)
func startContainer(context *cli.Context, spec *specs.Spec, action CtAct, criuOpts *libcontainer.CriuOpts) (int, error) {
id := context.Args().First()
if id == "" {
return -1, errEmptyID
@ -372,7 +388,8 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
detach: context.Bool("detach"),
pidFile: context.String("pid-file"),
preserveFDs: context.Int("preserve-fds"),
create: create,
action: action,
criuOpts: criuOpts,
}
return r.run(&spec.Process)
}