123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- // +build linux
- package runc
- import (
- "os"
- "syscall"
- "github.com/Sirupsen/logrus"
- "github.com/codegangsta/cli"
- "github.com/opencontainers/runc/libcontainer"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/specconv"
- "github.com/opencontainers/runtime-spec/specs-go"
- )
- var restoreCommand = cli.Command{
- Name: "restore",
- Usage: "restore a container from a previous checkpoint",
- ArgsUsage: `<container-id>
- Where "<container-id>" is the name for the instance of the container to be
- restored.`,
- Description: `Restores the saved state of the container instance that was previously saved
- using the runc checkpoint command.`,
- 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",
- },
- cli.StringFlag{
- Name: "manage-cgroups-mode",
- Value: "",
- Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'.",
- },
- cli.StringFlag{
- Name: "bundle, b",
- Value: "",
- Usage: "path to the root of the bundle directory",
- },
- cli.BoolFlag{
- Name: "detach,d",
- Usage: "detach from the container's process",
- },
- cli.StringFlag{
- Name: "pid-file",
- Value: "",
- Usage: "specify the file to write the process id to",
- },
- cli.BoolFlag{
- Name: "no-subreaper",
- Usage: "disable the use of the subreaper used to reap reparented processes",
- },
- cli.BoolFlag{
- Name: "no-pivot",
- Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk",
- },
- },
- Action: func(context *cli.Context) {
- imagePath := context.String("image-path")
- id := context.Args().First()
- if id == "" {
- fatal(errEmptyID)
- }
- if imagePath == "" {
- imagePath = getDefaultImagePath(context)
- }
- bundle := context.String("bundle")
- if bundle != "" {
- if err := os.Chdir(bundle); err != nil {
- fatal(err)
- }
- }
- spec, err := loadSpec(specConfig)
- if err != nil {
- fatal(err)
- }
- config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
- CgroupName: id,
- UseSystemdCgroup: context.GlobalBool("systemd-cgroup"),
- NoPivotRoot: context.Bool("no-pivot"),
- Spec: 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.Spec, config *configs.Config, imagePath string) (code int, err error) {
- var (
- rootuid = 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)
- // 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, "", false, detach)
- if err != nil {
- return -1, err
- }
- defer tty.Close()
- handler := newSignalHandler(tty, !context.Bool("no-subreaper"))
- if err := container.Restore(process, options); err != nil {
- return -1, err
- }
- 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
- }
- }
- if detach {
- return 0, nil
- }
- 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: context.Bool("tcp-established"),
- ExternalUnixConnections: context.Bool("ext-unix-sk"),
- ShellJob: context.Bool("shell-job"),
- FileLocks: context.Bool("file-locks"),
- }
- }
|