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

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"syscall"
    10  
    11  	"github.com/opencontainers/runc/libcontainer"
    12  	"github.com/opencontainers/runtime-spec/specs-go"
    13  	"github.com/urfave/cli"
    14  )
    15  
    16  var checkpointCommand = cli.Command{
    17  	Name:  "checkpoint",
    18  	Usage: "checkpoint a running container",
    19  	ArgsUsage: `<container-id>
    20  
    21  Where "<container-id>" is the name for the instance of the container to be
    22  checkpointed.`,
    23  	Description: `The checkpoint command saves the state of the container instance.`,
    24  	Flags: []cli.Flag{
    25  		cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"},
    26  		cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"},
    27  		cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"},
    28  		cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"},
    29  		cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"},
    30  		cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"},
    31  		cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"},
    32  		cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
    33  		cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'"},
    34  		cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properies"},
    35  	},
    36  	Action: func(context *cli.Context) error {
    37  		container, err := getContainer(context)
    38  		if err != nil {
    39  			return err
    40  		}
    41  		status, err := container.Status()
    42  		if err != nil {
    43  			return err
    44  		}
    45  		if status == libcontainer.Created {
    46  			fatalf("Container cannot be checkpointed in created state")
    47  		}
    48  		defer destroy(container)
    49  		options := criuOptions(context)
    50  		// these are the mandatory criu options for a container
    51  		setPageServer(context, options)
    52  		setManageCgroupsMode(context, options)
    53  		if err := setEmptyNsMask(context, options); err != nil {
    54  			return err
    55  		}
    56  		if err := container.Checkpoint(options); err != nil {
    57  			return err
    58  		}
    59  		return nil
    60  	},
    61  }
    62  
    63  func getCheckpointImagePath(context *cli.Context) string {
    64  	imagePath := context.String("image-path")
    65  	if imagePath == "" {
    66  		imagePath = getDefaultImagePath(context)
    67  	}
    68  	return imagePath
    69  }
    70  
    71  func setPageServer(context *cli.Context, options *libcontainer.CriuOpts) {
    72  	// xxx following criu opts are optional
    73  	// The dump image can be sent to a criu page server
    74  	if psOpt := context.String("page-server"); psOpt != "" {
    75  		addressPort := strings.Split(psOpt, ":")
    76  		if len(addressPort) != 2 {
    77  			fatal(fmt.Errorf("Use --page-server ADDRESS:PORT to specify page server"))
    78  		}
    79  		portInt, err := strconv.Atoi(addressPort[1])
    80  		if err != nil {
    81  			fatal(fmt.Errorf("Invalid port number"))
    82  		}
    83  		options.PageServer = libcontainer.CriuPageServerInfo{
    84  			Address: addressPort[0],
    85  			Port:    int32(portInt),
    86  		}
    87  	}
    88  }
    89  
    90  func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) {
    91  	if cgOpt := context.String("manage-cgroups-mode"); cgOpt != "" {
    92  		switch cgOpt {
    93  		case "soft":
    94  			options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_SOFT
    95  		case "full":
    96  			options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_FULL
    97  		case "strict":
    98  			options.ManageCgroupsMode = libcontainer.CRIU_CG_MODE_STRICT
    99  		default:
   100  			fatal(fmt.Errorf("Invalid manage cgroups mode"))
   101  		}
   102  	}
   103  }
   104  
   105  var namespaceMapping = map[specs.NamespaceType]int{
   106  	specs.NetworkNamespace: syscall.CLONE_NEWNET,
   107  }
   108  
   109  func setEmptyNsMask(context *cli.Context, options *libcontainer.CriuOpts) error {
   110  	var nsmask int
   111  
   112  	for _, ns := range context.StringSlice("empty-ns") {
   113  		f, exists := namespaceMapping[specs.NamespaceType(ns)]
   114  		if !exists {
   115  			return fmt.Errorf("namespace %q is not supported", ns)
   116  		}
   117  		nsmask |= f
   118  	}
   119  
   120  	options.EmptyNs = uint32(nsmask)
   121  	return nil
   122  }