Add option to preserve digests on copy

When enabled, if digests can't be preserved an error will be raised.

Signed-off-by: James Hewitt <james.hewitt@uk.ibm.com>
This commit is contained in:
James Hewitt
2021-12-03 16:02:40 +00:00
parent 2046bfdaaa
commit c582c4844f
4 changed files with 22 additions and 0 deletions

View File

@@ -40,6 +40,7 @@ type syncOptions struct {
destination string // Destination registry name destination string // Destination registry name
scoped bool // When true, namespace copied images at destination using the source repository name scoped bool // When true, namespace copied images at destination using the source repository name
all bool // Copy all of the images if an image in the source is a list all bool // Copy all of the images if an image in the source is a list
preserveDigests bool // Preserve digests during sync
keepGoing bool // Whether or not to abort the sync if there are any errors during syncing the images keepGoing bool // Whether or not to abort the sync if there are any errors during syncing the images
} }
@@ -106,6 +107,7 @@ See skopeo-sync(1) for details.
flags.StringVarP(&opts.destination, "dest", "d", "", "DESTINATION transport type") flags.StringVarP(&opts.destination, "dest", "d", "", "DESTINATION transport type")
flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope") flags.BoolVar(&opts.scoped, "scoped", false, "Images at DESTINATION are prefix using the full source image path as scope")
flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list") flags.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list")
flags.BoolVar(&opts.preserveDigests, "preserve-digests", false, "Preserve digests of images and lists")
flags.BoolVarP(&opts.keepGoing, "keep-going", "", false, "Do not abort the sync if any image copy fails") flags.BoolVarP(&opts.keepGoing, "keep-going", "", false, "Do not abort the sync if any image copy fails")
flags.AddFlagSet(&sharedFlags) flags.AddFlagSet(&sharedFlags)
flags.AddFlagSet(&deprecatedTLSVerifyFlags) flags.AddFlagSet(&deprecatedTLSVerifyFlags)
@@ -577,6 +579,7 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
ReportWriter: os.Stdout, ReportWriter: os.Stdout,
DestinationCtx: destinationCtx, DestinationCtx: destinationCtx,
ImageListSelection: imageListSelection, ImageListSelection: imageListSelection,
PreserveDigests: opts.preserveDigests,
OptimizeDestinationImageAlreadyExists: true, OptimizeDestinationImageAlreadyExists: true,
ForceManifestMIMEType: manifestType, ForceManifestMIMEType: manifestType,
} }

View File

@@ -109,6 +109,7 @@ _skopeo_sync() {
--src-no-creds --src-no-creds
--src-tls-verify --src-tls-verify
--keep-going --keep-going
--preserve-digests
" "
local transports local transports

View File

@@ -62,6 +62,8 @@ Print usage statement.
**--scoped** Prefix images with the source image path, so that multiple images with the same name can be stored at _destination_. **--scoped** Prefix images with the source image path, so that multiple images with the same name can be stored at _destination_.
**--preserve-digests** Preserve the digests during copying. Fail if the digest cannot be preserved.
**--remove-signatures** Do not copy signatures, if any, from _source-image_. This is necessary when copying a signed image to a destination which does not support signatures. **--remove-signatures** Do not copy signatures, if any, from _source-image_. This is necessary when copying a signed image to a destination which does not support signatures.
**--sign-by**=_key-id_ Add a signature using that key ID for an image name corresponding to _destination-image_. **--sign-by**=_key-id_ Add a signature using that key ID for an image name corresponding to _destination-image_.

View File

@@ -163,6 +163,22 @@ func (s *SyncSuite) TestDocker2DirTaggedAll(c *check.C) {
c.Assert(out, check.Equals, "") c.Assert(out, check.Equals, "")
} }
func (s *SyncSuite) TestPreserveDigests(c *check.C) {
tmpDir, err := ioutil.TempDir("", "skopeo-sync-test")
c.Assert(err, check.IsNil)
defer os.RemoveAll(tmpDir)
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedManifestList
// copy docker => dir
assertSkopeoSucceeds(c, "", "copy", "--all", "--preserve-digests", "docker://"+image, "dir:"+tmpDir)
_, err = os.Stat(path.Join(tmpDir, "manifest.json"))
c.Assert(err, check.IsNil)
assertSkopeoFails(c, ".*Instructed to preserve digests.*", "copy", "--all", "--preserve-digests", "--format=oci", "docker://"+image, "dir:"+tmpDir)
}
func (s *SyncSuite) TestScoped(c *check.C) { func (s *SyncSuite) TestScoped(c *check.C) {
// FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection. // FIXME: It would be nice to use one of the local Docker registries instead of needing an Internet connection.
image := pullableTaggedImage image := pullableTaggedImage