Add support for podman push --retry --retry-delay

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2024-02-21 06:11:50 -05:00
parent e5ee0bb5f3
commit c3c0c4ab96
No known key found for this signature in database
GPG Key ID: A2DF901DABE2C028
13 changed files with 138 additions and 9 deletions

View File

@ -114,10 +114,10 @@ func pullFlags(cmd *cobra.Command) {
_ = cmd.RegisterFlagCompletionFunc(decryptionKeysFlagName, completion.AutocompleteDefault) _ = cmd.RegisterFlagCompletionFunc(decryptionKeysFlagName, completion.AutocompleteDefault)
retryFlagName := "retry" retryFlagName := "retry"
flags.Uint(retryFlagName, cli.MaxPullPushRetries, "number of times to retry in case of failure when performing pull") flags.Uint(retryFlagName, registry.RetryDefault(), "number of times to retry in case of failure when performing pull")
_ = cmd.RegisterFlagCompletionFunc(retryFlagName, completion.AutocompleteNone) _ = cmd.RegisterFlagCompletionFunc(retryFlagName, completion.AutocompleteNone)
retryDelayFlagName := "retry-delay" retryDelayFlagName := "retry-delay"
flags.String(retryDelayFlagName, cli.PullPushRetryDelay.String(), "delay between retries in case of pull failures") flags.String(retryDelayFlagName, registry.RetryDelayDefault(), "delay between retries in case of pull failures")
_ = cmd.RegisterFlagCompletionFunc(retryDelayFlagName, completion.AutocompleteNone) _ = cmd.RegisterFlagCompletionFunc(retryDelayFlagName, completion.AutocompleteNone)
if registry.IsRemote() { if registry.IsRemote() {

View File

@ -111,6 +111,13 @@ func pushFlags(cmd *cobra.Command) {
flags.BoolVarP(&pushOptions.Quiet, "quiet", "q", false, "Suppress output information when pushing images") flags.BoolVarP(&pushOptions.Quiet, "quiet", "q", false, "Suppress output information when pushing images")
flags.BoolVar(&pushOptions.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image") flags.BoolVar(&pushOptions.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image")
retryFlagName := "retry"
flags.Uint(retryFlagName, registry.RetryDefault(), "number of times to retry in case of failure when performing push")
_ = cmd.RegisterFlagCompletionFunc(retryFlagName, completion.AutocompleteNone)
retryDelayFlagName := "retry-delay"
flags.String(retryDelayFlagName, registry.RetryDelayDefault(), "delay between retries in case of push failures")
_ = cmd.RegisterFlagCompletionFunc(retryDelayFlagName, completion.AutocompleteNone)
signByFlagName := "sign-by" signByFlagName := "sign-by"
flags.StringVar(&pushOptions.SignBy, signByFlagName, "", "Add a signature at the destination using the specified key") flags.StringVar(&pushOptions.SignBy, signByFlagName, "", "Add a signature at the destination using the specified key")
_ = cmd.RegisterFlagCompletionFunc(signByFlagName, completion.AutocompleteNone) _ = cmd.RegisterFlagCompletionFunc(signByFlagName, completion.AutocompleteNone)
@ -208,6 +215,24 @@ func imagePush(cmd *cobra.Command, args []string) error {
pushOptions.OciEncryptConfig = encConfig pushOptions.OciEncryptConfig = encConfig
pushOptions.OciEncryptLayers = encLayers pushOptions.OciEncryptLayers = encLayers
if cmd.Flags().Changed("retry") {
retry, err := cmd.Flags().GetUint("retry")
if err != nil {
return err
}
pushOptions.Retry = &retry
}
if cmd.Flags().Changed("retry-delay") {
val, err := cmd.Flags().GetString("retry-delay")
if err != nil {
return err
}
pushOptions.RetryDelay = val
}
if cmd.Flags().Changed("compression-level") { if cmd.Flags().Changed("compression-level") {
val, err := cmd.Flags().GetInt("compression-level") val, err := cmd.Flags().GetInt("compression-level")
if err != nil { if err != nil {

View File

@ -166,3 +166,19 @@ func setXdgDirs() error {
} }
return nil return nil
} }
func RetryDefault() uint {
if IsRemote() {
return 0
}
return PodmanConfig().ContainersConfDefaultsRO.Engine.Retry
}
func RetryDelayDefault() string {
if IsRemote() {
return ""
}
return PodmanConfig().ContainersConfDefaultsRO.Engine.RetryDelay
}

View File

@ -1,7 +1,8 @@
####> This option file is used in: ####> This option file is used in:
####> podman build, farm build, pull ####> podman build, farm build, pull, push
####> If file is edited, make sure the changes ####> If file is edited, make sure the changes
####> are applicable to all of those. ####> are applicable to all of those.
#### **--retry-delay**=*duration* #### **--retry-delay**=*duration*
Duration of delay between retry attempts in case of failure when performing pull of images from registry. Default is **2s**. Duration of delay between retry attempts when pulling or pushing images between
the registry and local storage in case of failure. The default is to start at two seconds and then exponentially back off. The delay is used when this value is set, and no exponential back off occurs.

View File

@ -1,8 +1,8 @@
####> This option file is used in: ####> This option file is used in:
####> podman build, farm build, pull ####> podman build, farm build, pull, push
####> If file is edited, make sure the changes ####> If file is edited, make sure the changes
####> are applicable to all of those. ####> are applicable to all of those.
#### **--retry**=*attempts* #### **--retry**=*attempts*
Number of times to retry in case of failure when performing pull of Number of times to retry pulling or pushing images between the registry and
images from registry. Default is **3**. local storage in case of failure. Default is **3**.

View File

@ -84,6 +84,10 @@ When writing the output image, suppress progress output
Discard any pre-existing signatures in the image. Discard any pre-existing signatures in the image.
@@option retry
@@option retry-delay
#### **--sign-by**=*key* #### **--sign-by**=*key*
Add a “simple signing” signature at the destination using the specified key. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines) Add a “simple signing” signature at the destination using the specified key. (This option is not available with the remote Podman client, including Mac and Windows (excluding WSL2) machines)

View File

@ -32,6 +32,8 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
Destination string `schema:"destination"` Destination string `schema:"destination"`
Format string `schema:"format"` Format string `schema:"format"`
RemoveSignatures bool `schema:"removeSignatures"` RemoveSignatures bool `schema:"removeSignatures"`
Retry uint `schema:"retry"`
RetryDelay string `schema:"retryDelay"`
TLSVerify bool `schema:"tlsVerify"` TLSVerify bool `schema:"tlsVerify"`
Quiet bool `schema:"quiet"` Quiet bool `schema:"quiet"`
}{ }{
@ -83,9 +85,14 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
Password: password, Password: password,
Quiet: query.Quiet, Quiet: query.Quiet,
RemoveSignatures: query.RemoveSignatures, RemoveSignatures: query.RemoveSignatures,
RetryDelay: query.RetryDelay,
Username: username, Username: username,
} }
if _, found := r.URL.Query()["retry"]; found {
options.Retry = &query.Retry
}
if _, found := r.URL.Query()["compressionFormat"]; found { if _, found := r.URL.Query()["compressionFormat"]; found {
if _, foundForceCompression := r.URL.Query()["forceCompressionFormat"]; !foundForceCompression { if _, foundForceCompression := r.URL.Query()["forceCompressionFormat"]; !foundForceCompression {
// If `compressionFormat` is set and no value for `forceCompressionFormat` // If `compressionFormat` is set and no value for `forceCompressionFormat`

View File

@ -162,6 +162,10 @@ type PushOptions struct {
SkipTLSVerify *bool `schema:"-"` SkipTLSVerify *bool `schema:"-"`
// RemoveSignatures Discard any pre-existing signatures in the image. // RemoveSignatures Discard any pre-existing signatures in the image.
RemoveSignatures *bool RemoveSignatures *bool
// Retry number of times to retry push in case of failure
Retry *uint
// RetryDelay between retries in case of push failures
RetryDelay *string
// Username for authenticating against the registry. // Username for authenticating against the registry.
Username *string `schema:"-"` Username *string `schema:"-"`
// Quiet can be specified to suppress progress when pushing. // Quiet can be specified to suppress progress when pushing.

View File

@ -198,6 +198,36 @@ func (o *PushOptions) GetRemoveSignatures() bool {
return *o.RemoveSignatures return *o.RemoveSignatures
} }
// WithRetry set field Retry to given value
func (o *PushOptions) WithRetry(value uint) *PushOptions {
o.Retry = &value
return o
}
// GetRetry returns value of field Retry
func (o *PushOptions) GetRetry() uint {
if o.Retry == nil {
var z uint
return z
}
return *o.Retry
}
// WithRetryDelay set field RetryDelay to given value
func (o *PushOptions) WithRetryDelay(value string) *PushOptions {
o.RetryDelay = &value
return o
}
// GetRetryDelay returns value of field RetryDelay
func (o *PushOptions) GetRetryDelay() string {
if o.RetryDelay == nil {
var z string
return z
}
return *o.RetryDelay
}
// WithUsername set field Username to given value // WithUsername set field Username to given value
func (o *PushOptions) WithUsername(value string) *PushOptions { func (o *PushOptions) WithUsername(value string) *PushOptions {
o.Username = &value o.Username = &value

View File

@ -151,6 +151,10 @@ type ImagePushOptions struct {
// RemoveSignatures, discard any pre-existing signatures in the image. // RemoveSignatures, discard any pre-existing signatures in the image.
// Ignored for remote calls. // Ignored for remote calls.
RemoveSignatures bool RemoveSignatures bool
// Retry number of times to retry push in case of failure
Retry *uint
// RetryDelay between retries in case of push failures
RetryDelay string
// SignaturePolicy to use when pulling. Ignored for remote calls. // SignaturePolicy to use when pulling. Ignored for remote calls.
SignaturePolicy string SignaturePolicy string
// Signers, if non-empty, asks for signatures to be added during the copy // Signers, if non-empty, asks for signatures to be added during the copy

View File

@ -254,8 +254,8 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify
pullOptions.Writer = options.Writer pullOptions.Writer = options.Writer
pullOptions.OciDecryptConfig = options.OciDecryptConfig pullOptions.OciDecryptConfig = options.OciDecryptConfig
pullOptions.MaxRetries = options.Retry pullOptions.MaxRetries = options.Retry
if options.RetryDelay != "" { if options.RetryDelay != "" {
duration, err := time.ParseDuration(options.RetryDelay) duration, err := time.ParseDuration(options.RetryDelay)
if err != nil { if err != nil {
@ -343,6 +343,14 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
pushOptions.OciEncryptLayers = options.OciEncryptLayers pushOptions.OciEncryptLayers = options.OciEncryptLayers
pushOptions.CompressionLevel = options.CompressionLevel pushOptions.CompressionLevel = options.CompressionLevel
pushOptions.ForceCompressionFormat = options.ForceCompressionFormat pushOptions.ForceCompressionFormat = options.ForceCompressionFormat
pushOptions.MaxRetries = options.Retry
if options.RetryDelay != "" {
duration, err := time.ParseDuration(options.RetryDelay)
if err != nil {
return nil, err
}
pushOptions.RetryDelay = &duration
}
compressionFormat := options.CompressionFormat compressionFormat := options.CompressionFormat
if compressionFormat == "" { if compressionFormat == "" {

View File

@ -273,6 +273,12 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
options.WithSkipTLSVerify(false) options.WithSkipTLSVerify(false)
} }
} }
if opts.Retry != nil {
options.WithRetry(*opts.Retry)
}
if opts.RetryDelay != "" {
options.WithRetryDelay(opts.RetryDelay)
}
if err := images.Push(ir.ClientCtx, source, destination, options); err != nil { if err := images.Push(ir.ClientCtx, source, destination, options); err != nil {
return nil, err return nil, err
} }

View File

@ -327,7 +327,7 @@ function _test_skopeo_credential_sharing() {
} }
@test "podman images with retry" { @test "podman pull images with retry" {
run_podman pull -q --retry 4 --retry-delay "10s" $IMAGE run_podman pull -q --retry 4 --retry-delay "10s" $IMAGE
run_podman 125 pull -q --retry 4 --retry-delay "bogus" $IMAGE run_podman 125 pull -q --retry 4 --retry-delay "bogus" $IMAGE
is "$output" 'Error: time: invalid duration "bogus"' "bad retry-delay" is "$output" 'Error: time: invalid duration "bogus"' "bad retry-delay"
@ -367,6 +367,30 @@ function _test_skopeo_credential_sharing() {
run_podman rmi $image1 run_podman rmi $image1
} }
@test "podman containers.conf retry" {
skip_if_remote "containers.conf settings not set for remote connections"
run_podman pull --help
assert "$output" =~ "--retry .*performing pull \(default 3\)"
run_podman push --help
assert "$output" =~ "--retry .*performing push \(default 3\)"
containersConf=$PODMAN_TMPDIR/containers.conf
cat >$containersConf <<EOF
[engine]
retry=10
retry_delay="5s"
EOF
CONTAINERS_CONF="$containersConf" run_podman pull --help
assert "$output" =~ "--retry .*performing pull \(default 10\)"
assert "$output" =~ "--retry-delay .*pull failures \(default \"5s\"\)"
CONTAINERS_CONF="$containersConf" run_podman push --help
assert "$output" =~ "--retry .*performing push \(default 10\)"
assert "$output" =~ "--retry-delay .*push failures \(default \"5s\"\)"
}
# END cooperation with skopeo # END cooperation with skopeo
# END actual tests # END actual tests
############################################################################### ###############################################################################