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
 | 
						|
}
 |