diff --git a/cli/command/stack/swarm/deploy.go b/cli/command/stack/swarm/deploy.go index d11c328f3f..df5f300026 100644 --- a/cli/command/stack/swarm/deploy.go +++ b/cli/command/stack/swarm/deploy.go @@ -25,25 +25,26 @@ const ( func RunDeploy(dockerCli command.Cli, opts options.Deploy, cfg *composetypes.Config) error { ctx := context.Background() - if err := validateResolveImageFlag(dockerCli, &opts); err != nil { + if err := validateResolveImageFlag(&opts); err != nil { return err } - - return deployCompose(ctx, dockerCli, opts, cfg) -} - -// validateResolveImageFlag validates the opts.resolveImage command line option -// and also turns image resolution off if the version is older than 1.30 -func validateResolveImageFlag(dockerCli command.Cli, opts *options.Deploy) error { - if opts.ResolveImage != ResolveImageAlways && opts.ResolveImage != ResolveImageChanged && opts.ResolveImage != ResolveImageNever { - return errors.Errorf("Invalid option %s for flag --resolve-image", opts.ResolveImage) - } // client side image resolution should not be done when the supported // server version is older than 1.30 if versions.LessThan(dockerCli.Client().ClientVersion(), "1.30") { opts.ResolveImage = ResolveImageNever } - return nil + + return deployCompose(ctx, dockerCli, opts, cfg) +} + +// validateResolveImageFlag validates the opts.resolveImage command line option +func validateResolveImageFlag(opts *options.Deploy) error { + switch opts.ResolveImage { + case ResolveImageAlways, ResolveImageChanged, ResolveImageNever: + return nil + default: + return errors.Errorf("Invalid option %s for flag --resolve-image", opts.ResolveImage) + } } // checkDaemonIsSwarmManager does an Info API call to verify that the daemon is diff --git a/cli/command/stack/swarm/deploy_composefile.go b/cli/command/stack/swarm/deploy_composefile.go index e4574fd987..125b35e285 100644 --- a/cli/command/stack/swarm/deploy_composefile.go +++ b/cli/command/stack/swarm/deploy_composefile.go @@ -192,6 +192,7 @@ func createNetworks( return nil } +// nolint: gocyclo func deployServices( ctx context.Context, dockerCli command.Cli, @@ -214,10 +215,12 @@ func deployServices( } for internalName, serviceSpec := range services { - name := namespace.Scope(internalName) + var ( + name = namespace.Scope(internalName) + image = serviceSpec.TaskTemplate.ContainerSpec.Image + encodedAuth string + ) - encodedAuth := "" - image := serviceSpec.TaskTemplate.ContainerSpec.Image if sendAuth { // Retrieve encoded auth token from the image reference encodedAuth, err = command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) @@ -231,20 +234,33 @@ func deployServices( updateOpts := types.ServiceUpdateOptions{EncodedRegistryAuth: encodedAuth} - switch { - case resolveImage == ResolveImageAlways || (resolveImage == ResolveImageChanged && image != service.Spec.Labels[convert.LabelImage]): + switch resolveImage { + case ResolveImageAlways: // image should be updated by the server using QueryRegistry updateOpts.QueryRegistry = true - case image == service.Spec.Labels[convert.LabelImage]: - // image has not changed; update the serviceSpec with the - // existing information that was set by QueryRegistry on the - // previous deploy. Otherwise this will trigger an incorrect - // service update. - serviceSpec.TaskTemplate.ContainerSpec.Image = service.Spec.TaskTemplate.ContainerSpec.Image + case ResolveImageChanged: + if image != service.Spec.Labels[convert.LabelImage] { + // Query the registry to resolve digest for the updated image + updateOpts.QueryRegistry = true + } else { + // image has not changed; update the serviceSpec with the + // existing information that was set by QueryRegistry on the + // previous deploy. Otherwise this will trigger an incorrect + // service update. + serviceSpec.TaskTemplate.ContainerSpec.Image = service.Spec.TaskTemplate.ContainerSpec.Image + } + default: + if image == service.Spec.Labels[convert.LabelImage] { + // image has not changed; update the serviceSpec with the + // existing information that was set by QueryRegistry on the + // previous deploy. Otherwise this will trigger an incorrect + // service update. + serviceSpec.TaskTemplate.ContainerSpec.Image = service.Spec.TaskTemplate.ContainerSpec.Image + } } - // Stack deploy does not have a `--force` option. Preserve existing ForceUpdate - // value so that tasks are not re-deployed if not updated. + // Stack deploy does not have a `--force` option. Preserve existing + // ForceUpdate value so that tasks are not re-deployed if not updated. // TODO move this to API client? serviceSpec.TaskTemplate.ForceUpdate = service.Spec.TaskTemplate.ForceUpdate