From a4fcbfb704173c452af0e51d30969c43e427fb4b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 2 Mar 2017 10:48:00 +0300 Subject: [PATCH] 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 --- create.go | 2 +- exec.go | 1 + restore.go | 108 ++++--------------------------------------------- run.go | 2 +- utils_linux.go | 37 ++++++++++++----- 5 files changed, 37 insertions(+), 113 deletions(-) diff --git a/create.go b/create.go index 096e8e335..5f3ac6095 100644 --- a/create.go +++ b/create.go @@ -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 } diff --git a/exec.go b/exec.go index 22f2689ab..922e6272a 100644 --- a/exec.go +++ b/exec.go @@ -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) } diff --git a/restore.go b/restore.go index 7ddc3373b..ecd1d6263 100644 --- a/restore.go +++ b/restore.go @@ -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 { diff --git a/run.go b/run.go index ebec222ec..f8d631784 100644 --- a/run.go +++ b/run.go @@ -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. diff --git a/utils_linux.go b/utils_linux.go index c6a8c028e..a830542a3 100644 --- a/utils_linux.go +++ b/utils_linux.go @@ -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) }