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>
| ... | ... |
@@ -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) |