remove task handling from Restore
Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
parent
2d3db08daf
commit
0e4d9da755
38
client.go
38
client.go
@ -38,7 +38,6 @@ import (
|
|||||||
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
|
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
|
||||||
"github.com/containerd/containerd/api/services/tasks/v1"
|
"github.com/containerd/containerd/api/services/tasks/v1"
|
||||||
versionservice "github.com/containerd/containerd/api/services/version/v1"
|
versionservice "github.com/containerd/containerd/api/services/version/v1"
|
||||||
"github.com/containerd/containerd/cio"
|
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/content"
|
"github.com/containerd/containerd/content"
|
||||||
contentproxy "github.com/containerd/containerd/content/proxy"
|
contentproxy "github.com/containerd/containerd/content/proxy"
|
||||||
@ -524,15 +523,15 @@ func (c *Client) ListImages(ctx context.Context, filters ...string) ([]Image, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restore restores a container from a checkpoint
|
// Restore restores a container from a checkpoint
|
||||||
func (c *Client) Restore(ctx context.Context, id, ref string, opts ...RestoreOpts) error {
|
func (c *Client) Restore(ctx context.Context, id, ref string, opts ...RestoreOpts) (Container, error) {
|
||||||
checkpoint, err := c.GetImage(ctx, ref)
|
checkpoint, err := c.GetImage(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errdefs.IsNotFound(err) {
|
if !errdefs.IsNotFound(err) {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
ck, err := c.Fetch(ctx, ref)
|
ck, err := c.Fetch(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
checkpoint = NewImage(c, ck)
|
checkpoint = NewImage(c, ck)
|
||||||
}
|
}
|
||||||
@ -540,61 +539,50 @@ func (c *Client) Restore(ctx context.Context, id, ref string, opts ...RestoreOpt
|
|||||||
store := c.ContentStore()
|
store := c.ContentStore()
|
||||||
index, err := decodeIndex(ctx, store, checkpoint.Target())
|
index, err := decodeIndex(ctx, store, checkpoint.Target())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, done, err := c.WithLease(ctx)
|
ctx, done, err := c.WithLease(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer done(ctx)
|
defer done(ctx)
|
||||||
|
|
||||||
copts := []NewContainerOpts{}
|
copts := []NewContainerOpts{}
|
||||||
topts := []NewTaskOpts{}
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
co, to, err := o(ctx, id, c, checkpoint, index)
|
co, err := o(ctx, id, c, checkpoint, index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
copts = append(copts, co...)
|
copts = append(copts, co...)
|
||||||
topts = append(topts, to...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctr, err := c.NewContainer(ctx, id, copts...)
|
ctr, err := c.NewContainer(ctx, id, copts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply rw layer
|
// apply rw layer
|
||||||
info, err := ctr.Info(ctx)
|
info, err := ctr.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rw, err := GetIndexByMediaType(index, ocispec.MediaTypeImageLayerGzip)
|
rw, err := GetIndexByMediaType(index, ocispec.MediaTypeImageLayerGzip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts, err := c.SnapshotService(info.Snapshotter).Mounts(ctx, info.SnapshotKey)
|
mounts, err := c.SnapshotService(info.Snapshotter).Mounts(ctx, info.SnapshotKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.DiffService().Apply(ctx, *rw, mounts); err != nil {
|
if _, err := c.DiffService().Apply(ctx, *rw, mounts); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
task, err := ctr.NewTask(ctx, cio.NewCreator(cio.WithStdio), topts...)
|
return ctr, nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Start(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) {
|
func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) {
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||||
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
"github.com/containerd/containerd/cmd/ctr/commands/run"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/containerd/typeurl"
|
"github.com/containerd/typeurl"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@ -364,15 +365,39 @@ var restoreCommand = cli.Command{
|
|||||||
}
|
}
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
checkpoint, err := client.GetImage(ctx, ref)
|
||||||
|
if err != nil {
|
||||||
|
if !errdefs.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ck, err := client.Fetch(ctx, ref)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
checkpoint = containerd.NewImage(client, ck)
|
||||||
|
}
|
||||||
|
|
||||||
opts := []containerd.RestoreOpts{
|
opts := []containerd.RestoreOpts{
|
||||||
containerd.WithRestoreSpec,
|
containerd.WithRestoreSpec,
|
||||||
containerd.WithRestoreSnapshot,
|
containerd.WithRestoreSnapshot,
|
||||||
containerd.WithRestoreRuntime,
|
containerd.WithRestoreRuntime,
|
||||||
}
|
}
|
||||||
if context.Bool("live") {
|
|
||||||
opts = append(opts, containerd.WithRestoreLive)
|
ctr, err := client.Restore(ctx, id, ref, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if err := client.Restore(ctx, id, ref, opts...); err != nil {
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Start(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,26 +39,19 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RestoreOpts are options to manage the restore operation
|
// RestoreOpts are options to manage the restore operation
|
||||||
type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) ([]NewContainerOpts, []NewTaskOpts, error)
|
type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) ([]NewContainerOpts, error)
|
||||||
|
|
||||||
// WithRestoreLive restores the runtime and memory data for the container
|
|
||||||
func WithRestoreLive(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, []NewTaskOpts, error) {
|
|
||||||
return nil, []NewTaskOpts{
|
|
||||||
WithTaskCheckpoint(checkpoint),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithRestoreRuntime restores the runtime for the container
|
// WithRestoreRuntime restores the runtime for the container
|
||||||
func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, []NewTaskOpts, error) {
|
func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, error) {
|
||||||
runtimeName, ok := index.Annotations["runtime.name"]
|
runtimeName, ok := index.Annotations["runtime.name"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, ErrCheckpointIndexRuntimeNameNotFound
|
return nil, ErrCheckpointIndexRuntimeNameNotFound
|
||||||
}
|
}
|
||||||
// restore options if present
|
// restore options if present
|
||||||
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions)
|
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != ErrMediaTypeNotFound {
|
if err != ErrMediaTypeNotFound {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var options *ptypes.Any
|
var options *ptypes.Any
|
||||||
@ -66,64 +59,64 @@ func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoi
|
|||||||
store := client.ContentStore()
|
store := client.ContentStore()
|
||||||
data, err := content.ReadBlob(ctx, store, *m)
|
data, err := content.ReadBlob(ctx, store, *m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "unable to read checkpoint runtime")
|
return nil, errors.Wrap(err, "unable to read checkpoint runtime")
|
||||||
}
|
}
|
||||||
if err := proto.Unmarshal(data, options); err != nil {
|
if err := proto.Unmarshal(data, options); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []NewContainerOpts{
|
return []NewContainerOpts{
|
||||||
WithRuntime(runtimeName, options),
|
WithRuntime(runtimeName, options),
|
||||||
}, nil, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRestoreSpec restores the spec from the checkpoint for the container
|
// WithRestoreSpec restores the spec from the checkpoint for the container
|
||||||
func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, []NewTaskOpts, error) {
|
func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, error) {
|
||||||
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig)
|
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
store := client.ContentStore()
|
store := client.ContentStore()
|
||||||
data, err := content.ReadBlob(ctx, store, *m)
|
data, err := content.ReadBlob(ctx, store, *m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "unable to read checkpoint config")
|
return nil, errors.Wrap(err, "unable to read checkpoint config")
|
||||||
}
|
}
|
||||||
var any ptypes.Any
|
var any ptypes.Any
|
||||||
if err := proto.Unmarshal(data, &any); err != nil {
|
if err := proto.Unmarshal(data, &any); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := typeurl.UnmarshalAny(&any)
|
v, err := typeurl.UnmarshalAny(&any)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
spec := v.(*oci.Spec)
|
spec := v.(*oci.Spec)
|
||||||
return []NewContainerOpts{
|
return []NewContainerOpts{
|
||||||
WithSpec(spec),
|
WithSpec(spec),
|
||||||
}, nil, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithRestoreSnapshot(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) ([]NewContainerOpts, []NewTaskOpts, error) {
|
// 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
|
// get image from annotation
|
||||||
imageName, ok := index.Annotations["image.name"]
|
imageName, ok := index.Annotations["image.name"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, ErrCheckpointIndexImageNameNotFound
|
return nil, ErrCheckpointIndexImageNameNotFound
|
||||||
}
|
}
|
||||||
i, err := client.Pull(ctx, imageName, WithPullUnpack)
|
i, err := client.Pull(ctx, imageName, WithPullUnpack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
|
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//setSnapshotterIfEmpty(client)
|
|
||||||
parent := identity.ChainID(diffIDs).String()
|
parent := identity.ChainID(diffIDs).String()
|
||||||
if _, err := client.SnapshotService(DefaultSnapshotter).Prepare(ctx, id, parent); err != nil {
|
if _, err := client.SnapshotService(DefaultSnapshotter).Prepare(ctx, id, parent); err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []NewContainerOpts{
|
return []NewContainerOpts{
|
||||||
WithImage(i),
|
WithImage(i),
|
||||||
WithSnapshot(id),
|
WithSnapshot(id),
|
||||||
}, nil, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user