Signed-off-by: Dong Chen <dongluo.chen@docker.com>
| ... | ... |
@@ -21,8 +21,9 @@ func newAcceptCommand(dockerCli *client.DockerCli) *cobra.Command {
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 | 23 |
func runAccept(dockerCli *client.DockerCli, nodes []string) error {
|
| 24 |
- accept := func(node *swarm.Node) {
|
|
| 24 |
+ accept := func(node *swarm.Node) error {
|
|
| 25 | 25 |
node.Spec.Membership = swarm.NodeMembershipAccepted |
| 26 |
+ return nil |
|
| 26 | 27 |
} |
| 27 | 28 |
success := func(nodeID string) {
|
| 28 | 29 |
fmt.Fprintf(dockerCli.Out(), "Node %s accepted in the swarm.\n", nodeID) |
| ... | ... |
@@ -21,8 +21,9 @@ func newDemoteCommand(dockerCli *client.DockerCli) *cobra.Command {
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 | 23 |
func runDemote(dockerCli *client.DockerCli, nodes []string) error {
|
| 24 |
- demote := func(node *swarm.Node) {
|
|
| 24 |
+ demote := func(node *swarm.Node) error {
|
|
| 25 | 25 |
node.Spec.Role = swarm.NodeRoleWorker |
| 26 |
+ return nil |
|
| 26 | 27 |
} |
| 27 | 28 |
success := func(nodeID string) {
|
| 28 | 29 |
fmt.Fprintf(dockerCli.Out(), "Manager %s demoted in the swarm.\n", nodeID) |
| ... | ... |
@@ -4,18 +4,37 @@ import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"strings" |
| 6 | 6 |
|
| 7 |
+ "github.com/docker/docker/opts" |
|
| 8 |
+ runconfigopts "github.com/docker/docker/runconfig/opts" |
|
| 7 | 9 |
"github.com/docker/engine-api/types/swarm" |
| 8 | 10 |
) |
| 9 | 11 |
|
| 10 | 12 |
type nodeOptions struct {
|
| 13 |
+ annotations |
|
| 11 | 14 |
role string |
| 12 | 15 |
membership string |
| 13 | 16 |
availability string |
| 14 | 17 |
} |
| 15 | 18 |
|
| 19 |
+type annotations struct {
|
|
| 20 |
+ name string |
|
| 21 |
+ labels opts.ListOpts |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func newNodeOptions() *nodeOptions {
|
|
| 25 |
+ return &nodeOptions{
|
|
| 26 |
+ annotations: annotations{
|
|
| 27 |
+ labels: opts.NewListOpts(nil), |
|
| 28 |
+ }, |
|
| 29 |
+ } |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 16 | 32 |
func (opts *nodeOptions) ToNodeSpec() (swarm.NodeSpec, error) {
|
| 17 | 33 |
var spec swarm.NodeSpec |
| 18 | 34 |
|
| 35 |
+ spec.Annotations.Name = opts.annotations.name |
|
| 36 |
+ spec.Annotations.Labels = runconfigopts.ConvertKVStringsToMap(opts.annotations.labels.GetAll()) |
|
| 37 |
+ |
|
| 19 | 38 |
switch swarm.NodeRole(strings.ToLower(opts.role)) {
|
| 20 | 39 |
case swarm.NodeRoleWorker: |
| 21 | 40 |
spec.Role = swarm.NodeRoleWorker |
| ... | ... |
@@ -21,8 +21,9 @@ func newPromoteCommand(dockerCli *client.DockerCli) *cobra.Command {
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 | 23 |
func runPromote(dockerCli *client.DockerCli, nodes []string) error {
|
| 24 |
- promote := func(node *swarm.Node) {
|
|
| 24 |
+ promote := func(node *swarm.Node) error {
|
|
| 25 | 25 |
node.Spec.Role = swarm.NodeRoleManager |
| 26 |
+ return nil |
|
| 26 | 27 |
} |
| 27 | 28 |
success := func(nodeID string) {
|
| 28 | 29 |
fmt.Fprintf(dockerCli.Out(), "Node %s promoted to a manager in the swarm.\n", nodeID) |
| ... | ... |
@@ -5,6 +5,8 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/docker/api/client" |
| 7 | 7 |
"github.com/docker/docker/cli" |
| 8 |
+ "github.com/docker/docker/opts" |
|
| 9 |
+ runconfigopts "github.com/docker/docker/runconfig/opts" |
|
| 8 | 10 |
"github.com/docker/engine-api/types/swarm" |
| 9 | 11 |
"github.com/spf13/cobra" |
| 10 | 12 |
"github.com/spf13/pflag" |
| ... | ... |
@@ -12,7 +14,7 @@ import ( |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 | 14 |
func newUpdateCommand(dockerCli *client.DockerCli) *cobra.Command {
|
| 15 |
- var opts nodeOptions |
|
| 15 |
+ nodeOpts := newNodeOptions() |
|
| 16 | 16 |
|
| 17 | 17 |
cmd := &cobra.Command{
|
| 18 | 18 |
Use: "update [OPTIONS] NODE", |
| ... | ... |
@@ -24,9 +26,12 @@ func newUpdateCommand(dockerCli *client.DockerCli) *cobra.Command {
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
flags := cmd.Flags() |
| 27 |
- flags.StringVar(&opts.role, flagRole, "", "Role of the node (worker/manager)") |
|
| 28 |
- flags.StringVar(&opts.membership, flagMembership, "", "Membership of the node (accepted/rejected)") |
|
| 29 |
- flags.StringVar(&opts.availability, flagAvailability, "", "Availability of the node (active/pause/drain)") |
|
| 27 |
+ flags.StringVar(&nodeOpts.role, flagRole, "", "Role of the node (worker/manager)") |
|
| 28 |
+ flags.StringVar(&nodeOpts.membership, flagMembership, "", "Membership of the node (accepted/rejected)") |
|
| 29 |
+ flags.StringVar(&nodeOpts.availability, flagAvailability, "", "Availability of the node (active/pause/drain)") |
|
| 30 |
+ flags.Var(&nodeOpts.annotations.labels, flagLabelAdd, "Add or update a node label (key=value)") |
|
| 31 |
+ labelKeys := opts.NewListOpts(nil) |
|
| 32 |
+ flags.Var(&labelKeys, flagLabelRemove, "Remove a node label if exists") |
|
| 30 | 33 |
return cmd |
| 31 | 34 |
} |
| 32 | 35 |
|
| ... | ... |
@@ -37,7 +42,7 @@ func runUpdate(dockerCli *client.DockerCli, flags *pflag.FlagSet, nodeID string) |
| 37 | 37 |
return updateNodes(dockerCli, []string{nodeID}, mergeNodeUpdate(flags), success)
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 |
-func updateNodes(dockerCli *client.DockerCli, nodes []string, mergeNode func(node *swarm.Node), success func(nodeID string)) error {
|
|
| 40 |
+func updateNodes(dockerCli *client.DockerCli, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error {
|
|
| 41 | 41 |
client := dockerCli.Client() |
| 42 | 42 |
ctx := context.Background() |
| 43 | 43 |
|
| ... | ... |
@@ -47,7 +52,10 @@ func updateNodes(dockerCli *client.DockerCli, nodes []string, mergeNode func(nod |
| 47 | 47 |
return err |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
- mergeNode(&node) |
|
| 50 |
+ err = mergeNode(&node) |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ return err |
|
| 53 |
+ } |
|
| 51 | 54 |
err = client.NodeUpdate(ctx, node.ID, node.Version, node.Spec) |
| 52 | 55 |
if err != nil {
|
| 53 | 56 |
return err |
| ... | ... |
@@ -57,22 +65,51 @@ func updateNodes(dockerCli *client.DockerCli, nodes []string, mergeNode func(nod |
| 57 | 57 |
return nil |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
-func mergeNodeUpdate(flags *pflag.FlagSet) func(*swarm.Node) {
|
|
| 61 |
- return func(node *swarm.Node) {
|
|
| 60 |
+func mergeNodeUpdate(flags *pflag.FlagSet) func(*swarm.Node) error {
|
|
| 61 |
+ return func(node *swarm.Node) error {
|
|
| 62 | 62 |
spec := &node.Spec |
| 63 | 63 |
|
| 64 | 64 |
if flags.Changed(flagRole) {
|
| 65 |
- str, _ := flags.GetString(flagRole) |
|
| 65 |
+ str, err := flags.GetString(flagRole) |
|
| 66 |
+ if err != nil {
|
|
| 67 |
+ return err |
|
| 68 |
+ } |
|
| 66 | 69 |
spec.Role = swarm.NodeRole(str) |
| 67 | 70 |
} |
| 68 | 71 |
if flags.Changed(flagMembership) {
|
| 69 |
- str, _ := flags.GetString(flagMembership) |
|
| 72 |
+ str, err := flags.GetString(flagMembership) |
|
| 73 |
+ if err != nil {
|
|
| 74 |
+ return err |
|
| 75 |
+ } |
|
| 70 | 76 |
spec.Membership = swarm.NodeMembership(str) |
| 71 | 77 |
} |
| 72 | 78 |
if flags.Changed(flagAvailability) {
|
| 73 |
- str, _ := flags.GetString(flagAvailability) |
|
| 79 |
+ str, err := flags.GetString(flagAvailability) |
|
| 80 |
+ if err != nil {
|
|
| 81 |
+ return err |
|
| 82 |
+ } |
|
| 74 | 83 |
spec.Availability = swarm.NodeAvailability(str) |
| 75 | 84 |
} |
| 85 |
+ if spec.Annotations.Labels == nil {
|
|
| 86 |
+ spec.Annotations.Labels = make(map[string]string) |
|
| 87 |
+ } |
|
| 88 |
+ if flags.Changed(flagLabelAdd) {
|
|
| 89 |
+ labels := flags.Lookup(flagLabelAdd).Value.(*opts.ListOpts).GetAll() |
|
| 90 |
+ for k, v := range runconfigopts.ConvertKVStringsToMap(labels) {
|
|
| 91 |
+ spec.Annotations.Labels[k] = v |
|
| 92 |
+ } |
|
| 93 |
+ } |
|
| 94 |
+ if flags.Changed(flagLabelRemove) {
|
|
| 95 |
+ keys := flags.Lookup(flagLabelRemove).Value.(*opts.ListOpts).GetAll() |
|
| 96 |
+ for _, k := range keys {
|
|
| 97 |
+ // if a key doesn't exist, fail the command explicitly |
|
| 98 |
+ if _, exists := spec.Annotations.Labels[k]; !exists {
|
|
| 99 |
+ return fmt.Errorf("key %s doesn't exist in node's labels", k)
|
|
| 100 |
+ } |
|
| 101 |
+ delete(spec.Annotations.Labels, k) |
|
| 102 |
+ } |
|
| 103 |
+ } |
|
| 104 |
+ return nil |
|
| 76 | 105 |
} |
| 77 | 106 |
} |
| 78 | 107 |
|
| ... | ... |
@@ -80,4 +117,6 @@ const ( |
| 80 | 80 |
flagRole = "role" |
| 81 | 81 |
flagMembership = "membership" |
| 82 | 82 |
flagAvailability = "availability" |
| 83 |
+ flagLabelAdd = "label-add" |
|
| 84 |
+ flagLabelRemove = "label-rm" |
|
| 83 | 85 |
) |
| ... | ... |
@@ -19,6 +19,8 @@ Update a node |
| 19 | 19 |
Options: |
| 20 | 20 |
--availability string Availability of the node (active/pause/drain) |
| 21 | 21 |
--help Print usage |
| 22 |
+ --label-add value Add or update a node label (key=value) (default []) |
|
| 23 |
+ --label-rm value Remove a node label if exists (default []) |
|
| 22 | 24 |
--membership string Membership of the node (accepted/rejected) |
| 23 | 25 |
--role string Role of the node (worker/manager) |
| 24 | 26 |
``` |