From bd27bef4ad87d703cb5d3e2368fda8db0e47c826 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 10 May 2019 14:20:19 +0000 Subject: [PATCH] Move checkpoint and restore commands to new files Signed-off-by: Michael Crosby --- cmd/ctr/commands/containers/checkpoint.go | 102 +++++++++++++++ cmd/ctr/commands/containers/containers.go | 146 ---------------------- cmd/ctr/commands/containers/restore.go | 96 ++++++++++++++ 3 files changed, 198 insertions(+), 146 deletions(-) create mode 100644 cmd/ctr/commands/containers/checkpoint.go create mode 100644 cmd/ctr/commands/containers/restore.go diff --git a/cmd/ctr/commands/containers/checkpoint.go b/cmd/ctr/commands/containers/checkpoint.go new file mode 100644 index 000000000..53bf70b3c --- /dev/null +++ b/cmd/ctr/commands/containers/checkpoint.go @@ -0,0 +1,102 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containers + +import ( + "fmt" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var checkpointCommand = cli.Command{ + Name: "checkpoint", + Usage: "checkpoint a container", + ArgsUsage: "CONTAINER REF", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "rw", + Usage: "include the rw layer in the checkpoint", + }, + cli.BoolFlag{ + Name: "image", + Usage: "include the image in the checkpoint", + }, + cli.BoolFlag{ + Name: "task", + Usage: "checkpoint container task", + }, + }, + Action: func(context *cli.Context) error { + id := context.Args().First() + if id == "" { + return errors.New("container id must be provided") + } + ref := context.Args().Get(1) + if ref == "" { + return errors.New("ref must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + opts := []containerd.CheckpointOpts{ + containerd.WithCheckpointRuntime, + } + + if context.Bool("image") { + opts = append(opts, containerd.WithCheckpointImage) + } + if context.Bool("rw") { + opts = append(opts, containerd.WithCheckpointRW) + } + if context.Bool("task") { + opts = append(opts, containerd.WithCheckpointTask) + } + container, err := client.LoadContainer(ctx, id) + if err != nil { + return err + } + task, err := container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return err + } + } + // pause if running + if task != nil { + if err := task.Pause(ctx); err != nil { + return err + } + defer func() { + if err := task.Resume(ctx); err != nil { + fmt.Println(errors.Wrap(err, "error resuming task")) + } + }() + } + + if _, err := container.Checkpoint(ctx, ref, opts...); err != nil { + return err + } + + return nil + }, +} diff --git a/cmd/ctr/commands/containers/containers.go b/cmd/ctr/commands/containers/containers.go index 91f164c1a..9e40b6aa7 100644 --- a/cmd/ctr/commands/containers/containers.go +++ b/cmd/ctr/commands/containers/containers.go @@ -28,7 +28,6 @@ import ( "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/cmd/ctr/commands/run" "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/typeurl" "github.com/pkg/errors" @@ -285,148 +284,3 @@ var infoCommand = cli.Command{ return nil }, } - -var checkpointCommand = cli.Command{ - Name: "checkpoint", - Usage: "checkpoint a container", - ArgsUsage: "CONTAINER REF", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "rw", - Usage: "include the rw layer in the checkpoint", - }, - cli.BoolFlag{ - Name: "image", - Usage: "include the image in the checkpoint", - }, - cli.BoolFlag{ - Name: "task", - Usage: "checkpoint container task", - }, - }, - Action: func(context *cli.Context) error { - id := context.Args().First() - if id == "" { - return errors.New("container id must be provided") - } - ref := context.Args().Get(1) - if ref == "" { - return errors.New("ref must be provided") - } - client, ctx, cancel, err := commands.NewClient(context) - if err != nil { - return err - } - defer cancel() - opts := []containerd.CheckpointOpts{ - containerd.WithCheckpointRuntime, - } - - if context.Bool("image") { - opts = append(opts, containerd.WithCheckpointImage) - } - if context.Bool("rw") { - opts = append(opts, containerd.WithCheckpointRW) - } - if context.Bool("task") { - opts = append(opts, containerd.WithCheckpointTask) - } - container, err := client.LoadContainer(ctx, id) - if err != nil { - return err - } - task, err := container.Task(ctx, nil) - if err != nil { - if !errdefs.IsNotFound(err) { - return err - } - } - // pause if running - if task != nil { - if err := task.Pause(ctx); err != nil { - return err - } - defer func() { - if err := task.Resume(ctx); err != nil { - fmt.Println(errors.Wrap(err, "error resuming task")) - } - }() - } - - if _, err := container.Checkpoint(ctx, ref, opts...); err != nil { - return err - } - - return nil - }, -} - -var restoreCommand = cli.Command{ - Name: "restore", - Usage: "restore a container from checkpoint", - ArgsUsage: "CONTAINER REF", - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "rw", - Usage: "restore the rw layer from the checkpoint", - }, - cli.BoolFlag{ - Name: "live", - Usage: "restore the runtime and memory data from the checkpoint", - }, - }, - Action: func(context *cli.Context) error { - id := context.Args().First() - if id == "" { - return errors.New("container id must be provided") - } - ref := context.Args().Get(1) - if ref == "" { - return errors.New("ref must be provided") - } - client, ctx, cancel, err := commands.NewClient(context) - if err != nil { - return err - } - defer cancel() - - checkpoint, err := client.GetImage(ctx, ref) - if err != nil { - if !errdefs.IsNotFound(err) { - return err - } - // TODO (ehazlett): consider other options (always/never fetch) - ck, err := client.Fetch(ctx, ref) - if err != nil { - return err - } - checkpoint = containerd.NewImage(client, ck) - } - - opts := []containerd.RestoreOpts{ - containerd.WithRestoreImage, - containerd.WithRestoreSpec, - containerd.WithRestoreRuntime, - } - if context.Bool("rw") { - opts = append(opts, containerd.WithRestoreRW) - } - - ctr, err := client.Restore(ctx, id, checkpoint, opts...) - if err != nil { - return err - } - - topts := []containerd.NewTaskOpts{} - if context.Bool("live") { - topts = append(topts, containerd.WithTaskCheckpoint(checkpoint)) - } - - task, err := ctr.NewTask(ctx, cio.NewCreator(cio.WithStdio), topts...) - if err != nil { - return err - } - - return task.Start(ctx) - }, -} diff --git a/cmd/ctr/commands/containers/restore.go b/cmd/ctr/commands/containers/restore.go new file mode 100644 index 000000000..85337b34d --- /dev/null +++ b/cmd/ctr/commands/containers/restore.go @@ -0,0 +1,96 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package containers + +import ( + "github.com/containerd/containerd" + "github.com/containerd/containerd/cio" + "github.com/containerd/containerd/cmd/ctr/commands" + "github.com/containerd/containerd/errdefs" + "github.com/pkg/errors" + "github.com/urfave/cli" +) + +var restoreCommand = cli.Command{ + Name: "restore", + Usage: "restore a container from checkpoint", + ArgsUsage: "CONTAINER REF", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "rw", + Usage: "restore the rw layer from the checkpoint", + }, + cli.BoolFlag{ + Name: "live", + Usage: "restore the runtime and memory data from the checkpoint", + }, + }, + Action: func(context *cli.Context) error { + id := context.Args().First() + if id == "" { + return errors.New("container id must be provided") + } + ref := context.Args().Get(1) + if ref == "" { + return errors.New("ref must be provided") + } + client, ctx, cancel, err := commands.NewClient(context) + if err != nil { + return err + } + defer cancel() + + checkpoint, err := client.GetImage(ctx, ref) + if err != nil { + if !errdefs.IsNotFound(err) { + return err + } + // TODO (ehazlett): consider other options (always/never fetch) + ck, err := client.Fetch(ctx, ref) + if err != nil { + return err + } + checkpoint = containerd.NewImage(client, ck) + } + + opts := []containerd.RestoreOpts{ + containerd.WithRestoreImage, + containerd.WithRestoreSpec, + containerd.WithRestoreRuntime, + } + if context.Bool("rw") { + opts = append(opts, containerd.WithRestoreRW) + } + + ctr, err := client.Restore(ctx, id, checkpoint, opts...) + if err != nil { + return err + } + + topts := []containerd.NewTaskOpts{} + if context.Bool("live") { + topts = append(topts, containerd.WithTaskCheckpoint(checkpoint)) + } + + task, err := ctr.NewTask(ctx, cio.NewCreator(cio.WithStdio), topts...) + if err != nil { + return err + } + + return task.Start(ctx) + }, +}