Browse code

Fix multi-remove during service update.

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

Daniel Nephin authored on 2016/07/14 04:59:23
Showing 2 changed files
... ...
@@ -103,13 +103,6 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
103 103
 		}
104 104
 	}
105 105
 
106
-	updateListOpts := func(flag string, field *[]string) {
107
-		if flags.Changed(flag) {
108
-			value := flags.Lookup(flag).Value.(*opts.ListOpts)
109
-			*field = value.GetAll()
110
-		}
111
-	}
112
-
113 106
 	updateInt64Value := func(flag string, field *int64) {
114 107
 		if flags.Changed(flag) {
115 108
 			*field = flags.Lookup(flag).Value.(int64Value).Value()
... ...
@@ -243,15 +236,10 @@ func anyChanged(flags *pflag.FlagSet, fields ...string) bool {
243 243
 
244 244
 func updatePlacement(flags *pflag.FlagSet, placement *swarm.Placement) {
245 245
 	field, _ := flags.GetStringSlice(flagConstraintAdd)
246
-	constraints := &placement.Constraints
247 246
 	placement.Constraints = append(placement.Constraints, field...)
248 247
 
249 248
 	toRemove := buildToRemoveSet(flags, flagConstraintRemove)
250
-	for i, constraint := range placement.Constraints {
251
-		if _, exists := toRemove[constraint]; exists {
252
-			*constraints = append((*constraints)[:i], (*constraints)[i+1:]...)
253
-		}
254
-	}
249
+	placement.Constraints = removeItems(placement.Constraints, toRemove, itemKey)
255 250
 }
256 251
 
257 252
 func updateLabels(flags *pflag.FlagSet, field *map[string]string) {
... ...
@@ -280,12 +268,7 @@ func updateEnvironment(flags *pflag.FlagSet, field *[]string) {
280 280
 		*field = append(*field, value.GetAll()...)
281 281
 	}
282 282
 	toRemove := buildToRemoveSet(flags, flagEnvRemove)
283
-	for i, env := range *field {
284
-		key := envKey(env)
285
-		if _, exists := toRemove[key]; exists {
286
-			*field = append((*field)[:i], (*field)[i+1:]...)
287
-		}
288
-	}
283
+	*field = removeItems(*field, toRemove, envKey)
289 284
 }
290 285
 
291 286
 func envKey(value string) string {
... ...
@@ -293,6 +276,10 @@ func envKey(value string) string {
293 293
 	return kv[0]
294 294
 }
295 295
 
296
+func itemKey(value string) string {
297
+	return value
298
+}
299
+
296 300
 func buildToRemoveSet(flags *pflag.FlagSet, flag string) map[string]struct{} {
297 301
 	var empty struct{}
298 302
 	toRemove := make(map[string]struct{})
... ...
@@ -308,17 +295,34 @@ func buildToRemoveSet(flags *pflag.FlagSet, flag string) map[string]struct{} {
308 308
 	return toRemove
309 309
 }
310 310
 
311
+func removeItems(
312
+	seq []string,
313
+	toRemove map[string]struct{},
314
+	keyFunc func(string) string,
315
+) []string {
316
+	newSeq := []string{}
317
+	for _, item := range seq {
318
+		if _, exists := toRemove[keyFunc(item)]; !exists {
319
+			newSeq = append(newSeq, item)
320
+		}
321
+	}
322
+	return newSeq
323
+}
324
+
311 325
 func updateMounts(flags *pflag.FlagSet, mounts *[]swarm.Mount) {
312 326
 	if flags.Changed(flagMountAdd) {
313 327
 		values := flags.Lookup(flagMountAdd).Value.(*MountOpt).Value()
314 328
 		*mounts = append(*mounts, values...)
315 329
 	}
316 330
 	toRemove := buildToRemoveSet(flags, flagMountRemove)
317
-	for i, mount := range *mounts {
318
-		if _, exists := toRemove[mount.Target]; exists {
319
-			*mounts = append((*mounts)[:i], (*mounts)[i+1:]...)
331
+
332
+	newMounts := []swarm.Mount{}
333
+	for _, mount := range *mounts {
334
+		if _, exists := toRemove[mount.Target]; !exists {
335
+			newMounts = append(newMounts, mount)
320 336
 		}
321 337
 	}
338
+	*mounts = newMounts
322 339
 }
323 340
 
324 341
 func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) {
... ...
@@ -331,19 +335,27 @@ func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) {
331 331
 		}
332 332
 	}
333 333
 
334
-	if flags.Changed(flagPublishRemove) {
335
-		toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll()
334
+	if !flags.Changed(flagPublishRemove) {
335
+		return
336
+	}
337
+	toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll()
338
+	newPorts := []swarm.PortConfig{}
339
+portLoop:
340
+	for _, port := range *portConfig {
336 341
 		for _, rawTargetPort := range toRemove {
337 342
 			targetPort := nat.Port(rawTargetPort)
338
-			for i, port := range *portConfig {
339
-				if string(port.Protocol) == targetPort.Proto() &&
340
-					port.TargetPort == uint32(targetPort.Int()) {
341
-					*portConfig = append((*portConfig)[:i], (*portConfig)[i+1:]...)
342
-					break
343
-				}
343
+			if equalPort(targetPort, port) {
344
+				continue portLoop
344 345
 			}
345 346
 		}
347
+		newPorts = append(newPorts, port)
346 348
 	}
349
+	*portConfig = newPorts
350
+}
351
+
352
+func equalPort(targetPort nat.Port, port swarm.PortConfig) bool {
353
+	return (string(port.Protocol) == targetPort.Proto() &&
354
+		port.TargetPort == uint32(targetPort.Int()))
347 355
 }
348 356
 
349 357
 func updateNetworks(flags *pflag.FlagSet, attachments *[]swarm.NetworkAttachmentConfig) {
... ...
@@ -354,11 +366,13 @@ func updateNetworks(flags *pflag.FlagSet, attachments *[]swarm.NetworkAttachment
354 354
 		}
355 355
 	}
356 356
 	toRemove := buildToRemoveSet(flags, flagNetworkRemove)
357
-	for i, network := range *attachments {
358
-		if _, exists := toRemove[network.Target]; exists {
359
-			*attachments = append((*attachments)[:i], (*attachments)[i+1:]...)
357
+	newNetworks := []swarm.NetworkAttachmentConfig{}
358
+	for _, network := range *attachments {
359
+		if _, exists := toRemove[network.Target]; !exists {
360
+			newNetworks = append(newNetworks, network)
360 361
 		}
361 362
 	}
363
+	*attachments = newNetworks
362 364
 }
363 365
 
364 366
 func updateReplicas(flags *pflag.FlagSet, serviceMode *swarm.ServiceMode) error {
... ...
@@ -35,6 +35,15 @@ func TestUpdateLabels(t *testing.T) {
35 35
 	assert.Equal(t, labels["toadd"], "newlabel")
36 36
 }
37 37
 
38
+func TestUpdateLabelsRemoveALabelThatDoesNotExist(t *testing.T) {
39
+	flags := newUpdateCommand(nil).Flags()
40
+	flags.Set("label-rm", "dne")
41
+
42
+	labels := map[string]string{"foo": "theoldlabel"}
43
+	updateLabels(flags, &labels)
44
+	assert.Equal(t, len(labels), 1)
45
+}
46
+
38 47
 func TestUpdatePlacement(t *testing.T) {
39 48
 	flags := newUpdateCommand(nil).Flags()
40 49
 	flags.Set("constraint-add", "node=toadd")
... ...
@@ -63,6 +72,18 @@ func TestUpdateEnvironment(t *testing.T) {
63 63
 	assert.Equal(t, envs[1], "toadd=newenv")
64 64
 }
65 65
 
66
+func TestUpdateEnvironmentWithDuplicateValues(t *testing.T) {
67
+	flags := newUpdateCommand(nil).Flags()
68
+	flags.Set("env-add", "foo=newenv")
69
+	flags.Set("env-add", "foo=dupe")
70
+	flags.Set("env-rm", "foo")
71
+
72
+	envs := []string{"foo=value"}
73
+
74
+	updateEnvironment(flags, &envs)
75
+	assert.Equal(t, len(envs), 0)
76
+}
77
+
66 78
 func TestUpdateMounts(t *testing.T) {
67 79
 	flags := newUpdateCommand(nil).Flags()
68 80
 	flags.Set("mount-add", "type=volume,target=/toadd")