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  )