Add checkpoint and restore to client package
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
		
							
								
								
									
										127
									
								
								container_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								container_linux.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| package containerd | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/containerd/containerd/api/services/containers" | ||||
| 	"github.com/containerd/containerd/api/services/execution" | ||||
| 	"github.com/containerd/containerd/api/types/descriptor" | ||||
| 	"github.com/containerd/containerd/content" | ||||
| 	"github.com/containerd/containerd/images" | ||||
| 	"github.com/containerd/containerd/snapshot" | ||||
| 	protobuf "github.com/gogo/protobuf/types" | ||||
| 	digest "github.com/opencontainers/go-digest" | ||||
| 	"github.com/opencontainers/image-spec/identity" | ||||
| 	"github.com/opencontainers/image-spec/specs-go/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func WithSpec(spec *specs.Spec) NewContainerOpts { | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		data, err := json.Marshal(spec) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		c.Spec = &protobuf.Any{ | ||||
| 			TypeUrl: spec.Version, | ||||
| 			Value:   data, | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithCheckpoint(desc v1.Descriptor, rootfsID string) NewContainerOpts { | ||||
| 	// set image and rw, and spec | ||||
| 	return func(ctx context.Context, client *Client, c *containers.Container) error { | ||||
| 		id := desc.Digest | ||||
| 		store := client.ContentStore() | ||||
| 		index, err := decodeIndex(ctx, store, id) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		var rw *v1.Descriptor | ||||
| 		for _, m := range index.Manifests { | ||||
| 			switch m.MediaType { | ||||
| 			case v1.MediaTypeImageLayer: | ||||
| 				fk := m | ||||
| 				rw = &fk | ||||
| 			case images.MediaTypeDockerSchema2Manifest: | ||||
| 				config, err := images.Config(ctx, store, m) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				diffIDs, err := images.RootFS(ctx, store, config) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if _, err := client.SnapshotService().Prepare(ctx, rootfsID, identity.ChainID(diffIDs).String()); err != nil { | ||||
| 					if !snapshot.IsExist(err) { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 				c.Image = index.Annotations["image.name"] | ||||
| 			case images.MediaTypeContainerd1CheckpointConfig: | ||||
| 				r, err := store.Reader(ctx, m.Digest) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				data, err := ioutil.ReadAll(r) | ||||
| 				r.Close() | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				c.Spec = &protobuf.Any{ | ||||
| 					TypeUrl: specs.Version, | ||||
| 					Value:   data, | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if rw != nil { | ||||
| 			// apply the rw snapshot to the new rw layer | ||||
| 			mounts, err := client.SnapshotService().Mounts(ctx, rootfsID) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		c.RootFS = rootfsID | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithTaskCheckpoint(desc v1.Descriptor) NewTaskOpts { | ||||
| 	return func(ctx context.Context, c *Client, r *execution.CreateRequest) error { | ||||
| 		id := desc.Digest | ||||
| 		index, err := decodeIndex(ctx, c.ContentStore(), id) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for _, m := range index.Manifests { | ||||
| 			if m.MediaType == images.MediaTypeContainerd1Checkpoint { | ||||
| 				r.Checkpoint = &descriptor.Descriptor{ | ||||
| 					MediaType: m.MediaType, | ||||
| 					Size_:     m.Size, | ||||
| 					Digest:    m.Digest, | ||||
| 				} | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 		return fmt.Errorf("checkpoint not found in index %s", id) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func decodeIndex(ctx context.Context, store content.Store, id digest.Digest) (*v1.Index, error) { | ||||
| 	var index v1.Index | ||||
| 	r, err := store.Reader(ctx, id) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	err = json.NewDecoder(r).Decode(&index) | ||||
| 	r.Close() | ||||
| 	return &index, err | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Michael Crosby
					Michael Crosby