update.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package node
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/docker/docker/api/types/swarm"
  6. "github.com/docker/docker/cli"
  7. "github.com/docker/docker/cli/command"
  8. "github.com/docker/docker/opts"
  9. runconfigopts "github.com/docker/docker/runconfig/opts"
  10. "github.com/spf13/cobra"
  11. "github.com/spf13/pflag"
  12. "golang.org/x/net/context"
  13. )
  14. var (
  15. errNoRoleChange = errors.New("role was already set to the requested value")
  16. )
  17. func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
  18. nodeOpts := newNodeOptions()
  19. cmd := &cobra.Command{
  20. Use: "update [OPTIONS] NODE",
  21. Short: "Update a node",
  22. Args: cli.ExactArgs(1),
  23. RunE: func(cmd *cobra.Command, args []string) error {
  24. return runUpdate(dockerCli, cmd.Flags(), args[0])
  25. },
  26. }
  27. flags := cmd.Flags()
  28. flags.StringVar(&nodeOpts.role, flagRole, "", "Role of the node (worker/manager)")
  29. flags.StringVar(&nodeOpts.availability, flagAvailability, "", "Availability of the node (active/pause/drain)")
  30. flags.Var(&nodeOpts.annotations.labels, flagLabelAdd, "Add or update a node label (key=value)")
  31. labelKeys := opts.NewListOpts(nil)
  32. flags.Var(&labelKeys, flagLabelRemove, "Remove a node label if exists")
  33. return cmd
  34. }
  35. func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, nodeID string) error {
  36. success := func(_ string) {
  37. fmt.Fprintln(dockerCli.Out(), nodeID)
  38. }
  39. return updateNodes(dockerCli, []string{nodeID}, mergeNodeUpdate(flags), success)
  40. }
  41. func updateNodes(dockerCli *command.DockerCli, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error {
  42. client := dockerCli.Client()
  43. ctx := context.Background()
  44. for _, nodeID := range nodes {
  45. node, _, err := client.NodeInspectWithRaw(ctx, nodeID)
  46. if err != nil {
  47. return err
  48. }
  49. err = mergeNode(&node)
  50. if err != nil {
  51. if err == errNoRoleChange {
  52. continue
  53. }
  54. return err
  55. }
  56. err = client.NodeUpdate(ctx, node.ID, node.Version, node.Spec)
  57. if err != nil {
  58. return err
  59. }
  60. success(nodeID)
  61. }
  62. return nil
  63. }
  64. func mergeNodeUpdate(flags *pflag.FlagSet) func(*swarm.Node) error {
  65. return func(node *swarm.Node) error {
  66. spec := &node.Spec
  67. if flags.Changed(flagRole) {
  68. str, err := flags.GetString(flagRole)
  69. if err != nil {
  70. return err
  71. }
  72. spec.Role = swarm.NodeRole(str)
  73. }
  74. if flags.Changed(flagAvailability) {
  75. str, err := flags.GetString(flagAvailability)
  76. if err != nil {
  77. return err
  78. }
  79. spec.Availability = swarm.NodeAvailability(str)
  80. }
  81. if spec.Annotations.Labels == nil {
  82. spec.Annotations.Labels = make(map[string]string)
  83. }
  84. if flags.Changed(flagLabelAdd) {
  85. labels := flags.Lookup(flagLabelAdd).Value.(*opts.ListOpts).GetAll()
  86. for k, v := range runconfigopts.ConvertKVStringsToMap(labels) {
  87. spec.Annotations.Labels[k] = v
  88. }
  89. }
  90. if flags.Changed(flagLabelRemove) {
  91. keys := flags.Lookup(flagLabelRemove).Value.(*opts.ListOpts).GetAll()
  92. for _, k := range keys {
  93. // if a key doesn't exist, fail the command explicitly
  94. if _, exists := spec.Annotations.Labels[k]; !exists {
  95. return fmt.Errorf("key %s doesn't exist in node's labels", k)
  96. }
  97. delete(spec.Annotations.Labels, k)
  98. }
  99. }
  100. return nil
  101. }
  102. }
  103. const (
  104. flagRole = "role"
  105. flagAvailability = "availability"
  106. flagLabelAdd = "label-add"
  107. flagLabelRemove = "label-rm"
  108. )