Browse code

Adding a flag to specify sending of registry auth

Signed-off-by: Nishant Totla <nishanttotla@gmail.com>
(cherry picked from commit 538bac39d7fe93562922b89e9a294096be48fb59)

Nishant Totla authored on 2016/06/30 09:08:00
Showing 7 changed files
... ...
@@ -149,8 +149,8 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is
149 149
 	return authconfig, nil
150 150
 }
151 151
 
152
-// ResolveAuthConfigFromImage retrieves that AuthConfig using the image string
153
-func (cli *DockerCli) ResolveAuthConfigFromImage(ctx context.Context, image string) (types.AuthConfig, error) {
152
+// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
153
+func (cli *DockerCli) resolveAuthConfigFromImage(ctx context.Context, image string) (types.AuthConfig, error) {
154 154
 	registryRef, err := reference.ParseNamed(image)
155 155
 	if err != nil {
156 156
 		return types.AuthConfig{}, err
... ...
@@ -166,7 +166,7 @@ func (cli *DockerCli) ResolveAuthConfigFromImage(ctx context.Context, image stri
166 166
 // RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image
167 167
 func (cli *DockerCli) RetrieveAuthTokenFromImage(ctx context.Context, image string) (string, error) {
168 168
 	// Retrieve encoded auth token from the image reference
169
-	authConfig, err := cli.ResolveAuthConfigFromImage(ctx, image)
169
+	authConfig, err := cli.resolveAuthConfigFromImage(ctx, image)
170 170
 	if err != nil {
171 171
 		return "", err
172 172
 	}
... ...
@@ -33,6 +33,7 @@ func newCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
33 33
 
34 34
 func runCreate(dockerCli *client.DockerCli, opts *serviceOptions) error {
35 35
 	apiClient := dockerCli.Client()
36
+	headers := map[string][]string{}
36 37
 
37 38
 	service, err := opts.ToService()
38 39
 	if err != nil {
... ...
@@ -40,14 +41,15 @@ func runCreate(dockerCli *client.DockerCli, opts *serviceOptions) error {
40 40
 	}
41 41
 
42 42
 	ctx := context.Background()
43
-	// Retrieve encoded auth token from the image reference
44
-	encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image)
45
-	if err != nil {
46
-		return err
47
-	}
48 43
 
49
-	headers := map[string][]string{
50
-		"X-Registry-Auth": {encodedAuth},
44
+	// only send auth if flag was set
45
+	if opts.registryAuth {
46
+		// Retrieve encoded auth token from the image reference
47
+		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image)
48
+		if err != nil {
49
+			return err
50
+		}
51
+		headers["X-Registry-Auth"] = []string{encodedAuth}
51 52
 	}
52 53
 
53 54
 	response, err := apiClient.ServiceCreate(ctx, service, headers)
... ...
@@ -373,6 +373,8 @@ type serviceOptions struct {
373 373
 	update        updateOptions
374 374
 	networks      []string
375 375
 	endpoint      endpointOptions
376
+
377
+	registryAuth bool
376 378
 }
377 379
 
378 380
 func newServiceOptions() *serviceOptions {
... ...
@@ -436,7 +438,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
436 436
 	return service, nil
437 437
 }
438 438
 
439
-// addServiceFlags adds all flags that are common to both `create` and `update.
439
+// addServiceFlags adds all flags that are common to both `create` and `update`.
440 440
 // Any flags that are not common are added separately in the individual command
441 441
 func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
442 442
 	flags := cmd.Flags()
... ...
@@ -469,6 +471,8 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
469 469
 	flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments")
470 470
 	flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "", "Endpoint mode(Valid values: vip, dnsrr)")
471 471
 	flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port")
472
+
473
+	flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to Swarm agents")
472 474
 }
473 475
 
474 476
 const (
... ...
@@ -493,4 +497,5 @@ const (
493 493
 	flagUpdateDelay        = "update-delay"
494 494
 	flagUpdateParallelism  = "update-parallelism"
495 495
 	flagUser               = "user"
496
+	flagRegistryAuth       = "registry-auth"
496 497
 )
... ...
@@ -60,7 +60,6 @@ func runScale(dockerCli *client.DockerCli, args []string) error {
60 60
 func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string) error {
61 61
 	client := dockerCli.Client()
62 62
 	ctx := context.Background()
63
-	headers := map[string][]string{}
64 63
 
65 64
 	service, _, err := client.ServiceInspectWithRaw(ctx, serviceID)
66 65
 
... ...
@@ -68,17 +67,6 @@ func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string
68 68
 		return err
69 69
 	}
70 70
 
71
-	// TODO(nishanttotla): Is this the best way to get the image?
72
-	image := service.Spec.TaskTemplate.ContainerSpec.Image
73
-	if image != "" {
74
-		// Retrieve encoded auth token from the image reference
75
-		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
76
-		if err != nil {
77
-			return err
78
-		}
79
-		headers["X-Registry-Auth"] = []string{encodedAuth}
80
-	}
81
-
82 71
 	serviceMode := &service.Spec.Mode
83 72
 	if serviceMode.Replicated == nil {
84 73
 		return fmt.Errorf("scale can only be used with replicated mode")
... ...
@@ -89,7 +77,7 @@ func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string
89 89
 	}
90 90
 	serviceMode.Replicated.Replicas = &uintScale
91 91
 
92
-	err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, headers)
92
+	err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, nil)
93 93
 	if err != nil {
94 94
 		return err
95 95
 	}
... ...
@@ -41,30 +41,31 @@ func runUpdate(dockerCli *client.DockerCli, flags *pflag.FlagSet, serviceID stri
41 41
 	ctx := context.Background()
42 42
 	headers := map[string][]string{}
43 43
 
44
-	// TODO(nishanttotla): Is this the best way to get the new image?
45
-	image, err := flags.GetString("image")
44
+	service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID)
46 45
 	if err != nil {
47 46
 		return err
48 47
 	}
49
-	if image != "" {
50
-		// Retrieve encoded auth token from the image reference
51
-		// only do this if a new image has been provided as part of the udpate
52
-		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
53
-		if err != nil {
54
-			return err
55
-		}
56
-		headers["X-Registry-Auth"] = []string{encodedAuth}
57
-	}
58 48
 
59
-	service, _, err := apiClient.ServiceInspectWithRaw(ctx, serviceID)
49
+	err = updateService(flags, &service.Spec)
60 50
 	if err != nil {
61 51
 		return err
62 52
 	}
63 53
 
64
-	err = updateService(flags, &service.Spec)
54
+	// only send auth if flag was set
55
+	sendAuth, err := flags.GetBool(flagRegistryAuth)
65 56
 	if err != nil {
66 57
 		return err
67 58
 	}
59
+	if sendAuth {
60
+		// Retrieve encoded auth token from the image reference
61
+		// This would be the old image if it didn't change in this update
62
+		image := service.Spec.TaskTemplate.ContainerSpec.Image
63
+		encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image)
64
+		if err != nil {
65
+			return err
66
+		}
67
+		headers["X-Registry-Auth"] = []string{encodedAuth}
68
+	}
68 69
 
69 70
 	err = apiClient.ServiceUpdate(ctx, service.ID, service.Version, service.Spec, headers)
70 71
 	if err != nil {
... ...
@@ -107,6 +107,7 @@ func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter,
107 107
 		return err
108 108
 	}
109 109
 
110
+	// Get returns "" if the header does not exist
110 111
 	encodedAuth := r.Header.Get("X-Registry-Auth")
111 112
 
112 113
 	id, err := sr.backend.CreateService(service, encodedAuth)
... ...
@@ -132,6 +133,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter,
132 132
 		return fmt.Errorf("Invalid service version '%s': %s", rawVersion, err.Error())
133 133
 	}
134 134
 
135
+	// Get returns "" if the header does not exist
135 136
 	encodedAuth := r.Header.Get("X-Registry-Auth")
136 137
 
137 138
 	if err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth); err != nil {
... ...
@@ -684,7 +684,11 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string
684 684
 	}
685 685
 
686 686
 	if encodedAuth != "" {
687
-		serviceSpec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
687
+		ctnr := serviceSpec.Task.GetContainer()
688
+		if ctnr == nil {
689
+			return "", fmt.Errorf("service does not use container tasks")
690
+		}
691
+		ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
688 692
 	}
689 693
 
690 694
 	r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
... ...
@@ -726,7 +730,23 @@ func (c *Cluster) UpdateService(serviceID string, version uint64, spec types.Ser
726 726
 	}
727 727
 
728 728
 	if encodedAuth != "" {
729
-		serviceSpec.Task.Runtime.(*swarmapi.TaskSpec_Container).Container.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
729
+		ctnr := serviceSpec.Task.GetContainer()
730
+		if ctnr == nil {
731
+			return fmt.Errorf("service does not use container tasks")
732
+		}
733
+		ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
734
+	} else {
735
+		// this is needed because if the encodedAuth isn't being updated then we
736
+		// shouldn't lose it, and continue to use the one that was already present
737
+		currentService, err := getService(c.getRequestContext(), c.client, serviceID)
738
+		if err != nil {
739
+			return err
740
+		}
741
+		ctnr := currentService.Spec.Task.GetContainer()
742
+		if ctnr == nil {
743
+			return fmt.Errorf("service does not use container tasks")
744
+		}
745
+		serviceSpec.Task.GetContainer().PullOptions = ctnr.PullOptions
730 746
 	}
731 747
 
732 748
 	_, err = c.client.UpdateService(