opts.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. package service
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "github.com/docker/docker/api/types/container"
  8. "github.com/docker/docker/api/types/swarm"
  9. "github.com/docker/docker/opts"
  10. runconfigopts "github.com/docker/docker/runconfig/opts"
  11. shlex "github.com/flynn-archive/go-shlex"
  12. "github.com/pkg/errors"
  13. "github.com/spf13/pflag"
  14. )
  15. type int64Value interface {
  16. Value() int64
  17. }
  18. // PositiveDurationOpt is an option type for time.Duration that uses a pointer.
  19. // It bahave similarly to DurationOpt but only allows positive duration values.
  20. type PositiveDurationOpt struct {
  21. DurationOpt
  22. }
  23. // Set a new value on the option. Setting a negative duration value will cause
  24. // an error to be returned.
  25. func (d *PositiveDurationOpt) Set(s string) error {
  26. err := d.DurationOpt.Set(s)
  27. if err != nil {
  28. return err
  29. }
  30. if *d.DurationOpt.value < 0 {
  31. return errors.Errorf("duration cannot be negative")
  32. }
  33. return nil
  34. }
  35. // DurationOpt is an option type for time.Duration that uses a pointer. This
  36. // allows us to get nil values outside, instead of defaulting to 0
  37. type DurationOpt struct {
  38. value *time.Duration
  39. }
  40. // Set a new value on the option
  41. func (d *DurationOpt) Set(s string) error {
  42. v, err := time.ParseDuration(s)
  43. d.value = &v
  44. return err
  45. }
  46. // Type returns the type of this option, which will be displayed in `--help` output
  47. func (d *DurationOpt) Type() string {
  48. return "duration"
  49. }
  50. // String returns a string repr of this option
  51. func (d *DurationOpt) String() string {
  52. if d.value != nil {
  53. return d.value.String()
  54. }
  55. return ""
  56. }
  57. // Value returns the time.Duration
  58. func (d *DurationOpt) Value() *time.Duration {
  59. return d.value
  60. }
  61. // Uint64Opt represents a uint64.
  62. type Uint64Opt struct {
  63. value *uint64
  64. }
  65. // Set a new value on the option
  66. func (i *Uint64Opt) Set(s string) error {
  67. v, err := strconv.ParseUint(s, 0, 64)
  68. i.value = &v
  69. return err
  70. }
  71. // Type returns the type of this option, which will be displayed in `--help` output
  72. func (i *Uint64Opt) Type() string {
  73. return "uint"
  74. }
  75. // String returns a string repr of this option
  76. func (i *Uint64Opt) String() string {
  77. if i.value != nil {
  78. return fmt.Sprintf("%v", *i.value)
  79. }
  80. return ""
  81. }
  82. // Value returns the uint64
  83. func (i *Uint64Opt) Value() *uint64 {
  84. return i.value
  85. }
  86. type floatValue float32
  87. func (f *floatValue) Set(s string) error {
  88. v, err := strconv.ParseFloat(s, 32)
  89. *f = floatValue(v)
  90. return err
  91. }
  92. func (f *floatValue) Type() string {
  93. return "float"
  94. }
  95. func (f *floatValue) String() string {
  96. return strconv.FormatFloat(float64(*f), 'g', -1, 32)
  97. }
  98. func (f *floatValue) Value() float32 {
  99. return float32(*f)
  100. }
  101. // placementPrefOpts holds a list of placement preferences.
  102. type placementPrefOpts struct {
  103. prefs []swarm.PlacementPreference
  104. strings []string
  105. }
  106. func (opts *placementPrefOpts) String() string {
  107. if len(opts.strings) == 0 {
  108. return ""
  109. }
  110. return fmt.Sprintf("%v", opts.strings)
  111. }
  112. // Set validates the input value and adds it to the internal slices.
  113. // Note: in the future strategies other than "spread", may be supported,
  114. // as well as additional comma-separated options.
  115. func (opts *placementPrefOpts) Set(value string) error {
  116. fields := strings.Split(value, "=")
  117. if len(fields) != 2 {
  118. return errors.New(`placement preference must be of the format "<strategy>=<arg>"`)
  119. }
  120. if fields[0] != "spread" {
  121. return errors.Errorf("unsupported placement preference %s (only spread is supported)", fields[0])
  122. }
  123. opts.prefs = append(opts.prefs, swarm.PlacementPreference{
  124. Spread: &swarm.SpreadOver{
  125. SpreadDescriptor: fields[1],
  126. },
  127. })
  128. opts.strings = append(opts.strings, value)
  129. return nil
  130. }
  131. // Type returns a string name for this Option type
  132. func (opts *placementPrefOpts) Type() string {
  133. return "pref"
  134. }
  135. // ShlexOpt is a flag Value which parses a string as a list of shell words
  136. type ShlexOpt []string
  137. // Set the value
  138. func (s *ShlexOpt) Set(value string) error {
  139. valueSlice, err := shlex.Split(value)
  140. *s = ShlexOpt(valueSlice)
  141. return err
  142. }
  143. // Type returns the tyep of the value
  144. func (s *ShlexOpt) Type() string {
  145. return "command"
  146. }
  147. func (s *ShlexOpt) String() string {
  148. return fmt.Sprint(*s)
  149. }
  150. // Value returns the value as a string slice
  151. func (s *ShlexOpt) Value() []string {
  152. return []string(*s)
  153. }
  154. type updateOptions struct {
  155. parallelism uint64
  156. delay time.Duration
  157. monitor time.Duration
  158. onFailure string
  159. maxFailureRatio floatValue
  160. }
  161. func (opts updateOptions) config() *swarm.UpdateConfig {
  162. return &swarm.UpdateConfig{
  163. Parallelism: opts.parallelism,
  164. Delay: opts.delay,
  165. Monitor: opts.monitor,
  166. FailureAction: opts.onFailure,
  167. MaxFailureRatio: opts.maxFailureRatio.Value(),
  168. }
  169. }
  170. type resourceOptions struct {
  171. limitCPU opts.NanoCPUs
  172. limitMemBytes opts.MemBytes
  173. resCPU opts.NanoCPUs
  174. resMemBytes opts.MemBytes
  175. }
  176. func (r *resourceOptions) ToResourceRequirements() *swarm.ResourceRequirements {
  177. return &swarm.ResourceRequirements{
  178. Limits: &swarm.Resources{
  179. NanoCPUs: r.limitCPU.Value(),
  180. MemoryBytes: r.limitMemBytes.Value(),
  181. },
  182. Reservations: &swarm.Resources{
  183. NanoCPUs: r.resCPU.Value(),
  184. MemoryBytes: r.resMemBytes.Value(),
  185. },
  186. }
  187. }
  188. type restartPolicyOptions struct {
  189. condition string
  190. delay DurationOpt
  191. maxAttempts Uint64Opt
  192. window DurationOpt
  193. }
  194. func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy {
  195. return &swarm.RestartPolicy{
  196. Condition: swarm.RestartPolicyCondition(r.condition),
  197. Delay: r.delay.Value(),
  198. MaxAttempts: r.maxAttempts.Value(),
  199. Window: r.window.Value(),
  200. }
  201. }
  202. func convertNetworks(networks []string) []swarm.NetworkAttachmentConfig {
  203. nets := []swarm.NetworkAttachmentConfig{}
  204. for _, network := range networks {
  205. nets = append(nets, swarm.NetworkAttachmentConfig{Target: network})
  206. }
  207. return nets
  208. }
  209. type endpointOptions struct {
  210. mode string
  211. publishPorts opts.PortOpt
  212. }
  213. func (e *endpointOptions) ToEndpointSpec() *swarm.EndpointSpec {
  214. return &swarm.EndpointSpec{
  215. Mode: swarm.ResolutionMode(strings.ToLower(e.mode)),
  216. Ports: e.publishPorts.Value(),
  217. }
  218. }
  219. type logDriverOptions struct {
  220. name string
  221. opts opts.ListOpts
  222. }
  223. func newLogDriverOptions() logDriverOptions {
  224. return logDriverOptions{opts: opts.NewListOpts(opts.ValidateEnv)}
  225. }
  226. func (ldo *logDriverOptions) toLogDriver() *swarm.Driver {
  227. if ldo.name == "" {
  228. return nil
  229. }
  230. // set the log driver only if specified.
  231. return &swarm.Driver{
  232. Name: ldo.name,
  233. Options: runconfigopts.ConvertKVStringsToMap(ldo.opts.GetAll()),
  234. }
  235. }
  236. type healthCheckOptions struct {
  237. cmd string
  238. interval PositiveDurationOpt
  239. timeout PositiveDurationOpt
  240. retries int
  241. noHealthcheck bool
  242. }
  243. func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error) {
  244. var healthConfig *container.HealthConfig
  245. haveHealthSettings := opts.cmd != "" ||
  246. opts.interval.Value() != nil ||
  247. opts.timeout.Value() != nil ||
  248. opts.retries != 0
  249. if opts.noHealthcheck {
  250. if haveHealthSettings {
  251. return nil, errors.Errorf("--%s conflicts with --health-* options", flagNoHealthcheck)
  252. }
  253. healthConfig = &container.HealthConfig{Test: []string{"NONE"}}
  254. } else if haveHealthSettings {
  255. var test []string
  256. if opts.cmd != "" {
  257. test = []string{"CMD-SHELL", opts.cmd}
  258. }
  259. var interval, timeout time.Duration
  260. if ptr := opts.interval.Value(); ptr != nil {
  261. interval = *ptr
  262. }
  263. if ptr := opts.timeout.Value(); ptr != nil {
  264. timeout = *ptr
  265. }
  266. healthConfig = &container.HealthConfig{
  267. Test: test,
  268. Interval: interval,
  269. Timeout: timeout,
  270. Retries: opts.retries,
  271. }
  272. }
  273. return healthConfig, nil
  274. }
  275. // convertExtraHostsToSwarmHosts converts an array of extra hosts in cli
  276. // <host>:<ip>
  277. // into a swarmkit host format:
  278. // IP_address canonical_hostname [aliases...]
  279. // This assumes input value (<host>:<ip>) has already been validated
  280. func convertExtraHostsToSwarmHosts(extraHosts []string) []string {
  281. hosts := []string{}
  282. for _, extraHost := range extraHosts {
  283. parts := strings.SplitN(extraHost, ":", 2)
  284. hosts = append(hosts, fmt.Sprintf("%s %s", parts[1], parts[0]))
  285. }
  286. return hosts
  287. }
  288. type serviceOptions struct {
  289. detach bool
  290. quiet bool
  291. name string
  292. labels opts.ListOpts
  293. containerLabels opts.ListOpts
  294. image string
  295. entrypoint ShlexOpt
  296. args []string
  297. hostname string
  298. env opts.ListOpts
  299. envFile opts.ListOpts
  300. workdir string
  301. user string
  302. groups opts.ListOpts
  303. stopSignal string
  304. tty bool
  305. readOnly bool
  306. mounts opts.MountOpt
  307. dns opts.ListOpts
  308. dnsSearch opts.ListOpts
  309. dnsOption opts.ListOpts
  310. hosts opts.ListOpts
  311. resources resourceOptions
  312. stopGrace DurationOpt
  313. replicas Uint64Opt
  314. mode string
  315. restartPolicy restartPolicyOptions
  316. constraints opts.ListOpts
  317. placementPrefs placementPrefOpts
  318. update updateOptions
  319. rollback updateOptions
  320. networks opts.ListOpts
  321. endpoint endpointOptions
  322. registryAuth bool
  323. logDriver logDriverOptions
  324. healthcheck healthCheckOptions
  325. secrets opts.SecretOpt
  326. }
  327. func newServiceOptions() *serviceOptions {
  328. return &serviceOptions{
  329. labels: opts.NewListOpts(opts.ValidateEnv),
  330. constraints: opts.NewListOpts(nil),
  331. containerLabels: opts.NewListOpts(opts.ValidateEnv),
  332. env: opts.NewListOpts(opts.ValidateEnv),
  333. envFile: opts.NewListOpts(nil),
  334. groups: opts.NewListOpts(nil),
  335. logDriver: newLogDriverOptions(),
  336. dns: opts.NewListOpts(opts.ValidateIPAddress),
  337. dnsOption: opts.NewListOpts(nil),
  338. dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
  339. hosts: opts.NewListOpts(opts.ValidateExtraHost),
  340. networks: opts.NewListOpts(nil),
  341. }
  342. }
  343. func (opts *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
  344. serviceMode := swarm.ServiceMode{}
  345. switch opts.mode {
  346. case "global":
  347. if opts.replicas.Value() != nil {
  348. return serviceMode, errors.Errorf("replicas can only be used with replicated mode")
  349. }
  350. serviceMode.Global = &swarm.GlobalService{}
  351. case "replicated":
  352. serviceMode.Replicated = &swarm.ReplicatedService{
  353. Replicas: opts.replicas.Value(),
  354. }
  355. default:
  356. return serviceMode, errors.Errorf("Unknown mode: %s, only replicated and global supported", opts.mode)
  357. }
  358. return serviceMode, nil
  359. }
  360. func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
  361. var service swarm.ServiceSpec
  362. envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll())
  363. if err != nil {
  364. return service, err
  365. }
  366. currentEnv := make([]string, 0, len(envVariables))
  367. for _, env := range envVariables { // need to process each var, in order
  368. k := strings.SplitN(env, "=", 2)[0]
  369. for i, current := range currentEnv { // remove duplicates
  370. if current == env {
  371. continue // no update required, may hide this behind flag to preserve order of envVariables
  372. }
  373. if strings.HasPrefix(current, k+"=") {
  374. currentEnv = append(currentEnv[:i], currentEnv[i+1:]...)
  375. }
  376. }
  377. currentEnv = append(currentEnv, env)
  378. }
  379. healthConfig, err := opts.healthcheck.toHealthConfig()
  380. if err != nil {
  381. return service, err
  382. }
  383. serviceMode, err := opts.ToServiceMode()
  384. if err != nil {
  385. return service, err
  386. }
  387. service = swarm.ServiceSpec{
  388. Annotations: swarm.Annotations{
  389. Name: opts.name,
  390. Labels: runconfigopts.ConvertKVStringsToMap(opts.labels.GetAll()),
  391. },
  392. TaskTemplate: swarm.TaskSpec{
  393. ContainerSpec: swarm.ContainerSpec{
  394. Image: opts.image,
  395. Args: opts.args,
  396. Command: opts.entrypoint.Value(),
  397. Env: currentEnv,
  398. Hostname: opts.hostname,
  399. Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
  400. Dir: opts.workdir,
  401. User: opts.user,
  402. Groups: opts.groups.GetAll(),
  403. StopSignal: opts.stopSignal,
  404. TTY: opts.tty,
  405. ReadOnly: opts.readOnly,
  406. Mounts: opts.mounts.Value(),
  407. DNSConfig: &swarm.DNSConfig{
  408. Nameservers: opts.dns.GetAll(),
  409. Search: opts.dnsSearch.GetAll(),
  410. Options: opts.dnsOption.GetAll(),
  411. },
  412. Hosts: convertExtraHostsToSwarmHosts(opts.hosts.GetAll()),
  413. StopGracePeriod: opts.stopGrace.Value(),
  414. Secrets: nil,
  415. Healthcheck: healthConfig,
  416. },
  417. Networks: convertNetworks(opts.networks.GetAll()),
  418. Resources: opts.resources.ToResourceRequirements(),
  419. RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
  420. Placement: &swarm.Placement{
  421. Constraints: opts.constraints.GetAll(),
  422. Preferences: opts.placementPrefs.prefs,
  423. },
  424. LogDriver: opts.logDriver.toLogDriver(),
  425. },
  426. Networks: convertNetworks(opts.networks.GetAll()),
  427. Mode: serviceMode,
  428. UpdateConfig: opts.update.config(),
  429. RollbackConfig: opts.rollback.config(),
  430. EndpointSpec: opts.endpoint.ToEndpointSpec(),
  431. }
  432. return service, nil
  433. }
  434. // addServiceFlags adds all flags that are common to both `create` and `update`.
  435. // Any flags that are not common are added separately in the individual command
  436. func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
  437. flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge")
  438. flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output")
  439. flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
  440. flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
  441. flags.StringVar(&opts.hostname, flagHostname, "", "Container hostname")
  442. flags.SetAnnotation(flagHostname, "version", []string{"1.25"})
  443. flags.Var(&opts.entrypoint, flagEntrypoint, "Overwrite the default ENTRYPOINT of the image")
  444. flags.Var(&opts.resources.limitCPU, flagLimitCPU, "Limit CPUs")
  445. flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
  446. flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs")
  447. flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
  448. flags.Var(&opts.stopGrace, flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)")
  449. flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
  450. flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", `Restart when condition is met ("none"|"on-failure"|"any")`)
  451. flags.Var(&opts.restartPolicy.delay, flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)")
  452. flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, "Maximum number of restarts before giving up")
  453. flags.Var(&opts.restartPolicy.window, flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)")
  454. flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, 1, "Maximum number of tasks updated simultaneously (0 to update all at once)")
  455. flags.DurationVar(&opts.update.delay, flagUpdateDelay, time.Duration(0), "Delay between updates (ns|us|ms|s|m|h) (default 0s)")
  456. flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, time.Duration(0), "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)")
  457. flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"})
  458. flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", `Action on update failure ("pause"|"continue"|"rollback")`)
  459. flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update")
  460. flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"})
  461. flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, 1, "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
  462. flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"})
  463. flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, time.Duration(0), "Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)")
  464. flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"})
  465. flags.DurationVar(&opts.rollback.monitor, flagRollbackMonitor, time.Duration(0), "Duration after each task rollback to monitor for failure (ns|us|ms|s|m|h) (default 0s)")
  466. flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"})
  467. flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "pause", `Action on rollback failure ("pause"|"continue")`)
  468. flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"})
  469. flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback")
  470. flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"})
  471. flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "vip", "Endpoint mode (vip or dnsrr)")
  472. flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents")
  473. flags.StringVar(&opts.logDriver.name, flagLogDriver, "", "Logging driver for service")
  474. flags.Var(&opts.logDriver.opts, flagLogOpt, "Logging driver options")
  475. flags.StringVar(&opts.healthcheck.cmd, flagHealthCmd, "", "Command to run to check health")
  476. flags.SetAnnotation(flagHealthCmd, "version", []string{"1.25"})
  477. flags.Var(&opts.healthcheck.interval, flagHealthInterval, "Time between running the check (ns|us|ms|s|m|h)")
  478. flags.SetAnnotation(flagHealthInterval, "version", []string{"1.25"})
  479. flags.Var(&opts.healthcheck.timeout, flagHealthTimeout, "Maximum time to allow one check to run (ns|us|ms|s|m|h)")
  480. flags.SetAnnotation(flagHealthTimeout, "version", []string{"1.25"})
  481. flags.IntVar(&opts.healthcheck.retries, flagHealthRetries, 0, "Consecutive failures needed to report unhealthy")
  482. flags.SetAnnotation(flagHealthRetries, "version", []string{"1.25"})
  483. flags.BoolVar(&opts.healthcheck.noHealthcheck, flagNoHealthcheck, false, "Disable any container-specified HEALTHCHECK")
  484. flags.SetAnnotation(flagNoHealthcheck, "version", []string{"1.25"})
  485. flags.BoolVarP(&opts.tty, flagTTY, "t", false, "Allocate a pseudo-TTY")
  486. flags.SetAnnotation(flagTTY, "version", []string{"1.25"})
  487. flags.BoolVar(&opts.readOnly, flagReadOnly, false, "Mount the container's root filesystem as read only")
  488. flags.SetAnnotation(flagReadOnly, "version", []string{"1.28"})
  489. flags.StringVar(&opts.stopSignal, flagStopSignal, "", "Signal to stop the container")
  490. flags.SetAnnotation(flagStopSignal, "version", []string{"1.28"})
  491. }
  492. const (
  493. flagPlacementPref = "placement-pref"
  494. flagPlacementPrefAdd = "placement-pref-add"
  495. flagPlacementPrefRemove = "placement-pref-rm"
  496. flagConstraint = "constraint"
  497. flagConstraintRemove = "constraint-rm"
  498. flagConstraintAdd = "constraint-add"
  499. flagContainerLabel = "container-label"
  500. flagContainerLabelRemove = "container-label-rm"
  501. flagContainerLabelAdd = "container-label-add"
  502. flagDNS = "dns"
  503. flagDNSRemove = "dns-rm"
  504. flagDNSAdd = "dns-add"
  505. flagDNSOption = "dns-option"
  506. flagDNSOptionRemove = "dns-option-rm"
  507. flagDNSOptionAdd = "dns-option-add"
  508. flagDNSSearch = "dns-search"
  509. flagDNSSearchRemove = "dns-search-rm"
  510. flagDNSSearchAdd = "dns-search-add"
  511. flagEndpointMode = "endpoint-mode"
  512. flagEntrypoint = "entrypoint"
  513. flagHost = "host"
  514. flagHostAdd = "host-add"
  515. flagHostRemove = "host-rm"
  516. flagHostname = "hostname"
  517. flagEnv = "env"
  518. flagEnvFile = "env-file"
  519. flagEnvRemove = "env-rm"
  520. flagEnvAdd = "env-add"
  521. flagGroup = "group"
  522. flagGroupAdd = "group-add"
  523. flagGroupRemove = "group-rm"
  524. flagLabel = "label"
  525. flagLabelRemove = "label-rm"
  526. flagLabelAdd = "label-add"
  527. flagLimitCPU = "limit-cpu"
  528. flagLimitMemory = "limit-memory"
  529. flagMode = "mode"
  530. flagMount = "mount"
  531. flagMountRemove = "mount-rm"
  532. flagMountAdd = "mount-add"
  533. flagName = "name"
  534. flagNetwork = "network"
  535. flagPublish = "publish"
  536. flagPublishRemove = "publish-rm"
  537. flagPublishAdd = "publish-add"
  538. flagReadOnly = "read-only"
  539. flagReplicas = "replicas"
  540. flagReserveCPU = "reserve-cpu"
  541. flagReserveMemory = "reserve-memory"
  542. flagRestartCondition = "restart-condition"
  543. flagRestartDelay = "restart-delay"
  544. flagRestartMaxAttempts = "restart-max-attempts"
  545. flagRestartWindow = "restart-window"
  546. flagRollbackDelay = "rollback-delay"
  547. flagRollbackFailureAction = "rollback-failure-action"
  548. flagRollbackMaxFailureRatio = "rollback-max-failure-ratio"
  549. flagRollbackMonitor = "rollback-monitor"
  550. flagRollbackParallelism = "rollback-parallelism"
  551. flagStopGracePeriod = "stop-grace-period"
  552. flagStopSignal = "stop-signal"
  553. flagTTY = "tty"
  554. flagUpdateDelay = "update-delay"
  555. flagUpdateFailureAction = "update-failure-action"
  556. flagUpdateMaxFailureRatio = "update-max-failure-ratio"
  557. flagUpdateMonitor = "update-monitor"
  558. flagUpdateParallelism = "update-parallelism"
  559. flagUser = "user"
  560. flagWorkdir = "workdir"
  561. flagRegistryAuth = "with-registry-auth"
  562. flagLogDriver = "log-driver"
  563. flagLogOpt = "log-opt"
  564. flagHealthCmd = "health-cmd"
  565. flagHealthInterval = "health-interval"
  566. flagHealthRetries = "health-retries"
  567. flagHealthTimeout = "health-timeout"
  568. flagNoHealthcheck = "no-healthcheck"
  569. flagSecret = "secret"
  570. flagSecretAdd = "secret-add"
  571. flagSecretRemove = "secret-rm"
  572. )