containerd/ctr/checkpoint_linux.go

166 lines
4.0 KiB
Go

package main
import (
"fmt"
"os"
"text/tabwriter"
"github.com/urfave/cli"
"github.com/containerd/containerd/api/grpc/types"
netcontext "golang.org/x/net/context"
)
var checkpointSubCmds = []cli.Command{
listCheckpointCommand,
createCheckpointCommand,
deleteCheckpointCommand,
}
var checkpointCommand = cli.Command{
Name: "checkpoints",
Usage: "list all checkpoints",
ArgsUsage: "COMMAND [arguments...]",
Subcommands: checkpointSubCmds,
Description: func() string {
desc := "\n COMMAND:\n"
for _, command := range checkpointSubCmds {
desc += fmt.Sprintf(" %-10.10s%s\n", command.Name, command.Usage)
}
return desc
}(),
Action: listCheckpoints,
}
var listCheckpointCommand = cli.Command{
Name: "list",
Usage: "list all checkpoints for a container",
Action: listCheckpoints,
Flags: []cli.Flag{
cli.StringFlag{
Name: "checkpoint-dir",
Value: "",
Usage: "path to checkpoint directory",
},
},
}
func listCheckpoints(context *cli.Context) {
var (
c = getClient(context)
id = context.Args().First()
)
if id == "" {
fatal("container id cannot be empty", ExitStatusMissingArg)
}
resp, err := c.ListCheckpoint(netcontext.Background(), &types.ListCheckpointRequest{
Id: id,
CheckpointDir: context.String("checkpoint-dir"),
})
if err != nil {
fatal(err.Error(), 1)
}
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
fmt.Fprint(w, "NAME\tTCP\tUNIX SOCKETS\tSHELL\n")
for _, c := range resp.Checkpoints {
fmt.Fprintf(w, "%s\t%v\t%v\t%v\n", c.Name, c.Tcp, c.UnixSockets, c.Shell)
}
if err := w.Flush(); err != nil {
fatal(err.Error(), 1)
}
}
var createCheckpointCommand = cli.Command{
Name: "create",
Usage: "create a new checkpoint for the container",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "tcp",
Usage: "persist open tcp connections",
},
cli.BoolFlag{
Name: "unix-sockets",
Usage: "persist unix sockets",
},
cli.BoolFlag{
Name: "exit",
Usage: "exit the container after the checkpoint completes successfully",
},
cli.BoolFlag{
Name: "shell",
Usage: "checkpoint shell jobs",
},
cli.StringFlag{
Name: "checkpoint-dir",
Value: "",
Usage: "directory to store checkpoints",
},
cli.StringSliceFlag{
Name: "empty-ns",
Usage: "create a namespace, but don't restore its properties",
},
},
Action: func(context *cli.Context) {
var (
containerID = context.Args().Get(0)
name = context.Args().Get(1)
)
if containerID == "" {
fatal("container id at cannot be empty", ExitStatusMissingArg)
}
if name == "" {
fatal("checkpoint name cannot be empty", ExitStatusMissingArg)
}
c := getClient(context)
checkpoint := types.Checkpoint{
Name: name,
Exit: context.Bool("exit"),
Tcp: context.Bool("tcp"),
Shell: context.Bool("shell"),
UnixSockets: context.Bool("unix-sockets"),
}
emptyNSes := context.StringSlice("empty-ns")
checkpoint.EmptyNS = append(checkpoint.EmptyNS, emptyNSes...)
if _, err := c.CreateCheckpoint(netcontext.Background(), &types.CreateCheckpointRequest{
Id: containerID,
CheckpointDir: context.String("checkpoint-dir"),
Checkpoint: &checkpoint,
}); err != nil {
fatal(err.Error(), 1)
}
},
}
var deleteCheckpointCommand = cli.Command{
Name: "delete",
Usage: "delete a container's checkpoint",
Flags: []cli.Flag{
cli.StringFlag{
Name: "checkpoint-dir",
Value: "",
Usage: "path to checkpoint directory",
},
},
Action: func(context *cli.Context) {
var (
containerID = context.Args().Get(0)
name = context.Args().Get(1)
)
if containerID == "" {
fatal("container id at cannot be empty", ExitStatusMissingArg)
}
if name == "" {
fatal("checkpoint name cannot be empty", ExitStatusMissingArg)
}
c := getClient(context)
if _, err := c.DeleteCheckpoint(netcontext.Background(), &types.DeleteCheckpointRequest{
Id: containerID,
Name: name,
CheckpointDir: context.String("checkpoint-dir"),
}); err != nil {
fatal(err.Error(), 1)
}
},
}