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  )