From 36d860ebcea8a2cc103f6cdd412c4f74ab317d68 Mon Sep 17 00:00:00 2001 From: Paul Fisher Date: Thu, 21 Oct 2021 13:29:47 -0700 Subject: [PATCH] Add --dest-precompute-digests option for docker This ensures layers are not uploaded that already exist on the destination registry, in exchange for streaming layers to temporary files when digests are unknown (ex. compressing "on the fly"). Signed-off-by: Paul Fisher --- cmd/skopeo/utils.go | 3 +++ cmd/skopeo/utils_test.go | 34 ++++++++++++++++++---------------- completions/bash/skopeo | 1 + docs/skopeo-copy.1.md | 4 ++++ 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/cmd/skopeo/utils.go b/cmd/skopeo/utils.go index c4d2f702..3cb61aac 100644 --- a/cmd/skopeo/utils.go +++ b/cmd/skopeo/utils.go @@ -227,6 +227,7 @@ type imageDestOptions struct { ociAcceptUncompressedLayers bool // Whether to accept uncompressed layers in the oci: transport compressionFormat string // Format to use for the compression compressionLevel optionalInt // Level to use for the compression + precomputeDigests bool // Precompute digests to dedup layers when saving to the docker: transport } // imageDestFlags prepares a collection of CLI flags writing into imageDestOptions, and the managed imageDestOptions structure. @@ -240,6 +241,7 @@ func imageDestFlags(global *globalOptions, shared *sharedImageOptions, deprecate fs.BoolVar(&opts.ociAcceptUncompressedLayers, flagPrefix+"oci-accept-uncompressed-layers", false, "Allow uncompressed image layers when saving to an OCI image using the 'oci' transport. (default is to compress things that aren't compressed)") fs.StringVar(&opts.compressionFormat, flagPrefix+"compress-format", "", "`FORMAT` to use for the compression") fs.Var(newOptionalIntValue(&opts.compressionLevel), flagPrefix+"compress-level", "`LEVEL` to use for the compression") + fs.BoolVar(&opts.precomputeDigests, flagPrefix+"precompute-digests", false, "Precompute digests to prevent uploading layers already on the registry using the 'docker' transport.") return fs, &opts } @@ -264,6 +266,7 @@ func (opts *imageDestOptions) newSystemContext() (*types.SystemContext, error) { if opts.compressionLevel.present { ctx.CompressionLevel = &opts.compressionLevel.value } + ctx.DockerRegistryPushPrecomputeDigests = opts.precomputeDigests return ctx, err } diff --git a/cmd/skopeo/utils_test.go b/cmd/skopeo/utils_test.go index 6c5fada3..1487a031 100644 --- a/cmd/skopeo/utils_test.go +++ b/cmd/skopeo/utils_test.go @@ -167,26 +167,28 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) { "--dest-tls-verify=false", "--dest-creds", "creds-user:creds-password", "--dest-registry-token", "faketoken", + "--dest-precompute-digests=true", }) res, err = opts.newSystemContext() require.NoError(t, err) assert.Equal(t, &types.SystemContext{ - RegistriesDirPath: "/srv/registries.d", - AuthFilePath: "/srv/authfile", - ArchitectureChoice: "overridden-arch", - OSChoice: "overridden-os", - VariantChoice: "overridden-variant", - OCISharedBlobDirPath: "/srv/shared-blob-dir", - DockerCertPath: "/srv/cert-dir", - DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, - DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"}, - DockerBearerRegistryToken: "faketoken", - DockerDaemonCertPath: "/srv/cert-dir", - DockerDaemonHost: "daemon-host.example.com", - DockerDaemonInsecureSkipTLSVerify: true, - DockerRegistryUserAgent: defaultUserAgent, - DirForceCompress: true, - BigFilesTemporaryDir: "/srv", + RegistriesDirPath: "/srv/registries.d", + AuthFilePath: "/srv/authfile", + ArchitectureChoice: "overridden-arch", + OSChoice: "overridden-os", + VariantChoice: "overridden-variant", + OCISharedBlobDirPath: "/srv/shared-blob-dir", + DockerCertPath: "/srv/cert-dir", + DockerInsecureSkipTLSVerify: types.OptionalBoolTrue, + DockerAuthConfig: &types.DockerAuthConfig{Username: "creds-user", Password: "creds-password"}, + DockerBearerRegistryToken: "faketoken", + DockerDaemonCertPath: "/srv/cert-dir", + DockerDaemonHost: "daemon-host.example.com", + DockerDaemonInsecureSkipTLSVerify: true, + DockerRegistryUserAgent: defaultUserAgent, + DirForceCompress: true, + BigFilesTemporaryDir: "/srv", + DockerRegistryPushPrecomputeDigests: true, }, res) // Global/per-command tlsVerify behavior is tested in TestTLSVerifyFlags. diff --git a/completions/bash/skopeo b/completions/bash/skopeo index f5a28918..da36d3b2 100644 --- a/completions/bash/skopeo +++ b/completions/bash/skopeo @@ -65,6 +65,7 @@ _skopeo_copy() { --src-no-creds --dest-no-creds --dest-oci-accept-uncompressed-layers + --dest-precompute-digests " local transports diff --git a/docs/skopeo-copy.1.md b/docs/skopeo-copy.1.md index 807a6c6c..e9c21592 100644 --- a/docs/skopeo-copy.1.md +++ b/docs/skopeo-copy.1.md @@ -160,6 +160,10 @@ Bearer token for accessing the source registry. Bearer token for accessing the destination registry. +**--dest-precompute-digests** _bool-value_ + +Precompute digests to ensure layers are not uploaded that already exist on the destination registry. Layers with initially unknown digests (ex. compressing "on the fly") will be temporarily streamed to disk. + **--retry-times** The number of times to retry. Retry wait time will be exponentially increased based on the number of failed attempts.