From b950f83c60465de600afa07e133571968c590c63 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Sat, 2 Oct 2021 09:11:19 +0530 Subject: [PATCH] issue#1466 - Introduce a --keep-going option to allow "sync" command to continue syncing even after a particular image sync fails --- cmd/skopeo/sync.go | 20 ++++++++++++++++---- completions/bash/skopeo | 1 + docs/skopeo-sync.1.md | 3 +++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/cmd/skopeo/sync.go b/cmd/skopeo/sync.go index f6b04483..06949550 100644 --- a/cmd/skopeo/sync.go +++ b/cmd/skopeo/sync.go @@ -39,6 +39,7 @@ type syncOptions struct { destination string // Destination registry 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 + keepGoing bool // Whether or not to abort the sync if there are any errors during syncing the images } // repoDescriptor contains information of a single repository used as a sync source. @@ -104,6 +105,7 @@ See skopeo-sync(1) for details. 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.BoolVarP(&opts.all, "all", "a", false, "Copy all images if SOURCE-IMAGE is a list") + flags.BoolVarP(&opts.keepGoing, "keep-going", "", false, "Do not abort the sync if any image copy fails") flags.AddFlagSet(&sharedFlags) flags.AddFlagSet(&deprecatedTLSVerifyFlags) flags.AddFlagSet(&srcFlags) @@ -568,7 +570,6 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error { return err } - imagesNumber := 0 options := copy.Options{ RemoveSignatures: opts.removeSignatures, SignBy: opts.signByFingerprint, @@ -578,7 +579,8 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error { OptimizeDestinationImageAlreadyExists: true, ForceManifestMIMEType: manifestType, } - + errorsPresent := false + imagesNumber := 0 for _, srcRepo := range srcRepoList { options.SourceCtx = srcRepo.Context for counter, ref := range srcRepo.ImageRefs { @@ -614,12 +616,22 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error { _, err = copy.Image(ctx, policyContext, destRef, ref, &options) return err }, opts.retryOpts); err != nil { - return errors.Wrapf(err, "Error copying ref %q", transports.ImageName(ref)) + if !opts.keepGoing { + return errors.Wrapf(err, "Error copying ref %q", transports.ImageName(ref)) + } + // log the error, keep a note that there was a failure and move on to the next + // image ref + errorsPresent = true + logrus.WithError(err).Errorf("Error copying ref %q", transports.ImageName(ref)) + continue } imagesNumber++ } } logrus.Infof("Synced %d images from %d sources", imagesNumber, len(srcRepoList)) - return nil + if !errorsPresent { + return nil + } + return errors.New("Sync failed due to previous reported error(s) for one or more images") } diff --git a/completions/bash/skopeo b/completions/bash/skopeo index ab994c0a..70681e1c 100644 --- a/completions/bash/skopeo +++ b/completions/bash/skopeo @@ -97,6 +97,7 @@ _skopeo_sync() { --scoped --src-no-creds --src-tls-verify + --keep-going " local transports diff --git a/docs/skopeo-sync.1.md b/docs/skopeo-sync.1.md index b5fb78c5..720097cc 100644 --- a/docs/skopeo-sync.1.md +++ b/docs/skopeo-sync.1.md @@ -88,6 +88,9 @@ Print usage statement. **--retry-times** the number of times to retry, retry wait time will be exponentially increased based on the number of failed attempts. +**--keep-going** +If any errors occur during copying of images, those errors are logged and the process continues syncing rest of the images and finally fails at the end. + ## EXAMPLES ### Synchronizing to a local directory