Skip to content

Commit

Permalink
Add copy.CopyOnlyInstances
Browse files Browse the repository at this point in the history
Add copy.CopyOnlyInstances to the copy.MultipleImagesOption enumerated
type, add Instance() to the manifest.List interface, and add an
Instances field top copy.Options.

Signed-off-by: Nalin Dahyabhai <[email protected]>
  • Loading branch information
nalind committed Oct 1, 2019
1 parent 1760311 commit 4d513f5
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 6 deletions.
42 changes: 36 additions & 6 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ const (
// source reference refers to a list of images, but the target reference
// can only accept one image, an error should be returned.
CopyAllImages
// CopyOnlyInstances is a value which, when set in Options.MultipleImages,
// indicates that the caller expects the source reference to be a list
// of images, and wants only specific instances from it copied, along with
// the list itself. If the target reference can only accept one image
// (i.e., it cannot accept lists), an error should be returned.
CopyOnlyInstances
)

// MultipleImagesOption is either CopyOnlyCurrentRuntimeImage or CopyAllImages, to control
Expand All @@ -141,7 +147,8 @@ type Options struct {
Progress chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.
// manifest MIME type of image set by user. "" is default and means use the autodetection to the the manifest MIME type
ForceManifestMIMEType string
MultipleImages MultipleImagesOption // set to either CopyOnlyCurrentRuntimeImage or CopyAllImages
MultipleImages MultipleImagesOption // set to either CopyOnlyCurrentRuntimeImage, CopyAllImages, or CopyOnlyInstances
Instances []digest.Digest // if MultipleImages is CopyOnlyInstances, copy only these instances and the list itself
}

// Image copies image from srcRef to destRef, using policyContext to validate
Expand All @@ -157,7 +164,7 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
options = &Options{}
}

if options.MultipleImages != CopyAllImages && options.MultipleImages != CopyOnlyCurrentRuntimeImage {
if options.MultipleImages != CopyAllImages && options.MultipleImages != CopyOnlyCurrentRuntimeImage && options.MultipleImages != CopyOnlyInstances {
return nil, errors.Errorf("Invalid value for options.MultipleImages: %d", options.MultipleImages)
}
reportWriter := ioutil.Discard
Expand Down Expand Up @@ -260,13 +267,18 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
if copiedManifest, _, _, err = c.copyOneImage(ctx, policyContext, options, unparsedInstance, nil); err != nil {
return nil, err
}
} else { /* options.MultipleImages == CopyAllImages */
} else { /* options.MultipleImages == CopyAllImages or options.MultipleImages == CopyOnlyInstances, */
// If we were asked to copy multiple images and can't, that's an error.
if !supportsMultipleImages(c.dest) {
return nil, errors.Errorf("Error copying multiple images: destination reference %q does not support multiple images", transports.ImageName(destRef))
}
// Copy all of the images.
logrus.Debugf("Source is a manifest list; copying all instances")
// Copy some or all of the images.
switch options.MultipleImages {
case CopyAllImages:
logrus.Debugf("Source is a manifest list; copying all instances")
case CopyOnlyInstances:
logrus.Debugf("Source is a manifest list; copying some instances")
}
if copiedManifest, _, err = c.copyMultipleImages(ctx, policyContext, options, unparsedToplevel); err != nil {
return nil, err
}
Expand Down Expand Up @@ -329,10 +341,28 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
}

// Copy each image, in turn.
// Copy each image, or just the ones we want to copy, in turn.
instanceDigests := list.Instances()
updates := make([]manifest.ListUpdate, len(instanceDigests))
for i, instanceDigest := range instanceDigests {
if options.MultipleImages == CopyOnlyInstances {
skip := true
for _, instance := range options.Instances {
if instance == instanceDigest {
skip = false
break
}
}
if skip {
update, err := list.Instance(instanceDigest)
if err != nil {
return nil, "", err
}
logrus.Debugf("Skipping instance %s (%d/%d)", instanceDigest, i+1, len(instanceDigests))
updates[i] = update
continue
}
}
logrus.Debugf("Copying instance %s (%d/%d)", instanceDigest, i+1, len(instanceDigests))
unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceDigest)
updatedManifest, updatedManifestType, updatedManifestDigest, err := c.copyOneImage(ctx, policyContext, options, unparsedInstance, &instanceDigest)
Expand Down
14 changes: 14 additions & 0 deletions manifest/docker_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ func (list *Schema2List) Instances() []digest.Digest {
return results
}

// Instance returns the size and MIME type of a particular instance in the list.
func (list *Schema2List) Instance(instanceDigest digest.Digest) (ListUpdate, error) {
for _, manifest := range list.Manifests {
if manifest.Digest == instanceDigest {
return ListUpdate{
Digest: manifest.Digest,
Size: manifest.Size,
MediaType: manifest.MediaType,
}, nil
}
}
return ListUpdate{}, errors.Errorf("unable to find instance %s passed to Schema2List.Instances", instanceDigest)
}

// UpdateInstances updates the sizes, digests, and media types of the manifests
// which the list catalogs.
func (list *Schema2List) UpdateInstances(updates []ListUpdate) error {
Expand Down
3 changes: 3 additions & 0 deletions manifest/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ type List interface {
// must be specified.
UpdateInstances([]ListUpdate) error

// Instance returns the size and MIME type of a particular instance in the list.
Instance(digest.Digest) (ListUpdate, error)

// ChooseInstance selects which manifest is most appropriate for the platform described by the
// SystemContext, or for the current platform if the SystemContext doesn't specify any details.
ChooseInstance(ctx *types.SystemContext) (digest.Digest, error)
Expand Down
14 changes: 14 additions & 0 deletions manifest/oci_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ func (index *OCI1Index) Instances() []digest.Digest {
return results
}

// Instance returns the size and MIME type of a particular instance in the index.
func (index *OCI1Index) Instance(instanceDigest digest.Digest) (ListUpdate, error) {
for _, manifest := range index.Manifests {
if manifest.Digest == instanceDigest {
return ListUpdate{
Digest: manifest.Digest,
Size: manifest.Size,
MediaType: manifest.MediaType,
}, nil
}
}
return ListUpdate{}, errors.Errorf("unable to find instance %s in OCI1Index", instanceDigest)
}

// UpdateInstances updates the sizes, digests, and media types of the manifests
// which the list catalogs.
func (index *OCI1Index) UpdateInstances(updates []ListUpdate) error {
Expand Down

0 comments on commit 4d513f5

Please sign in to comment.