 0b711d616a
			
		
	
	0b711d616a
	
	
	
		
			
			Make sure that the newly added annotations are copied around appropriately. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
		
			
				
	
	
		
			157 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    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 containerd
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"runtime"
 | |
| 
 | |
| 	tasks "github.com/containerd/containerd/api/services/tasks/v1"
 | |
| 	"github.com/containerd/containerd/containers"
 | |
| 	"github.com/containerd/containerd/diff"
 | |
| 	"github.com/containerd/containerd/images"
 | |
| 	"github.com/containerd/containerd/platforms"
 | |
| 	"github.com/containerd/containerd/rootfs"
 | |
| 	"github.com/containerd/containerd/runtime/v2/runc/options"
 | |
| 	"github.com/containerd/typeurl"
 | |
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1"
 | |
| 	"github.com/pkg/errors"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// ErrCheckpointRWUnsupported is returned if the container runtime does not support checkpoint
 | |
| 	ErrCheckpointRWUnsupported = errors.New("rw checkpoint is only supported on v2 runtimes")
 | |
| 	// ErrMediaTypeNotFound returns an error when a media type in the manifest is unknown
 | |
| 	ErrMediaTypeNotFound = errors.New("media type not found")
 | |
| )
 | |
| 
 | |
| // CheckpointOpts are options to manage the checkpoint operation
 | |
| type CheckpointOpts func(context.Context, *Client, *containers.Container, *imagespec.Index, *options.CheckpointOptions) error
 | |
| 
 | |
| // WithCheckpointImage includes the container image in the checkpoint
 | |
| func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
 | |
| 	ir, err := client.ImageService().Get(ctx, c.Image)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	index.Manifests = append(index.Manifests, ir.Target)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // WithCheckpointTask includes the running task
 | |
| func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
 | |
| 	any, err := typeurl.MarshalAny(copts)
 | |
| 	if err != nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	task, err := client.TaskService().Checkpoint(ctx, &tasks.CheckpointTaskRequest{
 | |
| 		ContainerID: c.ID,
 | |
| 		Options:     any,
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	for _, d := range task.Descriptors {
 | |
| 		platformSpec := platforms.DefaultSpec()
 | |
| 		index.Manifests = append(index.Manifests, imagespec.Descriptor{
 | |
| 			MediaType:   d.MediaType,
 | |
| 			Size:        d.Size_,
 | |
| 			Digest:      d.Digest,
 | |
| 			Platform:    &platformSpec,
 | |
| 			Annotations: d.Annotations,
 | |
| 		})
 | |
| 	}
 | |
| 	// save copts
 | |
| 	data, err := any.Marshal()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	r := bytes.NewReader(data)
 | |
| 	desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointOptions, c.ID+"-checkpoint-options", r)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	desc.Platform = &imagespec.Platform{
 | |
| 		OS:           runtime.GOOS,
 | |
| 		Architecture: runtime.GOARCH,
 | |
| 	}
 | |
| 	index.Manifests = append(index.Manifests, desc)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // WithCheckpointRuntime includes the container runtime info
 | |
| func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
 | |
| 	if c.Runtime.Options != nil {
 | |
| 		data, err := c.Runtime.Options.Marshal()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		r := bytes.NewReader(data)
 | |
| 		desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeOptions, c.ID+"-runtime-options", r)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		desc.Platform = &imagespec.Platform{
 | |
| 			OS:           runtime.GOOS,
 | |
| 			Architecture: runtime.GOARCH,
 | |
| 		}
 | |
| 		index.Manifests = append(index.Manifests, desc)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // WithCheckpointRW includes the rw in the checkpoint
 | |
| func WithCheckpointRW(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
 | |
| 	diffOpts := []diff.Opt{
 | |
| 		diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", c.SnapshotKey)),
 | |
| 	}
 | |
| 	rw, err := rootfs.CreateDiff(ctx,
 | |
| 		c.SnapshotKey,
 | |
| 		client.SnapshotService(c.Snapshotter),
 | |
| 		client.DiffService(),
 | |
| 		diffOpts...,
 | |
| 	)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 
 | |
| 	}
 | |
| 	rw.Platform = &imagespec.Platform{
 | |
| 		OS:           runtime.GOOS,
 | |
| 		Architecture: runtime.GOARCH,
 | |
| 	}
 | |
| 	index.Manifests = append(index.Manifests, rw)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // WithCheckpointTaskExit causes the task to exit after checkpoint
 | |
| func WithCheckpointTaskExit(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
 | |
| 	copts.Exit = true
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetIndexByMediaType returns the index in a manifest for the specified media type
 | |
| func GetIndexByMediaType(index *imagespec.Index, mt string) (*imagespec.Descriptor, error) {
 | |
| 	for _, d := range index.Manifests {
 | |
| 		if d.MediaType == mt {
 | |
| 			return &d, nil
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, ErrMediaTypeNotFound
 | |
| }
 |