Skip to content

Commit

Permalink
copy: implement instanceCopyClone for zstd compression
Browse files Browse the repository at this point in the history
* copy.Options now contains a new field `EnsureCompressionVariantExists
  map[string]int` which allows users to specify if they want to clone
images with specified `compression`.

* copyMultipleImages now implements `instanceCopyClone` and extends
  function specifically for `zstd` compression.

Signed-off-by: Aditya R <[email protected]>
  • Loading branch information
flouthoc committed Jun 7, 2023
1 parent 8c21415 commit 805cb83
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 4 deletions.
4 changes: 4 additions & 0 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ type Options struct {
// Download layer contents with "nondistributable" media types ("foreign" layers) and translate the layer media type
// to not indicate "nondistributable".
DownloadForeignLayers bool

// Contains a map of compression algorithm and compression level, where c/image will ensure that selected
// images in the manifest list will be replicated with provided compression algorithms.
EnsureCompressionVariantExists map[string]int
}

// copier allows us to keep track of diffID values for blobs, and other
Expand Down
61 changes: 57 additions & 4 deletions copy/multiple.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (
"github.com/containers/image/v5/internal/image"
internalManifest "github.com/containers/image/v5/internal/manifest"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/transports"
digest "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
Expand All @@ -28,6 +30,7 @@ const (
type instanceCopy struct {
op instanceCopyKind
sourceDigest digest.Digest
forceZstd bool
}

// prepareInstanceCopies prepares a list of instances which needs to copied to the manifest list.
Expand All @@ -39,8 +42,15 @@ func prepareInstanceCopies(instanceDigests []digest.Digest, options *Options) []
logrus.Debugf("Skipping instance %s (%d/%d)", instanceDigest, i+1, len(instanceDigests))
continue
}
operation := instanceCopyCopy
forceZstd := false
if _, ok := options.EnsureCompressionVariantExists["zstd"]; ok {
operation = instanceCopyClone
forceZstd = true
}
res = append(res, instanceCopy{
op: instanceCopyCopy,
op: operation,
forceZstd: forceZstd,
sourceDigest: instanceDigest,
})
}
Expand Down Expand Up @@ -124,8 +134,9 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
for i, instance := range instanceCopyList {
// Update instances to be edited by their `ListOperation` and
// populate necessary fields.
switch instance.op {
case instanceCopyCopy:
processedOp := false
if instance.op == instanceCopyCopy || instance.op == instanceCopyClone {
processedOp = true
logrus.Debugf("Copying instance %s (%d/%d)", instance.sourceDigest, i+1, len(instanceCopyList))
c.Printf("Copying image %s (%d/%d)\n", instance.sourceDigest, i+1, len(instanceCopyList))
unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceCopyList[i].sourceDigest)
Expand All @@ -140,7 +151,49 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
UpdateDigest: updatedManifestDigest,
UpdateSize: int64(len(updatedManifest)),
UpdateMediaType: updatedManifestType})
default:
}
if instance.op == instanceCopyClone {
processedOp = false
c.Printf("Replicating image %s (%d/%d)\n", instance.sourceDigest, i+1, len(instanceCopyList))
c.Printf("Replicating image %s (%d/%d)\n", instance.sourceDigest, i+1, len(instanceCopyList))
unparsedInstance := image.UnparsedInstance(c.rawSource, &instanceCopyList[i].sourceDigest)
src, err := image.FromUnparsedImage(ctx, options.SourceCtx, unparsedInstance)
if err != nil {
return nil, fmt.Errorf("initializing image from source %s: %w", transports.ImageName(c.rawSource.Reference()), err)
}
imgConfig, err := src.OCIConfig(ctx)
if err != nil {
return nil, fmt.Errorf("parsing image configuration: %w", err)
}
imgPlatform := imgspecv1.Platform{Architecture: imgConfig.Architecture,
OS: imgConfig.OS,
OSVersion: imgConfig.OSVersion,
OSFeatures: imgConfig.OSFeatures,
Variant: imgConfig.Variant}
addAnnotations := make(map[string]string)
if instance.forceZstd {
// add `zstd` annotation
addAnnotations[internalManifest.OCI1InstanceAnnotationCompressionZSTD] = "true"
// copy options with new compression format
optionsClone := options
optionsClone.DestinationCtx.CompressionFormat = &compression.Zstd
compressionLevel := options.EnsureCompressionVariantExists["zstd"]
options.DestinationCtx.CompressionLevel = &compressionLevel
}
addManifest, addManifestType, addManifestDigest, err := c.copySingleImage(ctx, policyContext, options, unparsedToplevel, unparsedInstance, &instanceCopyList[i].sourceDigest)
if err != nil {
return nil, fmt.Errorf("Replicating image %d/%d from manifest list: %w", i+1, len(instanceCopyList), err)
}
// Record the result of a possible conversion here.
instanceEdits = append(instanceEdits, internalManifest.ListEdit{
ListOperation: internalManifest.ListOpAdd,
AddDigest: addManifestDigest,
AddSize: int64(len(addManifest)),
AddMediaType: addManifestType,
AddAnnotations: addAnnotations,
AddPlatform: &imgPlatform})
}
if !processedOp {
return nil, fmt.Errorf("copying image: invalid copy operation %d", instance.op)
}
}
Expand Down

0 comments on commit 805cb83

Please sign in to comment.