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
+7 -101
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 {