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