Browse Source

Adding a flag to specify sending of registry auth

Signed-off-by: Nishant Totla <nishanttotla@gmail.com>
Nishant Totla 9 năm trước cách đây
mục cha
commit
538bac39d7

+ 3 - 3
api/client/registry.go

@@ -149,8 +149,8 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is
 	return authconfig, nil
 }
 
-// ResolveAuthConfigFromImage retrieves that AuthConfig using the image string
-func (cli *DockerCli) ResolveAuthConfigFromImage(ctx context.Context, image string) (types.AuthConfig, error) {
+// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
+func (cli *DockerCli) resolveAuthConfigFromImage(ctx context.Context, image string) (types.AuthConfig, error) {
 	registryRef, err := reference.ParseNamed(image)
 	if err != nil {
 		return types.AuthConfig{}, err
@@ -166,7 +166,7 @@ func (cli *DockerCli) ResolveAuthConfigFromImage(ctx context.Context, image stri
 // RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image
 func (cli *DockerCli) RetrieveAuthTokenFromImage(ctx context.Context, image string) (string, error) {
 	// Retrieve encoded auth token from the image reference
-	authConfig, err := cli.ResolveAuthConfigFromImage(ctx, image)
+	authConfig, err := cli.resolveAuthConfigFromImage(ctx, image)
 	if err != nil {
 		return "", err
 	}

+ 9 - 7
api/client/service/create.go

@@ -33,6 +33,7 @@ func newCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
 
 func runCreate(dockerCli *client.DockerCli, opts *serviceOptions) error {
 	apiClient := dockerCli.Client()
+	headers := map[string][]string{}
 
 	service, err := opts.ToService()
 	if err != nil {
@@ -40,14 +41,15 @@ func runCreate(dockerCli *client.DockerCli, opts *serviceOptions) error {
 	}
 
 	ctx := context.Background()
-	// Retrieve encoded auth token from the image reference
-	encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image)
-	if err != nil {
-		return err
-	}
 
-	headers := map[string][]string{
-		"X-Registry-Auth": {encodedAuth},
+	// only send auth if flag was set
+	if opts.registryAuth {
+		// Retrieve encoded auth token from the image reference
+		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image)
+		if err != nil {
+			return err
+		}
+		headers["X-Registry-Auth"] = []string{encodedAuth}
 	}
 
 	response, err := apiClient.ServiceCreate(ctx, service, headers)

+ 6 - 1
api/client/service/opts.go

@@ -373,6 +373,8 @@ type serviceOptions struct {
 	update        updateOptions
 	networks      []string
 	endpoint      endpointOptions
+
+	registryAuth bool
 }
 
 func newServiceOptions() *serviceOptions {
@@ -436,7 +438,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
 	return service, nil
 }
 
-// addServiceFlags adds all flags that are common to both `create` and `update.
+// addServiceFlags adds all flags that are common to both `create` and `update`.
 // Any flags that are not common are added separately in the individual command
 func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
 	flags := cmd.Flags()
@@ -469,6 +471,8 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
 	flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments")
 	flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "", "Endpoint mode(Valid values: vip, dnsrr)")
 	flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port")
+
+	flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to Swarm agents")
 }
 
 const (
@@ -493,4 +497,5 @@ const (
 	flagUpdateDelay        = "update-delay"
 	flagUpdateParallelism  = "update-parallelism"
 	flagUser               = "user"
+	flagRegistryAuth       = "registry-auth"
 )

+ 1 - 13
api/client/service/scale.go

@@ -60,7 +60,6 @@ func runScale(dockerCli *client.DockerCli, args []string) error {
 func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string) error {
 	client := dockerCli.Client()
 	ctx := context.Background()
-	headers := map[string][]string{}
 
 	service, _, err := client.ServiceInspectWithRaw(ctx, serviceID)
 
@@ -68,17 +67,6 @@ func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string
 		return err
 	}
 
-	// TODO(nishanttotla): Is this the best way to get the image?
-	image := service.Spec.TaskTemplate.ContainerSpec.Image
-	if image != "" {
-		// Retrieve encoded auth token from the image reference
-		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
-		if err != nil {
-			return err
-		}
-		headers["X-Registry-Auth"] = []string{encodedAuth}
-	}
-
 	serviceMode := &service.Spec.Mode
 	if serviceMode.Replicated == nil {
 		return fmt.Errorf("scale can only be used with replicated mode")
@@ -89,7 +77,7 @@ func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string
 	}
 	serviceMode.Replicated.Replicas = &uintScale
 
-	err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, headers)
+	err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, nil)
 	if err != nil {
 		return err
 	}

+ 14 - 13
api/client/service/update.go

@@ -41,30 +41,31 @@ func runUpdate(dockerCli *client.DockerCli, flags *pflag.FlagSet, serviceID stri
 	ctx := context.Background()
 	headers := map[string][]string{}
 
-	// TODO(nishanttotla): Is this the best way to get the new image?
-	image, err := flags.GetString("image")
+	service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID)
 	if err != nil {
 		return err
 	}
-	if image != "" {
-		// Retrieve encoded auth token from the image reference
-		// only do this if a new image has been provided as part of the udpate
-		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
-		if err != nil {
-			return err
-		}
-		headers["X-Registry-Auth"] = []string{encodedAuth}
-	}
 
-	service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID)
+	err = updateService(&service.Spec, flags)
 	if err != nil {
 		return err
 	}
 
-	err = updateService(&service.Spec, flags)
+	// only send auth if flag was set
+	sendAuth, err := flags.GetBool(flagRegistryAuth)
 	if err != nil {
 		return err
 	}
+	if sendAuth {
+		// Retrieve encoded auth token from the image reference
+		// This would be the old image if it didn't change in this update
+		image := service.Spec.TaskTemplate.ContainerSpec.Image
+		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
+		if err != nil {
+			return err
+		}
+		headers["X-Registry-Auth"] = []string{encodedAuth}
+	}
 
 	err = apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, headers)
 	if err != nil {

+ 2 - 0
api/server/router/swarm/cluster_routes.go

@@ -107,6 +107,7 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
 		return err
 	}
 
+	// Get returns "" if the header does not exist
 	encodedAuth := r.Header.Get("X-Registry-Auth")
 
 	id, err := sr.backend.CreateService(service, encodedAuth)
@@ -132,6 +133,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
 		return fmt.Errorf("Invalid service version '%s': %s", rawVersion, err.Error())
 	}
 
+	// Get returns "" if the header does not exist
 	encodedAuth := r.Header.Get("X-Registry-Auth")
 
 	if err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth); err != nil {

+ 22 - 2
daemon/cluster/cluster.go

@@ -689,7 +689,11 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string
 	}
 
 	if encodedAuth != "" {
-		serviceSpec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
+		ctnr := serviceSpec.Task.GetContainer()
+		if ctnr == nil {
+			return "", fmt.Errorf("service does not use container tasks")
+		}
+		ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
 	}
 
 	r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
@@ -731,7 +735,23 @@ func (c *Cluster) UpdateService(serviceID string, version uint64, spec types.Ser
 	}
 
 	if encodedAuth != "" {
-		serviceSpec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
+		ctnr := serviceSpec.Task.GetContainer()
+		if ctnr == nil {
+			return fmt.Errorf("service does not use container tasks")
+		}
+		ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
+	} else {
+		// this is needed because if the encodedAuth isn't being updated then we
+		// shouldn't lose it, and continue to use the one that was already present
+		currentService, err := getService(c.getRequestContext(), c.client, serviceID)
+		if err != nil {
+			return err
+		}
+		ctnr := currentService.Spec.Task.GetContainer()
+		if ctnr == nil {
+			return fmt.Errorf("service does not use container tasks")
+		}
+		serviceSpec.Task.GetContainer().PullOptions = ctnr.PullOptions
 	}
 
 	_, err = c.client.UpdateService(