From 147208061cbcf123db82050d13510c5009825bd3 Mon Sep 17 00:00:00 2001 From: Evan Hazlett Date: Mon, 17 Sep 2018 13:48:46 -0400 Subject: [PATCH] add image name and runtime name media types; remove task operation on checkpoint Signed-off-by: Evan Hazlett --- cmd/ctr/commands/containers/containers.go | 12 ++++ container.go | 85 ++++++++++++----------- container_restore_opts.go | 75 +++++++++++++++----- images/mediatypes.go | 2 + 4 files changed, 117 insertions(+), 57 deletions(-) diff --git a/cmd/ctr/commands/containers/containers.go b/cmd/ctr/commands/containers/containers.go index a0420a44f206..c21381947d7b 100644 --- a/cmd/ctr/commands/containers/containers.go +++ b/cmd/ctr/commands/containers/containers.go @@ -332,6 +332,17 @@ var checkpointCommand = cli.Command{ if err != nil { return err } + task, err := container.Task(ctx, nil) + if err != nil { + if !errdefs.IsNotFound(err) { + return err + } + } + if err := task.Pause(ctx); err != nil { + return err + } + defer task.Resume(ctx) + if _, err := container.Checkpoint(ctx, ref, opts...); err != nil { return err } @@ -378,6 +389,7 @@ var restoreCommand = cli.Command{ } opts := []containerd.RestoreOpts{ + containerd.WithRestoreImage, containerd.WithRestoreSpec, containerd.WithRestoreSnapshot, containerd.WithRestoreRuntime, diff --git a/container.go b/container.go index 4d24adfc371f..c20f526bee81 100644 --- a/container.go +++ b/container.go @@ -295,11 +295,15 @@ func (c *container) Checkpoint(ctx context.Context, ref string, opts ...Checkpoi FileLocks: true, EmptyNamespaces: nil, } + info, err := c.Info(ctx) + if err != nil { + return nil, err + } + img, err := c.Image(ctx) if err != nil { return nil, err } - index.Annotations["image.name"] = img.Name() ctx, done, err := c.client.WithLease(ctx) if err != nil { @@ -307,53 +311,52 @@ func (c *container) Checkpoint(ctx context.Context, ref string, opts ...Checkpoi } defer done(ctx) - // pause task to checkpoint - if err := func(ctx context.Context) error { - task, err := c.Task(ctx, nil) + // add image name to manifest + ir := bytes.NewReader([]byte(img.Name())) + idesc, err := writeContent(ctx, c.client.ContentStore(), images.MediaTypeContainerd1CheckpointImageName, info.ID+"-image-name", ir) + if err != nil { + return nil, err + } + idesc.Platform = &ocispec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, + } + index.Manifests = append(index.Manifests, idesc) + + // add runtime info to index + rr := bytes.NewReader([]byte(info.Runtime.Name)) + rdesc, err := writeContent(ctx, c.client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeName, info.ID+"-runtime-name", rr) + if err != nil { + return nil, err + } + rdesc.Platform = &ocispec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, + } + index.Manifests = append(index.Manifests, rdesc) + + if info.Runtime.Options != nil { + data, err := info.Runtime.Options.Marshal() if err != nil { - if errdefs.IsNotFound(err) { - return nil - } - return err - } - if err := task.Pause(ctx); err != nil { - return err + return nil, err } - defer task.Resume(ctx) - - info, err := c.Info(ctx) + r := bytes.NewReader(data) + desc, err := writeContent(ctx, c.client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeOptions, info.ID+"-runtime-options", r) if err != nil { - return err + return nil, err } - - // add runtime info to index - index.Annotations["runtime.name"] = info.Runtime.Name - if info.Runtime.Options != nil { - data, err := info.Runtime.Options.Marshal() - if err != nil { - return err - } - r := bytes.NewReader(data) - desc, err := writeContent(ctx, c.client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeOptions, info.ID+"-runtime-options", r) - if err != nil { - return err - } - desc.Platform = &ocispec.Platform{ - OS: runtime.GOOS, - Architecture: runtime.GOARCH, - } - index.Manifests = append(index.Manifests, desc) + desc.Platform = &ocispec.Platform{ + OS: runtime.GOOS, + Architecture: runtime.GOARCH, } + index.Manifests = append(index.Manifests, desc) + } - // process remaining opts - for _, o := range opts { - if err := o(ctx, c.client, &info, index, copts); err != nil { - return err - } + // process remaining opts + for _, o := range opts { + if err := o(ctx, c.client, &info, index, copts); err != nil { + return nil, err } - return nil - }(ctx); err != nil { - return nil, err } desc, err := writeIndex(ctx, index, c.client, c.ID()+"index") diff --git a/container_restore_opts.go b/container_restore_opts.go index 27c1f7adaacb..eeb353c34444 100644 --- a/container_restore_opts.go +++ b/container_restore_opts.go @@ -31,22 +31,54 @@ import ( "github.com/pkg/errors" ) -var ( - // ErrCheckpointIndexImageNameNotFound is returned when the checkpoint image name is not present in the index - ErrCheckpointIndexImageNameNotFound = errors.New("image name not present in index") - // ErrCheckpointIndexRuntimeNameNotFound is returned when the checkpoint runtime name is not present in the index - ErrCheckpointIndexRuntimeNameNotFound = errors.New("runtime name not present in index") -) - // RestoreOpts are options to manage the restore operation type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) ([]NewContainerOpts, error) +// WithRestoreImage restores the image for the container +func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, error) { + store := client.ContentStore() + m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointImageName) + if err != nil { + if err != ErrMediaTypeNotFound { + return nil, err + } + } + imageName := "" + if m != nil { + data, err := content.ReadBlob(ctx, store, *m) + if err != nil { + return nil, err + } + imageName = string(data) + } + i, err := client.GetImage(ctx, imageName) + if err != nil { + return nil, err + } + + return []NewContainerOpts{ + WithImage(i), + }, nil +} + // WithRestoreRuntime restores the runtime for the container func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, error) { - runtimeName, ok := index.Annotations["runtime.name"] - if !ok { - return nil, ErrCheckpointIndexRuntimeNameNotFound + store := client.ContentStore() + n, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeName) + if err != nil { + if err != ErrMediaTypeNotFound { + return nil, err + } + } + runtimeName := "" + if n != nil { + data, err := content.ReadBlob(ctx, store, *n) + if err != nil { + return nil, err + } + runtimeName = string(data) } + // restore options if present m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions) if err != nil { @@ -54,9 +86,9 @@ func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoi return nil, err } } + var options *ptypes.Any if m != nil { - store := client.ContentStore() data, err := content.ReadBlob(ctx, store, *m) if err != nil { return nil, errors.Wrap(err, "unable to read checkpoint runtime") @@ -98,15 +130,26 @@ func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint // WithRestoreSnapshot restores the snapshot from the checkpoint for the container func WithRestoreSnapshot(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, error) { - // get image from annotation - imageName, ok := index.Annotations["image.name"] - if !ok { - return nil, ErrCheckpointIndexImageNameNotFound + imageName := "" + store := client.ContentStore() + m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointImageName) + if err != nil { + if err != ErrMediaTypeNotFound { + return nil, err + } } - i, err := client.Pull(ctx, imageName, WithPullUnpack) + if m != nil { + data, err := content.ReadBlob(ctx, store, *m) + if err != nil { + return nil, err + } + imageName = string(data) + } + i, err := client.GetImage(ctx, imageName) if err != nil { return nil, err } + diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default()) if err != nil { return nil, err diff --git a/images/mediatypes.go b/images/mediatypes.go index e7a84526f370..005a2720b863 100644 --- a/images/mediatypes.go +++ b/images/mediatypes.go @@ -34,6 +34,8 @@ const ( MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar" MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar" MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto" + MediaTypeContainerd1CheckpointImageName = "application/vnd.containerd.container.checkpoint.image.name" + MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name" MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto" // Legacy Docker schema1 manifest MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"