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