Browse code

PR feedback

improve help text for service update remove flags
implement proper merge update of placement flag
more code re-use in update functions using a toRemove set.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2016/06/25 00:53:49
Showing 3 changed files
... ...
@@ -493,6 +493,7 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
493 493
 
494 494
 const (
495 495
 	flagConstraint         = "constraint"
496
+	flagConstraintRemove   = "remove-constraint"
496 497
 	flagEndpointMode       = "endpoint-mode"
497 498
 	flagEnv                = "env"
498 499
 	flagEnvRemove          = "remove-env"
... ...
@@ -36,10 +36,11 @@ func newUpdateCommand(dockerCli *client.DockerCli) *cobra.Command {
36 36
 	flags.String("args", "", "Service command args")
37 37
 	addServiceFlags(cmd, opts)
38 38
 	flags.StringSlice(flagEnvRemove, []string{}, "Remove an environment variable")
39
-	flags.StringSlice(flagLabelRemove, []string{}, "The key of a label to remove")
40
-	flags.StringSlice(flagMountRemove, []string{}, "The mount target for a mount to remove")
41
-	flags.StringSlice(flagPublishRemove, []string{}, "The target port to remove")
42
-	flags.StringSlice(flagNetworkRemove, []string{}, "The name of a network to remove")
39
+	flags.StringSlice(flagLabelRemove, []string{}, "Remove a label by its key")
40
+	flags.StringSlice(flagMountRemove, []string{}, "Remove a mount by its target path")
41
+	flags.StringSlice(flagPublishRemove, []string{}, "Remove a published port by its target port")
42
+	flags.StringSlice(flagNetworkRemove, []string{}, "Remove a network by name")
43
+	flags.StringSlice(flagConstraintRemove, []string{}, "Remove a constraint")
43 44
 	return cmd
44 45
 }
45 46
 
... ...
@@ -176,8 +177,10 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
176 176
 	}
177 177
 
178 178
 	if flags.Changed(flagConstraint) {
179
-		task.Placement = &swarm.Placement{}
180
-		updateSlice(flagConstraint, &task.Placement.Constraints)
179
+		if task.Placement == nil {
180
+			task.Placement = &swarm.Placement{}
181
+		}
182
+		updatePlacement(flags, task.Placement)
181 183
 	}
182 184
 
183 185
 	if err := updateReplicas(flags, &spec.Mode); err != nil {
... ...
@@ -227,6 +230,19 @@ func anyChanged(flags *pflag.FlagSet, fields ...string) bool {
227 227
 	return false
228 228
 }
229 229
 
230
+func updatePlacement(flags *pflag.FlagSet, placement *swarm.Placement) {
231
+	field, _ := flags.GetStringSlice(flagConstraint)
232
+	constraints := &placement.Constraints
233
+	placement.Constraints = append(placement.Constraints, field...)
234
+
235
+	toRemove := buildToRemoveSet(flags, flagConstraintRemove)
236
+	for i, constraint := range placement.Constraints {
237
+		if _, exists := toRemove[constraint]; exists {
238
+			*constraints = append((*constraints)[:i], (*constraints)[i+1:]...)
239
+		}
240
+	}
241
+}
242
+
230 243
 func updateLabels(flags *pflag.FlagSet, field *map[string]string) {
231 244
 	if flags.Changed(flagLabel) {
232 245
 		if field == nil {
... ...
@@ -252,15 +268,11 @@ func updateEnvironment(flags *pflag.FlagSet, field *[]string) {
252 252
 		value := flags.Lookup(flagEnv).Value.(*opts.ListOpts)
253 253
 		*field = append(*field, value.GetAll()...)
254 254
 	}
255
-	if flags.Changed(flagEnvRemove) {
256
-		toRemove, _ := flags.GetStringSlice(flagEnvRemove)
257
-		for _, envRemove := range toRemove {
258
-			for i, env := range *field {
259
-				key := envKey(env)
260
-				if key == envRemove {
261
-					*field = append((*field)[:i], (*field)[i+1:]...)
262
-				}
263
-			}
255
+	toRemove := buildToRemoveSet(flags, flagEnvRemove)
256
+	for i, env := range *field {
257
+		key := envKey(env)
258
+		if _, exists := toRemove[key]; exists {
259
+			*field = append((*field)[:i], (*field)[i+1:]...)
264 260
 		}
265 261
 	}
266 262
 }
... ...
@@ -270,19 +282,30 @@ func envKey(value string) string {
270 270
 	return kv[0]
271 271
 }
272 272
 
273
+func buildToRemoveSet(flags *pflag.FlagSet, flag string) map[string]struct{} {
274
+	var empty struct{}
275
+	toRemove := make(map[string]struct{})
276
+
277
+	if !flags.Changed(flag) {
278
+		return toRemove
279
+	}
280
+
281
+	toRemoveSlice, _ := flags.GetStringSlice(flag)
282
+	for _, key := range toRemoveSlice {
283
+		toRemove[key] = empty
284
+	}
285
+	return toRemove
286
+}
287
+
273 288
 func updateMounts(flags *pflag.FlagSet, mounts *[]swarm.Mount) {
274 289
 	if flags.Changed(flagMount) {
275 290
 		values := flags.Lookup(flagMount).Value.(*MountOpt).Value()
276 291
 		*mounts = append(*mounts, values...)
277 292
 	}
278
-	if flags.Changed(flagMountRemove) {
279
-		toRemove, _ := flags.GetStringSlice(flagMountRemove)
280
-		for _, mountTarget := range toRemove {
281
-			for i, mount := range *mounts {
282
-				if mount.Target == mountTarget {
283
-					*mounts = append((*mounts)[:i], (*mounts)[i+1:]...)
284
-				}
285
-			}
293
+	toRemove := buildToRemoveSet(flags, flagMountRemove)
294
+	for i, mount := range *mounts {
295
+		if _, exists := toRemove[mount.Target]; exists {
296
+			*mounts = append((*mounts)[:i], (*mounts)[i+1:]...)
286 297
 		}
287 298
 	}
288 299
 }
... ...
@@ -318,14 +341,10 @@ func updateNetworks(flags *pflag.FlagSet, attachments *[]swarm.NetworkAttachment
318 318
 			*attachments = append(*attachments, swarm.NetworkAttachmentConfig{Target: network})
319 319
 		}
320 320
 	}
321
-	if flags.Changed(flagNetworkRemove) {
322
-		toRemove, _ := flags.GetStringSlice(flagNetworkRemove)
323
-		for _, networkTarget := range toRemove {
324
-			for i, network := range *attachments {
325
-				if network.Target == networkTarget {
326
-					*attachments = append((*attachments)[:i], (*attachments)[i+1:]...)
327
-				}
328
-			}
321
+	toRemove := buildToRemoveSet(flags, flagNetworkRemove)
322
+	for i, network := range *attachments {
323
+		if _, exists := toRemove[network.Target]; exists {
324
+			*attachments = append((*attachments)[:i], (*attachments)[i+1:]...)
329 325
 		}
330 326
 	}
331 327
 }
... ...
@@ -35,15 +35,27 @@ func TestUpdateLabels(t *testing.T) {
35 35
 	assert.Equal(t, labels["toadd"], "newlabel")
36 36
 }
37 37
 
38
+func TestUpdatePlacement(t *testing.T) {
39
+	flags := newUpdateCommand(nil).Flags()
40
+	flags.Set("constraint", "node=toadd")
41
+	flags.Set("remove-constraint", "node!=toremove")
42
+
43
+	placement := &swarm.Placement{
44
+		Constraints: []string{"node!=toremove", "container=tokeep"},
45
+	}
46
+
47
+	updatePlacement(flags, placement)
48
+	assert.Equal(t, len(placement.Constraints), 2)
49
+	assert.Equal(t, placement.Constraints[0], "container=tokeep")
50
+	assert.Equal(t, placement.Constraints[1], "node=toadd")
51
+}
52
+
38 53
 func TestUpdateEnvironment(t *testing.T) {
39 54
 	flags := newUpdateCommand(nil).Flags()
40 55
 	flags.Set("env", "toadd=newenv")
41 56
 	flags.Set("remove-env", "toremove")
42 57
 
43
-	envs := []string{
44
-		"toremove=theenvtoremove",
45
-		"tokeep=value",
46
-	}
58
+	envs := []string{"toremove=theenvtoremove", "tokeep=value"}
47 59
 
48 60
 	updateEnvironment(flags, &envs)
49 61
 	assert.Equal(t, len(envs), 2)