github.com/kobeld/docker@v1.12.0-rc1/api/client/service/update.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "time" 6 7 "golang.org/x/net/context" 8 9 "github.com/docker/docker/api/client" 10 "github.com/docker/docker/cli" 11 "github.com/docker/docker/opts" 12 runconfigopts "github.com/docker/docker/runconfig/opts" 13 "github.com/docker/engine-api/types/swarm" 14 "github.com/docker/go-connections/nat" 15 "github.com/spf13/cobra" 16 "github.com/spf13/pflag" 17 ) 18 19 func newUpdateCommand(dockerCli *client.DockerCli) *cobra.Command { 20 opts := newServiceOptions() 21 var flags *pflag.FlagSet 22 23 cmd := &cobra.Command{ 24 Use: "update [OPTIONS] SERVICE", 25 Short: "Update a service", 26 Args: cli.ExactArgs(1), 27 RunE: func(cmd *cobra.Command, args []string) error { 28 return runUpdate(dockerCli, flags, args[0]) 29 }, 30 } 31 32 flags = cmd.Flags() 33 flags.String("image", "", "Service image tag") 34 flags.StringSlice("command", []string{}, "Service command") 35 flags.StringSlice("arg", []string{}, "Service command args") 36 addServiceFlags(cmd, opts) 37 return cmd 38 } 39 40 func runUpdate(dockerCli *client.DockerCli, flags *pflag.FlagSet, serviceID string) error { 41 client := dockerCli.Client() 42 ctx := context.Background() 43 44 service, err := client.ServiceInspect(ctx, serviceID) 45 if err != nil { 46 return err 47 } 48 49 err = mergeService(&service.Spec, flags) 50 if err != nil { 51 return err 52 } 53 err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec) 54 if err != nil { 55 return err 56 } 57 58 fmt.Fprintf(dockerCli.Out(), "%s\n", serviceID) 59 return nil 60 } 61 62 func mergeService(spec *swarm.ServiceSpec, flags *pflag.FlagSet) error { 63 64 mergeString := func(flag string, field *string) { 65 if flags.Changed(flag) { 66 *field, _ = flags.GetString(flag) 67 } 68 } 69 70 mergeListOpts := func(flag string, field *[]string) { 71 if flags.Changed(flag) { 72 value := flags.Lookup(flag).Value.(*opts.ListOpts) 73 *field = value.GetAll() 74 } 75 } 76 77 mergeSlice := func(flag string, field *[]string) { 78 if flags.Changed(flag) { 79 *field, _ = flags.GetStringSlice(flag) 80 } 81 } 82 83 mergeInt64Value := func(flag string, field *int64) { 84 if flags.Changed(flag) { 85 *field = flags.Lookup(flag).Value.(int64Value).Value() 86 } 87 } 88 89 mergeDuration := func(flag string, field *time.Duration) { 90 if flags.Changed(flag) { 91 *field, _ = flags.GetDuration(flag) 92 } 93 } 94 95 mergeDurationOpt := func(flag string, field *time.Duration) { 96 if flags.Changed(flag) { 97 *field = *flags.Lookup(flag).Value.(*DurationOpt).Value() 98 } 99 } 100 101 mergeUint64 := func(flag string, field *uint64) { 102 if flags.Changed(flag) { 103 *field, _ = flags.GetUint64(flag) 104 } 105 } 106 107 mergeUint64Opt := func(flag string, field *uint64) { 108 if flags.Changed(flag) { 109 *field = *flags.Lookup(flag).Value.(*Uint64Opt).Value() 110 } 111 } 112 113 cspec := &spec.TaskTemplate.ContainerSpec 114 task := &spec.TaskTemplate 115 mergeString(flagName, &spec.Name) 116 mergeLabels(flags, &spec.Labels) 117 mergeString("image", &cspec.Image) 118 mergeSlice("command", &cspec.Command) 119 mergeSlice("arg", &cspec.Command) 120 mergeListOpts("env", &cspec.Env) 121 mergeString("workdir", &cspec.Dir) 122 mergeString("user", &cspec.User) 123 mergeMounts(flags, &cspec.Mounts) 124 125 if flags.Changed(flagLimitCPU) || flags.Changed(flagLimitMemory) { 126 if task.Resources == nil { 127 task.Resources = &swarm.ResourceRequirements{} 128 } 129 task.Resources.Limits = &swarm.Resources{} 130 mergeInt64Value(flagLimitCPU, &task.Resources.Limits.NanoCPUs) 131 mergeInt64Value(flagLimitMemory, &task.Resources.Limits.MemoryBytes) 132 133 } 134 if flags.Changed(flagReserveCPU) || flags.Changed(flagReserveMemory) { 135 if task.Resources == nil { 136 task.Resources = &swarm.ResourceRequirements{} 137 } 138 task.Resources.Reservations = &swarm.Resources{} 139 mergeInt64Value(flagReserveCPU, &task.Resources.Reservations.NanoCPUs) 140 mergeInt64Value(flagReserveMemory, &task.Resources.Reservations.MemoryBytes) 141 } 142 143 mergeDurationOpt("stop-grace-period", cspec.StopGracePeriod) 144 145 if flags.Changed(flagRestartCondition) || flags.Changed(flagRestartDelay) || flags.Changed(flagRestartMaxAttempts) || flags.Changed(flagRestartWindow) { 146 if task.RestartPolicy == nil { 147 task.RestartPolicy = &swarm.RestartPolicy{} 148 } 149 150 if flags.Changed(flagRestartCondition) { 151 value, _ := flags.GetString(flagRestartCondition) 152 task.RestartPolicy.Condition = swarm.RestartPolicyCondition(value) 153 } 154 mergeDurationOpt(flagRestartDelay, task.RestartPolicy.Delay) 155 mergeUint64Opt(flagRestartMaxAttempts, task.RestartPolicy.MaxAttempts) 156 mergeDurationOpt((flagRestartWindow), task.RestartPolicy.Window) 157 } 158 159 if flags.Changed(flagConstraint) { 160 task.Placement = &swarm.Placement{} 161 mergeSlice(flagConstraint, &task.Placement.Constraints) 162 } 163 164 if err := mergeMode(flags, &spec.Mode); err != nil { 165 return err 166 } 167 168 if flags.Changed(flagUpdateParallelism) || flags.Changed(flagUpdateDelay) { 169 if spec.UpdateConfig == nil { 170 spec.UpdateConfig = &swarm.UpdateConfig{} 171 } 172 mergeUint64(flagUpdateParallelism, &spec.UpdateConfig.Parallelism) 173 mergeDuration(flagUpdateDelay, &spec.UpdateConfig.Delay) 174 } 175 176 mergeNetworks(flags, &spec.Networks) 177 if flags.Changed(flagEndpointMode) { 178 value, _ := flags.GetString(flagEndpointMode) 179 spec.EndpointSpec.Mode = swarm.ResolutionMode(value) 180 } 181 182 if flags.Changed(flagPublish) { 183 if spec.EndpointSpec == nil { 184 spec.EndpointSpec = &swarm.EndpointSpec{} 185 } 186 mergePorts(flags, &spec.EndpointSpec.Ports) 187 } 188 return nil 189 } 190 191 func mergeLabels(flags *pflag.FlagSet, field *map[string]string) { 192 if !flags.Changed(flagLabel) { 193 return 194 } 195 196 if *field == nil { 197 *field = make(map[string]string) 198 } 199 200 values := flags.Lookup(flagLabel).Value.(*opts.ListOpts).GetAll() 201 for key, value := range runconfigopts.ConvertKVStringsToMap(values) { 202 (*field)[key] = value 203 } 204 } 205 206 // TODO: should this override by destination path, or does swarm handle that? 207 func mergeMounts(flags *pflag.FlagSet, mounts *[]swarm.Mount) { 208 if !flags.Changed(flagMount) { 209 return 210 } 211 212 values := flags.Lookup(flagMount).Value.(*MountOpt).Value() 213 *mounts = append(*mounts, values...) 214 } 215 216 // TODO: should this override by name, or does swarm handle that? 217 func mergePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) { 218 if !flags.Changed(flagPublish) { 219 return 220 } 221 222 values := flags.Lookup(flagPublish).Value.(*opts.ListOpts).GetAll() 223 ports, portBindings, _ := nat.ParsePortSpecs(values) 224 225 for port := range ports { 226 *portConfig = append(*portConfig, convertPortToPortConfig(port, portBindings)...) 227 } 228 } 229 230 func mergeNetworks(flags *pflag.FlagSet, attachments *[]swarm.NetworkAttachmentConfig) { 231 if !flags.Changed(flagNetwork) { 232 return 233 } 234 networks, _ := flags.GetStringSlice(flagNetwork) 235 for _, network := range networks { 236 *attachments = append(*attachments, swarm.NetworkAttachmentConfig{Target: network}) 237 } 238 } 239 240 func mergeMode(flags *pflag.FlagSet, serviceMode *swarm.ServiceMode) error { 241 if !flags.Changed(flagMode) && !flags.Changed(flagReplicas) { 242 return nil 243 } 244 245 var mode string 246 if flags.Changed(flagMode) { 247 mode, _ = flags.GetString(flagMode) 248 } 249 250 if !(mode == "replicated" || serviceMode.Replicated != nil) && flags.Changed(flagReplicas) { 251 return fmt.Errorf("replicas can only be used with replicated mode") 252 } 253 254 if mode == "global" { 255 serviceMode.Replicated = nil 256 serviceMode.Global = &swarm.GlobalService{} 257 return nil 258 } 259 260 if flags.Changed(flagReplicas) { 261 replicas := flags.Lookup(flagReplicas).Value.(*Uint64Opt).Value() 262 serviceMode.Replicated = &swarm.ReplicatedService{Replicas: replicas} 263 serviceMode.Global = nil 264 return nil 265 } 266 267 if mode == "replicated" { 268 if serviceMode.Replicated != nil { 269 return nil 270 } 271 serviceMode.Replicated = &swarm.ReplicatedService{Replicas: &DefaultReplicas} 272 serviceMode.Global = nil 273 } 274 275 return nil 276 }