Skip to content

Commit

Permalink
copy: add --multi-arch=sparse:...
Browse files Browse the repository at this point in the history
Add a "sparse:..." value for the copy --multi-arch option, where the
"..." is a comma-separated list of instance digests, platform
specifications, or the literal word "system" to signify the local
platform.

Signed-off-by: Nalin Dahyabhai <[email protected]>
  • Loading branch information
nalind committed May 2, 2023
1 parent b48dea8 commit 75fe37f
Show file tree
Hide file tree
Showing 22 changed files with 1,720 additions and 20 deletions.
58 changes: 41 additions & 17 deletions cmd/skopeo/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"strings"

"github.com/containerd/containerd/platforms"
commonFlag "github.com/containers/common/pkg/flag"
"github.com/containers/common/pkg/retry"
"github.com/containers/image/v5/copy"
Expand All @@ -19,6 +20,8 @@ import (
"github.com/containers/image/v5/transports/alltransports"
encconfig "github.com/containers/ocicrypt/config"
enchelpers "github.com/containers/ocicrypt/helpers"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -99,23 +102,40 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
}

// parseMultiArch parses the list processing selection
// It returns the copy.ImageListSelection to use with image.Copy option
func parseMultiArch(multiArch string) (copy.ImageListSelection, error) {
switch multiArch {
case "system":
return copy.CopySystemImage, nil
case "all":
return copy.CopyAllImages, nil
// There is no CopyNoImages value in copy.ImageListSelection, but because we
// don't provide an option to select a set of images to copy, we can use
// CopySpecificImages.
case "index-only":
return copy.CopySpecificImages, nil
// We don't expose CopySpecificImages other than index-only above, because
// we currently don't provide an option to choose the images to copy. That
// could be added in the future.
// It returns the copy.ImageListSelection, instance list, and platform list to use in image.Copy option
func parseMultiArch(multiArch string) (copy.ImageListSelection, []digest.Digest, []imgspecv1.Platform, error) {
switch {
case multiArch == "system":
return copy.CopySystemImage, nil, nil, nil
case multiArch == "all":
return copy.CopyAllImages, nil, nil, nil
case multiArch == "index-only":
// There is no CopyNoImages value in copy.ImageListSelection per se, but
// we can get the desired effect by using CopySpecificImages.
return copy.CopySpecificImages, nil, nil, nil
case strings.HasPrefix(multiArch, "sparse:"):
sparseArg := strings.TrimPrefix(multiArch, "sparse:")
platformSpecs := strings.Split(sparseArg, ",")
var platformList []imgspecv1.Platform
var instanceList []digest.Digest
for _, platformSpec := range platformSpecs {
if instanceDigest, err := digest.Parse(platformSpec); err == nil {
instanceList = append(instanceList, instanceDigest)
continue
}
if platformSpec == "system" {
platformList = append(platformList, imgspecv1.Platform{})
} else {
p, err := platforms.Parse(platformSpec)
if err != nil {
return copy.CopySpecificImages, nil, nil, fmt.Errorf("while parsing platform specifier %q: %w", platformSpec, err)
}
platformList = append(platformList, p)
}
}
return copy.CopySpecificImages, instanceList, platformList, nil
default:
return copy.CopySystemImage, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'all', or 'index-only'", multiArch)
return copy.CopySystemImage, nil, nil, fmt.Errorf("unknown multi-arch option %q. Choose one of the supported options: 'system', 'sparse:...', 'all', or 'index-only'", multiArch)
}
}

Expand Down Expand Up @@ -186,11 +206,13 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) (retErr error) {
}

imageListSelection := copy.CopySystemImage
var instanceDigests []digest.Digest
var instancePlatforms []imgspecv1.Platform
if opts.multiArch.Present() && opts.all {
return fmt.Errorf("Cannot use --all and --multi-arch flags together")
}
if opts.multiArch.Present() {
imageListSelection, err = parseMultiArch(opts.multiArch.Value())
imageListSelection, instanceDigests, instancePlatforms, err = parseMultiArch(opts.multiArch.Value())
if err != nil {
return err
}
Expand Down Expand Up @@ -296,6 +318,8 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) (retErr error) {
DestinationCtx: destinationCtx,
ForceManifestMIMEType: manifestType,
ImageListSelection: imageListSelection,
Instances: instanceDigests,
InstancePlatforms: instancePlatforms,
PreserveDigests: opts.preserveDigests,
OciDecryptConfig: decConfig,
OciEncryptLayers: encLayers,
Expand Down
7 changes: 4 additions & 3 deletions docs/skopeo-copy.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ Print usage statement
Control what is copied if _source-image_ refers to a multi-architecture image. Default is system.

Options:
- system: Copy only the image that matches the system architecture
- all: Copy the full multi-architecture image
- index-only: Copy only the index
- "system": Copy only the image that matches the system architecture
- "all": Copy the full multi-architecture image
- "index-only": Copy only the index
- "sparse:_list_": Copy the index and images which match the comma-separated list of platform specifications, digests, or the local system ("system")

The index-only option usually fails unless the referenced per-architecture images are already present in the destination, or the target registry supports sparse indexes.

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/containers/skopeo
go 1.18

require (
github.com/containerd/containerd v1.7.0
github.com/containers/common v0.52.0
github.com/containers/image/v5 v5.25.0
github.com/containers/ocicrypt v1.1.7
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg=
github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc=
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
github.com/containers/common v0.52.0 h1:S5GApgpNEGBuPhDHTFgMc55y5gsuxHcQeElvUpO5kp4=
Expand Down
191 changes: 191 additions & 0 deletions vendor/github.com/containerd/containerd/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions vendor/github.com/containerd/containerd/NOTICE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 75fe37f

Please sign in to comment.