mirror of
https://github.com/containers/skopeo.git
synced 2025-08-18 14:37:16 +00:00
Merge pull request #977 from QiWang19/commands-retry
Retry on skopeo subcommands
This commit is contained in:
commit
494d237789
@ -22,6 +22,7 @@ type copyOptions struct {
|
|||||||
global *globalOptions
|
global *globalOptions
|
||||||
srcImage *imageOptions
|
srcImage *imageOptions
|
||||||
destImage *imageDestOptions
|
destImage *imageDestOptions
|
||||||
|
retryOpts *retryOptions
|
||||||
additionalTags []string // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these
|
additionalTags []string // For docker-archive: destinations, in addition to the name:tag specified as destination, also add these
|
||||||
removeSignatures bool // Do not copy signatures from the source image
|
removeSignatures bool // Do not copy signatures from the source image
|
||||||
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
||||||
@ -37,9 +38,11 @@ func copyCmd(global *globalOptions) *cobra.Command {
|
|||||||
sharedFlags, sharedOpts := sharedImageFlags()
|
sharedFlags, sharedOpts := sharedImageFlags()
|
||||||
srcFlags, srcOpts := imageFlags(global, sharedOpts, "src-", "screds")
|
srcFlags, srcOpts := imageFlags(global, sharedOpts, "src-", "screds")
|
||||||
destFlags, destOpts := imageDestFlags(global, sharedOpts, "dest-", "dcreds")
|
destFlags, destOpts := imageDestFlags(global, sharedOpts, "dest-", "dcreds")
|
||||||
|
retryFlags, retryOpts := retryFlags()
|
||||||
opts := copyOptions{global: global,
|
opts := copyOptions{global: global,
|
||||||
srcImage: srcOpts,
|
srcImage: srcOpts,
|
||||||
destImage: destOpts,
|
destImage: destOpts,
|
||||||
|
retryOpts: retryOpts,
|
||||||
}
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "copy [command options] SOURCE-IMAGE DESTINATION-IMAGE",
|
Use: "copy [command options] SOURCE-IMAGE DESTINATION-IMAGE",
|
||||||
@ -59,6 +62,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
|
|||||||
flags.AddFlagSet(&sharedFlags)
|
flags.AddFlagSet(&sharedFlags)
|
||||||
flags.AddFlagSet(&srcFlags)
|
flags.AddFlagSet(&srcFlags)
|
||||||
flags.AddFlagSet(&destFlags)
|
flags.AddFlagSet(&destFlags)
|
||||||
|
flags.AddFlagSet(&retryFlags)
|
||||||
flags.StringSliceVar(&opts.additionalTags, "additional-tag", []string{}, "additional tags (supports docker-archive)")
|
flags.StringSliceVar(&opts.additionalTags, "additional-tag", []string{}, "additional tags (supports docker-archive)")
|
||||||
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress output information when copying images")
|
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress output information when copying images")
|
||||||
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")
|
||||||
@ -178,6 +182,7 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
|
|||||||
decConfig = cc.DecryptConfig
|
decConfig = cc.DecryptConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return retryIfNecessary(ctx, func() error {
|
||||||
_, err = copy.Image(ctx, policyContext, destRef, srcRef, ©.Options{
|
_, err = copy.Image(ctx, policyContext, destRef, srcRef, ©.Options{
|
||||||
RemoveSignatures: opts.removeSignatures,
|
RemoveSignatures: opts.removeSignatures,
|
||||||
SignBy: opts.signByFingerprint,
|
SignBy: opts.signByFingerprint,
|
||||||
@ -191,4 +196,5 @@ func (opts *copyOptions) run(args []string, stdout io.Writer) error {
|
|||||||
OciEncryptConfig: encConfig,
|
OciEncryptConfig: encConfig,
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
|
}, opts.retryOpts)
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,17 @@ import (
|
|||||||
type deleteOptions struct {
|
type deleteOptions struct {
|
||||||
global *globalOptions
|
global *globalOptions
|
||||||
image *imageOptions
|
image *imageOptions
|
||||||
|
retryOpts *retryOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteCmd(global *globalOptions) *cobra.Command {
|
func deleteCmd(global *globalOptions) *cobra.Command {
|
||||||
sharedFlags, sharedOpts := sharedImageFlags()
|
sharedFlags, sharedOpts := sharedImageFlags()
|
||||||
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
|
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
|
||||||
|
retryFlags, retryOpts := retryFlags()
|
||||||
opts := deleteOptions{
|
opts := deleteOptions{
|
||||||
global: global,
|
global: global,
|
||||||
image: imageOpts,
|
image: imageOpts,
|
||||||
|
retryOpts: retryOpts,
|
||||||
}
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delete [command options] IMAGE-NAME",
|
Use: "delete [command options] IMAGE-NAME",
|
||||||
@ -38,6 +41,7 @@ See skopeo(1) section "IMAGE NAMES" for the expected format
|
|||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.AddFlagSet(&sharedFlags)
|
flags.AddFlagSet(&sharedFlags)
|
||||||
flags.AddFlagSet(&imageFlags)
|
flags.AddFlagSet(&imageFlags)
|
||||||
|
flags.AddFlagSet(&retryFlags)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,5 +67,8 @@ func (opts *deleteOptions) run(args []string, stdout io.Writer) error {
|
|||||||
|
|
||||||
ctx, cancel := opts.global.commandTimeoutContext()
|
ctx, cancel := opts.global.commandTimeoutContext()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
return retryIfNecessary(ctx, func() error {
|
||||||
return ref.DeleteImage(ctx, sys)
|
return ref.DeleteImage(ctx, sys)
|
||||||
|
}, opts.retryOpts)
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,17 @@ import (
|
|||||||
type layersOptions struct {
|
type layersOptions struct {
|
||||||
global *globalOptions
|
global *globalOptions
|
||||||
image *imageOptions
|
image *imageOptions
|
||||||
|
retryOpts *retryOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func layersCmd(global *globalOptions) *cobra.Command {
|
func layersCmd(global *globalOptions) *cobra.Command {
|
||||||
sharedFlags, sharedOpts := sharedImageFlags()
|
sharedFlags, sharedOpts := sharedImageFlags()
|
||||||
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
|
imageFlags, imageOpts := imageFlags(global, sharedOpts, "", "")
|
||||||
|
retryFlags, retryOpts := retryFlags()
|
||||||
opts := layersOptions{
|
opts := layersOptions{
|
||||||
global: global,
|
global: global,
|
||||||
image: imageOpts,
|
image: imageOpts,
|
||||||
|
retryOpts: retryOpts,
|
||||||
}
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
@ -38,6 +41,7 @@ func layersCmd(global *globalOptions) *cobra.Command {
|
|||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.AddFlagSet(&sharedFlags)
|
flags.AddFlagSet(&sharedFlags)
|
||||||
flags.AddFlagSet(&imageFlags)
|
flags.AddFlagSet(&imageFlags)
|
||||||
|
flags.AddFlagSet(&retryFlags)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +64,20 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache := blobinfocache.DefaultCache(sys)
|
cache := blobinfocache.DefaultCache(sys)
|
||||||
rawSource, err := parseImageSource(ctx, opts.image, imageName)
|
var (
|
||||||
if err != nil {
|
rawSource types.ImageSource
|
||||||
|
src types.ImageCloser
|
||||||
|
)
|
||||||
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
|
rawSource, err = parseImageSource(ctx, opts.image, imageName)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
src, err := image.FromSource(ctx, sys, rawSource)
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
if err != nil {
|
src, err = image.FromSource(ctx, sys, rawSource)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
if closeErr := rawSource.Close(); closeErr != nil {
|
if closeErr := rawSource.Close(); closeErr != nil {
|
||||||
return errors.Wrapf(err, " (close error: %v)", closeErr)
|
return errors.Wrapf(err, " (close error: %v)", closeErr)
|
||||||
}
|
}
|
||||||
@ -129,8 +141,14 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for _, bd := range blobDigests {
|
for _, bd := range blobDigests {
|
||||||
r, blobSize, err := rawSource.GetBlob(ctx, types.BlobInfo{Digest: bd.digest, Size: -1}, cache)
|
var (
|
||||||
if err != nil {
|
r io.ReadCloser
|
||||||
|
blobSize int64
|
||||||
|
)
|
||||||
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
|
r, blobSize, err = rawSource.GetBlob(ctx, types.BlobInfo{Digest: bd.digest, Size: -1}, cache)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := dest.PutBlob(ctx, r, types.BlobInfo{Digest: bd.digest, Size: blobSize}, cache, bd.isConfig); err != nil {
|
if _, err := dest.PutBlob(ctx, r, types.BlobInfo{Digest: bd.digest, Size: blobSize}, cache, bd.isConfig); err != nil {
|
||||||
@ -141,8 +159,11 @@ func (opts *layersOptions) run(args []string, stdout io.Writer) (retErr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest, _, err := src.Manifest(ctx)
|
var manifest []byte
|
||||||
if err != nil {
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
|
manifest, _, err = src.Manifest(ctx)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := dest.PutManifest(ctx, manifest, nil); err != nil {
|
if err := dest.PutManifest(ctx, manifest, nil); err != nil {
|
||||||
|
@ -24,15 +24,18 @@ type tagListOutput struct {
|
|||||||
type tagsOptions struct {
|
type tagsOptions struct {
|
||||||
global *globalOptions
|
global *globalOptions
|
||||||
image *imageOptions
|
image *imageOptions
|
||||||
|
retryOpts *retryOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagsCmd(global *globalOptions) *cobra.Command {
|
func tagsCmd(global *globalOptions) *cobra.Command {
|
||||||
sharedFlags, sharedOpts := sharedImageFlags()
|
sharedFlags, sharedOpts := sharedImageFlags()
|
||||||
imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, "", "")
|
imageFlags, imageOpts := dockerImageFlags(global, sharedOpts, "", "")
|
||||||
|
retryFlags, retryOpts := retryFlags()
|
||||||
|
|
||||||
opts := tagsOptions{
|
opts := tagsOptions{
|
||||||
global: global,
|
global: global,
|
||||||
image: imageOpts,
|
image: imageOpts,
|
||||||
|
retryOpts: retryOpts,
|
||||||
}
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "list-tags [command options] REPOSITORY-NAME",
|
Use: "list-tags [command options] REPOSITORY-NAME",
|
||||||
@ -51,6 +54,7 @@ See skopeo-list-tags(1) section "REPOSITORY NAMES" for the expected format
|
|||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.AddFlagSet(&sharedFlags)
|
flags.AddFlagSet(&sharedFlags)
|
||||||
flags.AddFlagSet(&imageFlags)
|
flags.AddFlagSet(&imageFlags)
|
||||||
|
flags.AddFlagSet(&retryFlags)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +122,12 @@ func (opts *tagsOptions) run(args []string, stdout io.Writer) (retErr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repositoryName, tagListing, err := listDockerTags(ctx, sys, imgRef)
|
var repositoryName string
|
||||||
if err != nil {
|
var tagListing []string
|
||||||
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
|
repositoryName, tagListing, err = listDockerTags(ctx, sys, imgRef)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ type syncOptions struct {
|
|||||||
global *globalOptions // Global (not command dependant) skopeo options
|
global *globalOptions // Global (not command dependant) skopeo options
|
||||||
srcImage *imageOptions // Source image options
|
srcImage *imageOptions // Source image options
|
||||||
destImage *imageDestOptions // Destination image options
|
destImage *imageDestOptions // Destination image options
|
||||||
|
retryOpts *retryOptions
|
||||||
removeSignatures bool // Do not copy signatures from the source image
|
removeSignatures bool // Do not copy signatures from the source image
|
||||||
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
signByFingerprint string // Sign the image using a GPG key with the specified fingerprint
|
||||||
source string // Source repository name
|
source string // Source repository name
|
||||||
@ -65,11 +66,13 @@ func syncCmd(global *globalOptions) *cobra.Command {
|
|||||||
sharedFlags, sharedOpts := sharedImageFlags()
|
sharedFlags, sharedOpts := sharedImageFlags()
|
||||||
srcFlags, srcOpts := dockerImageFlags(global, sharedOpts, "src-", "screds")
|
srcFlags, srcOpts := dockerImageFlags(global, sharedOpts, "src-", "screds")
|
||||||
destFlags, destOpts := dockerImageFlags(global, sharedOpts, "dest-", "dcreds")
|
destFlags, destOpts := dockerImageFlags(global, sharedOpts, "dest-", "dcreds")
|
||||||
|
retryFlags, retryOpts := retryFlags()
|
||||||
|
|
||||||
opts := syncOptions{
|
opts := syncOptions{
|
||||||
global: global,
|
global: global,
|
||||||
srcImage: srcOpts,
|
srcImage: srcOpts,
|
||||||
destImage: &imageDestOptions{imageOptions: destOpts},
|
destImage: &imageDestOptions{imageOptions: destOpts},
|
||||||
|
retryOpts: retryOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@ -95,6 +98,7 @@ See skopeo-sync(1) for details.
|
|||||||
flags.AddFlagSet(&sharedFlags)
|
flags.AddFlagSet(&sharedFlags)
|
||||||
flags.AddFlagSet(&srcFlags)
|
flags.AddFlagSet(&srcFlags)
|
||||||
flags.AddFlagSet(&destFlags)
|
flags.AddFlagSet(&destFlags)
|
||||||
|
flags.AddFlagSet(&retryFlags)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,9 +513,15 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := opts.global.commandTimeoutContext()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
sourceArg := args[0]
|
sourceArg := args[0]
|
||||||
srcRepoList, err := imagesToCopy(sourceArg, opts.source, sourceCtx)
|
var srcRepoList []repoDescriptor
|
||||||
if err != nil {
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
|
srcRepoList, err = imagesToCopy(sourceArg, opts.source, sourceCtx)
|
||||||
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,9 +531,6 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := opts.global.commandTimeoutContext()
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
imagesNumber := 0
|
imagesNumber := 0
|
||||||
options := copy.Options{
|
options := copy.Options{
|
||||||
RemoveSignatures: opts.removeSignatures,
|
RemoveSignatures: opts.removeSignatures,
|
||||||
@ -563,8 +570,10 @@ func (opts *syncOptions) run(args []string, stdout io.Writer) error {
|
|||||||
"to": transports.ImageName(destRef),
|
"to": transports.ImageName(destRef),
|
||||||
}).Infof("Copying image tag %d/%d", counter+1, len(srcRepo.TaggedImages))
|
}).Infof("Copying image tag %d/%d", counter+1, len(srcRepo.TaggedImages))
|
||||||
|
|
||||||
|
if err = retryIfNecessary(ctx, func() error {
|
||||||
_, err = copy.Image(ctx, policyContext, destRef, ref, &options)
|
_, err = copy.Image(ctx, policyContext, destRef, ref, &options)
|
||||||
if err != nil {
|
return err
|
||||||
|
}, opts.retryOpts); err != nil {
|
||||||
return errors.Wrapf(err, "Error copying tag %q", transports.ImageName(ref))
|
return errors.Wrapf(err, "Error copying tag %q", transports.ImageName(ref))
|
||||||
}
|
}
|
||||||
imagesNumber++
|
imagesNumber++
|
||||||
|
Loading…
Reference in New Issue
Block a user