github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/restore.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/opencontainers/runc/libcontainer"
    11  	"github.com/opencontainers/runc/libcontainer/configs"
    12  	"github.com/opencontainers/runc/libcontainer/specconv"
    13  	"github.com/opencontainers/runtime-spec/specs-go"
    14  	"github.com/urfave/cli"
    15  )
    16  
    17  var restoreCommand = cli.Command{
    18  	Name:  "restore",
    19  	Usage: "restore a container from a previous checkpoint",
    20  	ArgsUsage: `<container-id>
    21  
    22  Where "<container-id>" is the name for the instance of the container to be
    23  restored.`,
    24  	Description: `Restores the saved state of the container instance that was previously saved
    25  using the runc checkpoint command.`,
    26  	Flags: []cli.Flag{
    27  		cli.StringFlag{
    28  			Name:  "image-path",
    29  			Value: "",
    30  			Usage: "path to criu image files for restoring",
    31  		},
    32  		cli.StringFlag{
    33  			Name:  "work-path",
    34  			Value: "",
    35  			Usage: "path for saving work files and logs",
    36  		},
    37  		cli.BoolFlag{
    38  			Name:  "tcp-established",
    39  			Usage: "allow open tcp connections",
    40  		},
    41  		cli.BoolFlag{
    42  			Name:  "ext-unix-sk",
    43  			Usage: "allow external unix sockets",
    44  		},
    45  		cli.BoolFlag{
    46  			Name:  "shell-job",
    47  			Usage: "allow shell jobs",
    48  		},
    49  		cli.BoolFlag{
    50  			Name:  "file-locks",
    51  			Usage: "handle file locks, for safety",
    52  		},
    53  		cli.StringFlag{
    54  			Name:  "manage-cgroups-mode",
    55  			Value: "",
    56  			Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'",
    57  		},
    58  		cli.StringFlag{
    59  			Name:  "bundle, b",
    60  			Value: "",
    61  			Usage: "path to the root of the bundle directory",
    62  		},
    63  		cli.BoolFlag{
    64  			Name:  "detach,d",
    65  			Usage: "detach from the container's process",
    66  		},
    67  		cli.StringFlag{
    68  			Name:  "pid-file",
    69  			Value: "",
    70  			Usage: "specify the file to write the process id to",
    71  		},
    72  		cli.BoolFlag{
    73  			Name:  "no-subreaper",
    74  			Usage: "disable the use of the subreaper used to reap reparented processes",
    75  		},
    76  		cli.BoolFlag{
    77  			Name:  "no-pivot",
    78  			Usage: "do not use pivot root to jail process inside rootfs.  This should be used whenever the rootfs is on top of a ramdisk",
    79  		},
    80  		cli.StringSliceFlag{
    81  			Name:  "empty-ns",
    82  			Usage: "create a namespace, but don't restore its properies",
    83  		},
    84  	},
    85  	Action: func(context *cli.Context) error {
    86  		imagePath := context.String("image-path")
    87  		id := context.Args().First()
    88  		if id == "" {
    89  			return errEmptyID
    90  		}
    91  		if imagePath == "" {
    92  			imagePath = getDefaultImagePath(context)
    93  		}
    94  		bundle := context.String("bundle")
    95  		if bundle != "" {
    96  			if err := os.Chdir(bundle); err != nil {
    97  				return err
    98  			}
    99  		}
   100  		spec, err := loadSpec(specConfig)
   101  		if err != nil {
   102  			return err
   103  		}
   104  		config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
   105  			CgroupName:       id,
   106  			UseSystemdCgroup: context.GlobalBool("systemd-cgroup"),
   107  			NoPivotRoot:      context.Bool("no-pivot"),
   108  			Spec:             spec,
   109  		})
   110  		if err != nil {
   111  			return err
   112  		}
   113  		status, err := restoreContainer(context, spec, config, imagePath)
   114  		if err == nil {
   115  			os.Exit(status)
   116  		}
   117  		return err
   118  	},
   119  }
   120  
   121  func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Config, imagePath string) (int, error) {
   122  	var (
   123  		rootuid = 0
   124  		rootgid = 0
   125  		id      = context.Args().First()
   126  	)
   127  	factory, err := loadFactory(context)
   128  	if err != nil {
   129  		return -1, err
   130  	}
   131  	container, err := factory.Load(id)
   132  	if err != nil {
   133  		container, err = factory.Create(id, config)
   134  		if err != nil {
   135  			return -1, err
   136  		}
   137  	}
   138  	options := criuOptions(context)
   139  
   140  	status, err := container.Status()
   141  	if err != nil {
   142  		logrus.Error(err)
   143  	}
   144  	if status == libcontainer.Running {
   145  		fatalf("Container with id %s already running", id)
   146  	}
   147  
   148  	setManageCgroupsMode(context, options)
   149  
   150  	if err := setEmptyNsMask(context, options); err != nil {
   151  		return -1, err
   152  	}
   153  
   154  	// ensure that the container is always removed if we were the process
   155  	// that created it.
   156  	detach := context.Bool("detach")
   157  	if !detach {
   158  		defer destroy(container)
   159  	}
   160  	process := &libcontainer.Process{}
   161  	tty, err := setupIO(process, rootuid, rootgid, "", false, detach)
   162  	if err != nil {
   163  		return -1, err
   164  	}
   165  	defer tty.Close()
   166  	handler := newSignalHandler(tty, !context.Bool("no-subreaper"))
   167  	if err := container.Restore(process, options); err != nil {
   168  		return -1, err
   169  	}
   170  	if err := tty.ClosePostStart(); err != nil {
   171  		return -1, err
   172  	}
   173  	if pidFile := context.String("pid-file"); pidFile != "" {
   174  		if err := createPidFile(pidFile, process); err != nil {
   175  			process.Signal(syscall.SIGKILL)
   176  			process.Wait()
   177  			return -1, err
   178  		}
   179  	}
   180  	if detach {
   181  		return 0, nil
   182  	}
   183  	return handler.forward(process)
   184  }
   185  
   186  func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
   187  	imagePath := getCheckpointImagePath(context)
   188  	if err := os.MkdirAll(imagePath, 0655); err != nil {
   189  		fatal(err)
   190  	}
   191  	return &libcontainer.CriuOpts{
   192  		ImagesDirectory:         imagePath,
   193  		WorkDirectory:           context.String("work-path"),
   194  		LeaveRunning:            context.Bool("leave-running"),
   195  		TcpEstablished:          context.Bool("tcp-established"),
   196  		ExternalUnixConnections: context.Bool("ext-unix-sk"),
   197  		ShellJob:                context.Bool("shell-job"),
   198  		FileLocks:               context.Bool("file-locks"),
   199  	}
   200  }