opts.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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. order string
  161. }
  162. func (opts updateOptions) config() *swarm.UpdateConfig {
  163. return &swarm.UpdateConfig{
  164. Parallelism: opts.parallelism,
  165. Delay: opts.delay,
  166. Monitor: opts.monitor,
  167. FailureAction: opts.onFailure,
  168. MaxFailureRatio: opts.maxFailureRatio.Value(),
  169. Order: opts.order,
  170. }
  171. }
  172. type resourceOptions struct {
  173. limitCPU opts.NanoCPUs
  174. limitMemBytes opts.MemBytes
  175. resCPU opts.NanoCPUs
  176. resMemBytes opts.MemBytes
  177. }
  178. func (r *resourceOptions) ToResourceRequirements() *swarm.ResourceRequirements {
  179. return &swarm.ResourceRequirements{
  180. Limits: &swarm.Resources{
  181. NanoCPUs: r.limitCPU.Value(),
  182. MemoryBytes: r.limitMemBytes.Value(),
  183. },
  184. Reservations: &swarm.Resources{
  185. NanoCPUs: r.resCPU.Value(),
  186. MemoryBytes: r.resMemBytes.Value(),
  187. },
  188. }
  189. }
  190. type restartPolicyOptions struct {
  191. condition string
  192. delay DurationOpt
  193. maxAttempts Uint64Opt
  194. window DurationOpt
  195. }
  196. func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy {
  197. return &swarm.RestartPolicy{
  198. Condition: swarm.RestartPolicyCondition(r.condition),
  199. Delay: r.delay.Value(),
  200. MaxAttempts: r.maxAttempts.Value(),
  201. Window: r.window.Value(),
  202. }
  203. }
  204. type credentialSpecOpt struct {
  205. value *swarm.CredentialSpec
  206. source string
  207. }
  208. func (c *credentialSpecOpt) Set(value string) error {
  209. c.source = value
  210. c.value = &swarm.CredentialSpec{}
  211. switch {
  212. case strings.HasPrefix(value, "file://"):
  213. c.value.File = strings.TrimPrefix(value, "file://")
  214. case strings.HasPrefix(value, "registry://"):
  215. c.value.Registry = strings.TrimPrefix(value, "registry://")
  216. default:
  217. return errors.New("Invalid credential spec - value must be prefixed file:// or registry:// followed by a value")
  218. }
  219. return nil
  220. }
  221. func (c *credentialSpecOpt) Type() string {
  222. return "credential-spec"
  223. }
  224. func (c *credentialSpecOpt) String() string {
  225. return c.source
  226. }
  227. func (c *credentialSpecOpt) Value() *swarm.CredentialSpec {
  228. return c.value
  229. }
  230. func convertNetworks(networks []string) []swarm.NetworkAttachmentConfig {
  231. nets := []swarm.NetworkAttachmentConfig{}
  232. for _, network := range networks {
  233. nets = append(nets, swarm.NetworkAttachmentConfig{Target: network})
  234. }
  235. return nets
  236. }
  237. type endpointOptions struct {
  238. mode string
  239. publishPorts opts.PortOpt
  240. }
  241. func (e *endpointOptions) ToEndpointSpec() *swarm.EndpointSpec {
  242. return &swarm.EndpointSpec{
  243. Mode: swarm.ResolutionMode(strings.ToLower(e.mode)),
  244. Ports: e.publishPorts.Value(),
  245. }
  246. }
  247. type logDriverOptions struct {
  248. name string
  249. opts opts.ListOpts
  250. }
  251. func newLogDriverOptions() logDriverOptions {
  252. return logDriverOptions{opts: opts.NewListOpts(opts.ValidateEnv)}
  253. }
  254. func (ldo *logDriverOptions) toLogDriver() *swarm.Driver {
  255. if ldo.name == "" {
  256. return nil
  257. }
  258. // set the log driver only if specified.
  259. return &swarm.Driver{
  260. Name: ldo.name,
  261. Options: runconfigopts.ConvertKVStringsToMap(ldo.opts.GetAll()),
  262. }
  263. }
  264. type healthCheckOptions struct {
  265. cmd string
  266. interval PositiveDurationOpt
  267. timeout PositiveDurationOpt
  268. retries int
  269. startPeriod PositiveDurationOpt
  270. noHealthcheck bool
  271. }
  272. func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error) {
  273. var healthConfig *container.HealthConfig
  274. haveHealthSettings := opts.cmd != "" ||
  275. opts.interval.Value() != nil ||
  276. opts.timeout.Value() != nil ||
  277. opts.retries != 0
  278. if opts.noHealthcheck {
  279. if haveHealthSettings {
  280. return nil, errors.Errorf("--%s conflicts with --health-* options", flagNoHealthcheck)
  281. }
  282. healthConfig = &container.HealthConfig{Test: []string{"NONE"}}
  283. } else if haveHealthSettings {
  284. var test []string
  285. if opts.cmd != "" {
  286. test = []string{"CMD-SHELL", opts.cmd}
  287. }
  288. var interval, timeout, startPeriod time.Duration
  289. if ptr := opts.interval.Value(); ptr != nil {
  290. interval = *ptr
  291. }
  292. if ptr := opts.timeout.Value(); ptr != nil {
  293. timeout = *ptr
  294. }
  295. if ptr := opts.startPeriod.Value(); ptr != nil {
  296. startPeriod = *ptr
  297. }
  298. healthConfig = &container.HealthConfig{
  299. Test: test,
  300. Interval: interval,
  301. Timeout: timeout,
  302. Retries: opts.retries,
  303. StartPeriod: startPeriod,
  304. }
  305. }
  306. return healthConfig, nil
  307. }
  308. // convertExtraHostsToSwarmHosts converts an array of extra hosts in cli
  309. // <host>:<ip>
  310. // into a swarmkit host format:
  311. // IP_address canonical_hostname [aliases...]
  312. // This assumes input value (<host>:<ip>) has already been validated
  313. func convertExtraHostsToSwarmHosts(extraHosts []string) []string {
  314. hosts := []string{}
  315. for _, extraHost := range extraHosts {
  316. parts := strings.SplitN(extraHost, ":", 2)
  317. hosts = append(hosts, fmt.Sprintf("%s %s", parts[1], parts[0]))
  318. }
  319. return hosts
  320. }
  321. type serviceOptions struct {
  322. detach bool
  323. quiet bool
  324. name string
  325. labels opts.ListOpts
  326. containerLabels opts.ListOpts
  327. image string
  328. entrypoint ShlexOpt
  329. args []string
  330. hostname string
  331. env opts.ListOpts
  332. envFile opts.ListOpts
  333. workdir string
  334. user string
  335. groups opts.ListOpts
  336. credentialSpec credentialSpecOpt
  337. stopSignal string
  338. tty bool
  339. readOnly bool
  340. mounts opts.MountOpt
  341. dns opts.ListOpts
  342. dnsSearch opts.ListOpts
  343. dnsOption opts.ListOpts
  344. hosts opts.ListOpts
  345. resources resourceOptions
  346. stopGrace DurationOpt
  347. replicas Uint64Opt
  348. mode string
  349. restartPolicy restartPolicyOptions
  350. constraints opts.ListOpts
  351. placementPrefs placementPrefOpts
  352. update updateOptions
  353. rollback updateOptions
  354. networks opts.ListOpts
  355. endpoint endpointOptions
  356. registryAuth bool
  357. logDriver logDriverOptions
  358. healthcheck healthCheckOptions
  359. secrets opts.SecretOpt
  360. }
  361. func newServiceOptions() *serviceOptions {
  362. return &serviceOptions{
  363. labels: opts.NewListOpts(opts.ValidateEnv),
  364. constraints: opts.NewListOpts(nil),
  365. containerLabels: opts.NewListOpts(opts.ValidateEnv),
  366. env: opts.NewListOpts(opts.ValidateEnv),
  367. envFile: opts.NewListOpts(nil),
  368. groups: opts.NewListOpts(nil),
  369. logDriver: newLogDriverOptions(),
  370. dns: opts.NewListOpts(opts.ValidateIPAddress),
  371. dnsOption: opts.NewListOpts(nil),
  372. dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
  373. hosts: opts.NewListOpts(opts.ValidateExtraHost),
  374. networks: opts.NewListOpts(nil),
  375. }
  376. }
  377. func (opts *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
  378. serviceMode := swarm.ServiceMode{}
  379. switch opts.mode {
  380. case "global":
  381. if opts.replicas.Value() != nil {
  382. return serviceMode, errors.Errorf("replicas can only be used with replicated mode")
  383. }
  384. serviceMode.Global = &swarm.GlobalService{}
  385. case "replicated":
  386. serviceMode.Replicated = &swarm.ReplicatedService{
  387. Replicas: opts.replicas.Value(),
  388. }
  389. default:
  390. return serviceMode, errors.Errorf("Unknown mode: %s, only replicated and global supported", opts.mode)
  391. }
  392. return serviceMode, nil
  393. }
  394. func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
  395. var service swarm.ServiceSpec
  396. envVariables, err := runconfigopts.ReadKVStrings(opts.envFile.GetAll(), opts.env.GetAll())
  397. if err != nil {
  398. return service, err
  399. }
  400. currentEnv := make([]string, 0, len(envVariables))
  401. for _, env := range envVariables { // need to process each var, in order
  402. k := strings.SplitN(env, "=", 2)[0]
  403. for i, current := range currentEnv { // remove duplicates
  404. if current == env {
  405. continue // no update required, may hide this behind flag to preserve order of envVariables
  406. }
  407. if strings.HasPrefix(current, k+"=") {
  408. currentEnv = append(currentEnv[:i], currentEnv[i+1:]...)
  409. }
  410. }
  411. currentEnv = append(currentEnv, env)
  412. }
  413. healthConfig, err := opts.healthcheck.toHealthConfig()
  414. if err != nil {
  415. return service, err
  416. }
  417. serviceMode, err := opts.ToServiceMode()
  418. if err != nil {
  419. return service, err
  420. }
  421. service = swarm.ServiceSpec{
  422. Annotations: swarm.Annotations{
  423. Name: opts.name,
  424. Labels: runconfigopts.ConvertKVStringsToMap(opts.labels.GetAll()),
  425. },
  426. TaskTemplate: swarm.TaskSpec{
  427. ContainerSpec: swarm.ContainerSpec{
  428. Image: opts.image,
  429. Args: opts.args,
  430. Command: opts.entrypoint.Value(),
  431. Env: currentEnv,
  432. Hostname: opts.hostname,
  433. Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
  434. Dir: opts.workdir,
  435. User: opts.user,
  436. Groups: opts.groups.GetAll(),
  437. StopSignal: opts.stopSignal,
  438. TTY: opts.tty,
  439. ReadOnly: opts.readOnly,
  440. Mounts: opts.mounts.Value(),
  441. DNSConfig: &swarm.DNSConfig{
  442. Nameservers: opts.dns.GetAll(),
  443. Search: opts.dnsSearch.GetAll(),
  444. Options: opts.dnsOption.GetAll(),
  445. },
  446. Hosts: convertExtraHostsToSwarmHosts(opts.hosts.GetAll()),
  447. StopGracePeriod: opts.stopGrace.Value(),
  448. Secrets: nil,
  449. Healthcheck: healthConfig,
  450. },
  451. Networks: convertNetworks(opts.networks.GetAll()),
  452. Resources: opts.resources.ToResourceRequirements(),
  453. RestartPolicy: opts.restartPolicy.ToRestartPolicy(),
  454. Placement: &swarm.Placement{
  455. Constraints: opts.constraints.GetAll(),
  456. Preferences: opts.placementPrefs.prefs,
  457. },
  458. LogDriver: opts.logDriver.toLogDriver(),
  459. },
  460. Networks: convertNetworks(opts.networks.GetAll()),
  461. Mode: serviceMode,
  462. UpdateConfig: opts.update.config(),
  463. RollbackConfig: opts.rollback.config(),
  464. EndpointSpec: opts.endpoint.ToEndpointSpec(),
  465. }
  466. if opts.credentialSpec.Value() != nil {
  467. service.TaskTemplate.ContainerSpec.Privileges = &swarm.Privileges{
  468. CredentialSpec: opts.credentialSpec.Value(),
  469. }
  470. }
  471. return service, nil
  472. }
  473. // addServiceFlags adds all flags that are common to both `create` and `update`.
  474. // Any flags that are not common are added separately in the individual command
  475. func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
  476. flags.BoolVarP(&opts.detach, "detach", "d", true, "Exit immediately instead of waiting for the service to converge")
  477. flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Suppress progress output")
  478. flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
  479. flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
  480. flags.Var(&opts.credentialSpec, flagCredentialSpec, "Credential spec for managed service account (Windows only)")
  481. flags.SetAnnotation(flagCredentialSpec, "version", []string{"1.29"})
  482. flags.StringVar(&opts.hostname, flagHostname, "", "Container hostname")
  483. flags.SetAnnotation(flagHostname, "version", []string{"1.25"})
  484. flags.Var(&opts.entrypoint, flagEntrypoint, "Overwrite the default ENTRYPOINT of the image")
  485. flags.Var(&opts.resources.limitCPU, flagLimitCPU, "Limit CPUs")
  486. flags.Var(&opts.resources.limitMemBytes, flagLimitMemory, "Limit Memory")
  487. flags.Var(&opts.resources.resCPU, flagReserveCPU, "Reserve CPUs")
  488. flags.Var(&opts.resources.resMemBytes, flagReserveMemory, "Reserve Memory")
  489. flags.Var(&opts.stopGrace, flagStopGracePeriod, "Time to wait before force killing a container (ns|us|ms|s|m|h)")
  490. flags.Var(&opts.replicas, flagReplicas, "Number of tasks")
  491. flags.StringVar(&opts.restartPolicy.condition, flagRestartCondition, "", `Restart when condition is met ("none"|"on-failure"|"any")`)
  492. flags.Var(&opts.restartPolicy.delay, flagRestartDelay, "Delay between restart attempts (ns|us|ms|s|m|h)")
  493. flags.Var(&opts.restartPolicy.maxAttempts, flagRestartMaxAttempts, "Maximum number of restarts before giving up")
  494. flags.Var(&opts.restartPolicy.window, flagRestartWindow, "Window used to evaluate the restart policy (ns|us|ms|s|m|h)")
  495. flags.Uint64Var(&opts.update.parallelism, flagUpdateParallelism, 1, "Maximum number of tasks updated simultaneously (0 to update all at once)")
  496. flags.DurationVar(&opts.update.delay, flagUpdateDelay, time.Duration(0), "Delay between updates (ns|us|ms|s|m|h) (default 0s)")
  497. flags.DurationVar(&opts.update.monitor, flagUpdateMonitor, time.Duration(0), "Duration after each task update to monitor for failure (ns|us|ms|s|m|h)")
  498. flags.SetAnnotation(flagUpdateMonitor, "version", []string{"1.25"})
  499. flags.StringVar(&opts.update.onFailure, flagUpdateFailureAction, "pause", `Action on update failure ("pause"|"continue"|"rollback")`)
  500. flags.Var(&opts.update.maxFailureRatio, flagUpdateMaxFailureRatio, "Failure rate to tolerate during an update")
  501. flags.SetAnnotation(flagUpdateMaxFailureRatio, "version", []string{"1.25"})
  502. flags.StringVar(&opts.update.order, flagUpdateOrder, "stop-first", `Update order ("start-first"|"stop-first")`)
  503. flags.SetAnnotation(flagUpdateOrder, "version", []string{"1.29"})
  504. flags.Uint64Var(&opts.rollback.parallelism, flagRollbackParallelism, 1, "Maximum number of tasks rolled back simultaneously (0 to roll back all at once)")
  505. flags.SetAnnotation(flagRollbackParallelism, "version", []string{"1.28"})
  506. flags.DurationVar(&opts.rollback.delay, flagRollbackDelay, time.Duration(0), "Delay between task rollbacks (ns|us|ms|s|m|h) (default 0s)")
  507. flags.SetAnnotation(flagRollbackDelay, "version", []string{"1.28"})
  508. 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)")
  509. flags.SetAnnotation(flagRollbackMonitor, "version", []string{"1.28"})
  510. flags.StringVar(&opts.rollback.onFailure, flagRollbackFailureAction, "pause", `Action on rollback failure ("pause"|"continue")`)
  511. flags.SetAnnotation(flagRollbackFailureAction, "version", []string{"1.28"})
  512. flags.Var(&opts.rollback.maxFailureRatio, flagRollbackMaxFailureRatio, "Failure rate to tolerate during a rollback")
  513. flags.SetAnnotation(flagRollbackMaxFailureRatio, "version", []string{"1.28"})
  514. flags.StringVar(&opts.rollback.order, flagRollbackOrder, "stop-first", `Rollback order ("start-first"|"stop-first")`)
  515. flags.SetAnnotation(flagRollbackOrder, "version", []string{"1.29"})
  516. flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "vip", "Endpoint mode (vip or dnsrr)")
  517. flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to swarm agents")
  518. flags.StringVar(&opts.logDriver.name, flagLogDriver, "", "Logging driver for service")
  519. flags.Var(&opts.logDriver.opts, flagLogOpt, "Logging driver options")
  520. flags.StringVar(&opts.healthcheck.cmd, flagHealthCmd, "", "Command to run to check health")
  521. flags.SetAnnotation(flagHealthCmd, "version", []string{"1.25"})
  522. flags.Var(&opts.healthcheck.interval, flagHealthInterval, "Time between running the check (ns|us|ms|s|m|h)")
  523. flags.SetAnnotation(flagHealthInterval, "version", []string{"1.25"})
  524. flags.Var(&opts.healthcheck.timeout, flagHealthTimeout, "Maximum time to allow one check to run (ns|us|ms|s|m|h)")
  525. flags.SetAnnotation(flagHealthTimeout, "version", []string{"1.25"})
  526. flags.IntVar(&opts.healthcheck.retries, flagHealthRetries, 0, "Consecutive failures needed to report unhealthy")
  527. flags.SetAnnotation(flagHealthRetries, "version", []string{"1.25"})
  528. flags.Var(&opts.healthcheck.startPeriod, flagHealthStartPeriod, "Start period for the container to initialize before counting retries towards unstable (ns|us|ms|s|m|h)")
  529. flags.SetAnnotation(flagHealthStartPeriod, "version", []string{"1.29"})
  530. flags.BoolVar(&opts.healthcheck.noHealthcheck, flagNoHealthcheck, false, "Disable any container-specified HEALTHCHECK")
  531. flags.SetAnnotation(flagNoHealthcheck, "version", []string{"1.25"})
  532. flags.BoolVarP(&opts.tty, flagTTY, "t", false, "Allocate a pseudo-TTY")
  533. flags.SetAnnotation(flagTTY, "version", []string{"1.25"})
  534. flags.BoolVar(&opts.readOnly, flagReadOnly, false, "Mount the container's root filesystem as read only")
  535. flags.SetAnnotation(flagReadOnly, "version", []string{"1.28"})
  536. flags.StringVar(&opts.stopSignal, flagStopSignal, "", "Signal to stop the container")
  537. flags.SetAnnotation(flagStopSignal, "version", []string{"1.28"})
  538. }
  539. const (
  540. flagCredentialSpec = "credential-spec"
  541. flagPlacementPref = "placement-pref"
  542. flagPlacementPrefAdd = "placement-pref-add"
  543. flagPlacementPrefRemove = "placement-pref-rm"
  544. flagConstraint = "constraint"
  545. flagConstraintRemove = "constraint-rm"
  546. flagConstraintAdd = "constraint-add"
  547. flagContainerLabel = "container-label"
  548. flagContainerLabelRemove = "container-label-rm"
  549. flagContainerLabelAdd = "container-label-add"
  550. flagDNS = "dns"
  551. flagDNSRemove = "dns-rm"
  552. flagDNSAdd = "dns-add"
  553. flagDNSOption = "dns-option"
  554. flagDNSOptionRemove = "dns-option-rm"
  555. flagDNSOptionAdd = "dns-option-add"
  556. flagDNSSearch = "dns-search"
  557. flagDNSSearchRemove = "dns-search-rm"
  558. flagDNSSearchAdd = "dns-search-add"
  559. flagEndpointMode = "endpoint-mode"
  560. flagEntrypoint = "entrypoint"
  561. flagHost = "host"
  562. flagHostAdd = "host-add"
  563. flagHostRemove = "host-rm"
  564. flagHostname = "hostname"
  565. flagEnv = "env"
  566. flagEnvFile = "env-file"
  567. flagEnvRemove = "env-rm"
  568. flagEnvAdd = "env-add"
  569. flagGroup = "group"
  570. flagGroupAdd = "group-add"
  571. flagGroupRemove = "group-rm"
  572. flagLabel = "label"
  573. flagLabelRemove = "label-rm"
  574. flagLabelAdd = "label-add"
  575. flagLimitCPU = "limit-cpu"
  576. flagLimitMemory = "limit-memory"
  577. flagMode = "mode"
  578. flagMount = "mount"
  579. flagMountRemove = "mount-rm"
  580. flagMountAdd = "mount-add"
  581. flagName = "name"
  582. flagNetwork = "network"
  583. flagPublish = "publish"
  584. flagPublishRemove = "publish-rm"
  585. flagPublishAdd = "publish-add"
  586. flagReadOnly = "read-only"
  587. flagReplicas = "replicas"
  588. flagReserveCPU = "reserve-cpu"
  589. flagReserveMemory = "reserve-memory"
  590. flagRestartCondition = "restart-condition"
  591. flagRestartDelay = "restart-delay"
  592. flagRestartMaxAttempts = "restart-max-attempts"
  593. flagRestartWindow = "restart-window"
  594. flagRollbackDelay = "rollback-delay"
  595. flagRollbackFailureAction = "rollback-failure-action"
  596. flagRollbackMaxFailureRatio = "rollback-max-failure-ratio"
  597. flagRollbackMonitor = "rollback-monitor"
  598. flagRollbackOrder = "rollback-order"
  599. flagRollbackParallelism = "rollback-parallelism"
  600. flagStopGracePeriod = "stop-grace-period"
  601. flagStopSignal = "stop-signal"
  602. flagTTY = "tty"
  603. flagUpdateDelay = "update-delay"
  604. flagUpdateFailureAction = "update-failure-action"
  605. flagUpdateMaxFailureRatio = "update-max-failure-ratio"
  606. flagUpdateMonitor = "update-monitor"
  607. flagUpdateOrder = "update-order"
  608. flagUpdateParallelism = "update-parallelism"
  609. flagUser = "user"
  610. flagWorkdir = "workdir"
  611. flagRegistryAuth = "with-registry-auth"
  612. flagLogDriver = "log-driver"
  613. flagLogOpt = "log-opt"
  614. flagHealthCmd = "health-cmd"
  615. flagHealthInterval = "health-interval"
  616. flagHealthRetries = "health-retries"
  617. flagHealthTimeout = "health-timeout"
  618. flagHealthStartPeriod = "health-start-period"
  619. flagNoHealthcheck = "no-healthcheck"
  620. flagSecret = "secret"
  621. flagSecretAdd = "secret-add"
  622. flagSecretRemove = "secret-rm"
  623. )