@@ -25,6 +25,7 @@ import (
 | 
			
		||||
	"github.com/containerd/containerd/content"
 | 
			
		||||
	"github.com/containerd/containerd/errdefs"
 | 
			
		||||
	"github.com/containerd/containerd/images"
 | 
			
		||||
	"github.com/containerd/containerd/images/archive"
 | 
			
		||||
	"github.com/containerd/containerd/pkg/streaming"
 | 
			
		||||
	"github.com/containerd/containerd/pkg/transfer/plugins"
 | 
			
		||||
	"github.com/containerd/containerd/pkg/unpack"
 | 
			
		||||
@@ -47,6 +48,12 @@ type Store struct {
 | 
			
		||||
	labelMap      func(ocispec.Descriptor) []string
 | 
			
		||||
	manifestLimit int
 | 
			
		||||
 | 
			
		||||
	//import image options
 | 
			
		||||
	namePrefix   string
 | 
			
		||||
	checkPrefix  bool
 | 
			
		||||
	digestRefs   bool
 | 
			
		||||
	alwaysDigest bool
 | 
			
		||||
 | 
			
		||||
	unpacks []UnpackConfiguration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -86,6 +93,25 @@ func WithAllMetadata(s *Store) {
 | 
			
		||||
	s.allMetadata = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithNamePrefix sets the name prefix for imported images, if
 | 
			
		||||
// check is enabled, then only images with the prefix are stored.
 | 
			
		||||
func WithNamePrefix(prefix string, check bool) StoreOpt {
 | 
			
		||||
	return func(s *Store) {
 | 
			
		||||
		s.namePrefix = prefix
 | 
			
		||||
		s.checkPrefix = check
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithDigestRefs sets digest refs for imported images, if
 | 
			
		||||
// always is enabled, then digest refs are added even if a
 | 
			
		||||
// non-digest image name is added for the same image.
 | 
			
		||||
func WithDigestRefs(always bool) StoreOpt {
 | 
			
		||||
	return func(s *Store) {
 | 
			
		||||
		s.digestRefs = true
 | 
			
		||||
		s.alwaysDigest = always
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithUnpack specifies a platform to unpack for and an optional snapshotter to use
 | 
			
		||||
func WithUnpack(p ocispec.Platform, snapshotter string) StoreOpt {
 | 
			
		||||
	return func(s *Store) {
 | 
			
		||||
@@ -144,6 +170,35 @@ func (is *Store) Store(ctx context.Context, desc ocispec.Descriptor, store image
 | 
			
		||||
		Labels: is.imageLabels,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle imported image names
 | 
			
		||||
	if refType, ok := desc.Annotations["io.containerd.import.ref-type"]; ok {
 | 
			
		||||
		var nameT func(string) string
 | 
			
		||||
		if is.checkPrefix {
 | 
			
		||||
			nameT = archive.FilterRefPrefix(is.namePrefix)
 | 
			
		||||
		} else {
 | 
			
		||||
			nameT = archive.AddRefPrefix(is.namePrefix)
 | 
			
		||||
		}
 | 
			
		||||
		name := imageName(desc.Annotations, nameT)
 | 
			
		||||
		switch refType {
 | 
			
		||||
		case "name":
 | 
			
		||||
			if name == "" {
 | 
			
		||||
				return images.Image{}, fmt.Errorf("no image name: %w", errdefs.ErrNotFound)
 | 
			
		||||
			}
 | 
			
		||||
			img.Name = name
 | 
			
		||||
		case "digest":
 | 
			
		||||
			if !is.digestRefs || (!is.alwaysDigest && name != "") {
 | 
			
		||||
				return images.Image{}, fmt.Errorf("no digest refs: %w", errdefs.ErrNotFound)
 | 
			
		||||
			}
 | 
			
		||||
			img.Name = fmt.Sprintf("%s@%s", is.namePrefix, desc.Digest)
 | 
			
		||||
		default:
 | 
			
		||||
			return images.Image{}, fmt.Errorf("ref type not supported: %w", errdefs.ErrInvalidArgument)
 | 
			
		||||
		}
 | 
			
		||||
		delete(desc.Annotations, "io.containerd.import.ref-type")
 | 
			
		||||
	} else if img.Name == "" {
 | 
			
		||||
		// No valid image combination found
 | 
			
		||||
		return images.Image{}, fmt.Errorf("no image name found: %w", errdefs.ErrNotFound)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		if created, err := store.Create(ctx, img); err != nil {
 | 
			
		||||
			if !errdefs.IsAlreadyExists(err) {
 | 
			
		||||
@@ -189,6 +244,10 @@ func (is *Store) MarshalAny(context.Context, streaming.StreamCreator) (typeurl.A
 | 
			
		||||
		ManifestLimit: uint32(is.manifestLimit),
 | 
			
		||||
		AllMetadata:   is.allMetadata,
 | 
			
		||||
		Platforms:     platformsToProto(is.platforms),
 | 
			
		||||
		Prefix:        is.namePrefix,
 | 
			
		||||
		CheckPrefix:   is.checkPrefix,
 | 
			
		||||
		DigestRefs:    is.digestRefs,
 | 
			
		||||
		AlwaysDigest:  is.alwaysDigest,
 | 
			
		||||
		Unpacks:       unpackToProto(is.unpacks),
 | 
			
		||||
	}
 | 
			
		||||
	return typeurl.MarshalAny(s)
 | 
			
		||||
@@ -205,6 +264,10 @@ func (is *Store) UnmarshalAny(ctx context.Context, sm streaming.StreamGetter, a
 | 
			
		||||
	is.manifestLimit = int(s.ManifestLimit)
 | 
			
		||||
	is.allMetadata = s.AllMetadata
 | 
			
		||||
	is.platforms = platformFromProto(s.Platforms)
 | 
			
		||||
	is.namePrefix = s.Prefix
 | 
			
		||||
	is.checkPrefix = s.CheckPrefix
 | 
			
		||||
	is.digestRefs = s.DigestRefs
 | 
			
		||||
	is.alwaysDigest = s.AlwaysDigest
 | 
			
		||||
	is.unpacks = unpackFromProto(s.Unpacks)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -262,3 +325,17 @@ func unpackFromProto(auc []*transfertypes.UnpackConfiguration) []UnpackConfigura
 | 
			
		||||
	}
 | 
			
		||||
	return uc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func imageName(annotations map[string]string, ociCleanup func(string) string) string {
 | 
			
		||||
	name := annotations[images.AnnotationImageName]
 | 
			
		||||
	if name != "" {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	name = annotations[ocispec.AnnotationRefName]
 | 
			
		||||
	if name != "" {
 | 
			
		||||
		if ociCleanup != nil {
 | 
			
		||||
			name = ociCleanup(name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return name
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user