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 }