github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cmd/swarmctl/node/common.go (about)

     1  package node
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  
    10  	"github.com/docker/swarmkit/api"
    11  	"github.com/docker/swarmkit/cmd/swarmctl/common"
    12  	"github.com/spf13/cobra"
    13  )
    14  
    15  var (
    16  	errNoChange = errors.New("node attribute was already set to the requested value")
    17  	flagLabel   = "label"
    18  )
    19  
    20  func changeNodeAvailability(cmd *cobra.Command, args []string, availability api.NodeSpec_Availability) error {
    21  	if len(args) == 0 {
    22  		return errors.New("missing node ID")
    23  	}
    24  
    25  	if len(args) > 1 {
    26  		return errors.New("command takes exactly 1 argument")
    27  	}
    28  
    29  	c, err := common.Dial(cmd)
    30  	if err != nil {
    31  		return err
    32  	}
    33  	node, err := getNode(common.Context(cmd), c, args[0])
    34  	if err != nil {
    35  		return err
    36  	}
    37  	spec := &node.Spec
    38  
    39  	if spec.Availability == availability {
    40  		return errNoChange
    41  	}
    42  
    43  	spec.Availability = availability
    44  
    45  	_, err = c.UpdateNode(common.Context(cmd), &api.UpdateNodeRequest{
    46  		NodeID:      node.ID,
    47  		NodeVersion: &node.Meta.Version,
    48  		Spec:        spec,
    49  	})
    50  
    51  	return err
    52  }
    53  
    54  func changeNodeRole(cmd *cobra.Command, args []string, role api.NodeRole) error {
    55  	if len(args) == 0 {
    56  		return errors.New("missing node ID")
    57  	}
    58  
    59  	if len(args) > 1 {
    60  		return errors.New("command takes exactly 1 argument")
    61  	}
    62  
    63  	c, err := common.Dial(cmd)
    64  	if err != nil {
    65  		return err
    66  	}
    67  	node, err := getNode(common.Context(cmd), c, args[0])
    68  	if err != nil {
    69  		return err
    70  	}
    71  	spec := &node.Spec
    72  
    73  	if spec.DesiredRole == role {
    74  		return errNoChange
    75  	}
    76  
    77  	spec.DesiredRole = role
    78  
    79  	_, err = c.UpdateNode(common.Context(cmd), &api.UpdateNodeRequest{
    80  		NodeID:      node.ID,
    81  		NodeVersion: &node.Meta.Version,
    82  		Spec:        spec,
    83  	})
    84  
    85  	return err
    86  }
    87  
    88  func getNode(ctx context.Context, c api.ControlClient, input string) (*api.Node, error) {
    89  	// GetNode to match via full ID.
    90  	rg, err := c.GetNode(ctx, &api.GetNodeRequest{NodeID: input})
    91  	if err != nil {
    92  		// If any error (including NotFound), ListServices to match via full name.
    93  		rl, err := c.ListNodes(ctx,
    94  			&api.ListNodesRequest{
    95  				Filters: &api.ListNodesRequest_Filters{
    96  					Names: []string{input},
    97  				},
    98  			},
    99  		)
   100  		if err != nil {
   101  			return nil, err
   102  		}
   103  
   104  		if len(rl.Nodes) == 0 {
   105  			return nil, fmt.Errorf("node %s not found", input)
   106  		}
   107  
   108  		if l := len(rl.Nodes); l > 1 {
   109  			return nil, fmt.Errorf("node %s is ambiguous (%d matches found)", input, l)
   110  		}
   111  
   112  		return rl.Nodes[0], nil
   113  	}
   114  	return rg.Node, nil
   115  }
   116  
   117  func updateNode(cmd *cobra.Command, args []string) error {
   118  	if len(args) == 0 {
   119  		return errors.New("node ID missing")
   120  	}
   121  
   122  	if len(args) > 1 {
   123  		return errors.New("command takes exactly 1 argument")
   124  	}
   125  
   126  	c, err := common.Dial(cmd)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	node, err := getNode(common.Context(cmd), c, args[0])
   132  	if err != nil {
   133  		return err
   134  	}
   135  	spec := node.Spec.Copy()
   136  
   137  	flags := cmd.Flags()
   138  	if flags.Changed(flagLabel) {
   139  		labels, err := flags.GetStringSlice(flagLabel)
   140  		if err != nil {
   141  			return err
   142  		}
   143  		// overwrite existing labels
   144  		spec.Annotations.Labels = map[string]string{}
   145  		for _, l := range labels {
   146  			parts := strings.SplitN(l, "=", 2)
   147  			if len(parts) != 2 {
   148  				return fmt.Errorf("malformed label for node %s", l)
   149  			}
   150  			spec.Annotations.Labels[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
   151  		}
   152  	}
   153  
   154  	if reflect.DeepEqual(spec, &node.Spec) {
   155  		return errNoChange
   156  	}
   157  
   158  	_, err = c.UpdateNode(common.Context(cmd), &api.UpdateNodeRequest{
   159  		NodeID:      node.ID,
   160  		NodeVersion: &node.Meta.Version,
   161  		Spec:        spec,
   162  	})
   163  
   164  	return err
   165  }