Files
runc/restore.go
T
Fabio Kung 85f40c2bc7 container id is the cgroup name
Without this, multiple runc containers can accidentally share the same cgroup(s)
(and change each other's limits), when runc is invoked from the same directory
(i.e.: same cwd on multiple runc executions).

After these changes, each runc container will run on its own cgroup(s). Before,
the only workaround was to invoke runc from an unique (temporary?) cwd for each
container.

Common cgroup configuration (and hierarchical limits) can be set by having
multiple runc containers share the same cgroup parent, which is the cgroup of
the process executing runc.

Signed-off-by: Fabio Kung <fabio.kung@gmail.com>
2015-08-10 16:41:39 -07:00

112 lines
3.1 KiB
Go

// +build linux
package main
import (
"os"
"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/specs"
)
var restoreCommand = cli.Command{
Name: "restore",
Usage: "restore a container from a previous checkpoint",
Flags: []cli.Flag{
cli.StringFlag{Name: "image-path", Value: "", Usage: "path to criu image files for restoring"},
cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"},
cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"},
cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"},
cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"},
cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
},
Action: func(context *cli.Context) {
imagePath := context.String("image-path")
if imagePath == "" {
imagePath = getDefaultImagePath(context)
}
spec, err := loadSpec(context.Args().First())
if err != nil {
fatal(err)
}
config, err := createLibcontainerConfig(context.GlobalString("id"), spec)
if err != nil {
fatal(err)
}
status, err := restoreContainer(context, spec, config, imagePath)
if err != nil {
fatal(err)
}
os.Exit(status)
},
}
func restoreContainer(context *cli.Context, spec *specs.LinuxSpec, config *configs.Config, imagePath string) (code int, err error) {
rootuid := 0
factory, err := loadFactory(context)
if err != nil {
return -1, err
}
container, err := factory.Load(context.GlobalString("id"))
if err != nil {
container, err = factory.Create(context.GlobalString("id"), config)
if err != nil {
return -1, err
}
}
options := criuOptions(context)
// ensure that the container is always removed if we were the process
// that created it.
defer func() {
if err != nil {
return
}
status, err := container.Status()
if err != nil {
logrus.Error(err)
}
if status != libcontainer.Checkpointed {
if err := container.Destroy(); err != nil {
logrus.Error(err)
}
if err := os.RemoveAll(options.ImagesDirectory); err != nil {
logrus.Error(err)
}
}
}()
process := &libcontainer.Process{
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
tty, err := newTty(spec.Process.Terminal, process, rootuid)
if err != nil {
return -1, err
}
handler := newSignalHandler(tty)
defer handler.Close()
if err := container.Restore(process, options); err != nil {
return -1, err
}
return handler.forward(process)
}
func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
imagePath := getCheckpointImagePath(context)
if err := os.MkdirAll(imagePath, 0655); err != nil {
fatal(err)
}
return &libcontainer.CriuOpts{
ImagesDirectory: imagePath,
WorkDirectory: context.String("work-path"),
LeaveRunning: context.Bool("leave-running"),
TcpEstablished: true, // context.Bool("tcp-established"),
ExternalUnixConnections: context.Bool("ext-unix-sk"),
ShellJob: context.Bool("shell-job"),
FileLocks: context.Bool("file-locks"),
}
}