1package cluster // import "github.com/docker/docker/daemon/cluster"
2
3import (
4	"context"
5
6	apitypes "github.com/docker/docker/api/types"
7	types "github.com/docker/docker/api/types/swarm"
8	"github.com/docker/docker/daemon/cluster/convert"
9	"github.com/docker/docker/errdefs"
10	swarmapi "github.com/docker/swarmkit/api"
11	"google.golang.org/grpc"
12)
13
14// GetNodes returns a list of all nodes known to a cluster.
15func (c *Cluster) GetNodes(options apitypes.NodeListOptions) ([]types.Node, error) {
16	c.mu.RLock()
17	defer c.mu.RUnlock()
18
19	state := c.currentNodeState()
20	if !state.IsActiveManager() {
21		return nil, c.errNoManager(state)
22	}
23
24	filters, err := newListNodesFilters(options.Filters)
25	if err != nil {
26		return nil, err
27	}
28
29	ctx, cancel := c.getRequestContext()
30	defer cancel()
31
32	r, err := state.controlClient.ListNodes(
33		ctx,
34		&swarmapi.ListNodesRequest{Filters: filters},
35		grpc.MaxCallRecvMsgSize(defaultRecvSizeForListResponse),
36	)
37	if err != nil {
38		return nil, err
39	}
40
41	nodes := make([]types.Node, 0, len(r.Nodes))
42
43	for _, node := range r.Nodes {
44		nodes = append(nodes, convert.NodeFromGRPC(*node))
45	}
46	return nodes, nil
47}
48
49// GetNode returns a node based on an ID.
50func (c *Cluster) GetNode(input string) (types.Node, error) {
51	var node *swarmapi.Node
52
53	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
54		n, err := getNode(ctx, state.controlClient, input)
55		if err != nil {
56			return err
57		}
58		node = n
59		return nil
60	}); err != nil {
61		return types.Node{}, err
62	}
63
64	return convert.NodeFromGRPC(*node), nil
65}
66
67// UpdateNode updates existing nodes properties.
68func (c *Cluster) UpdateNode(input string, version uint64, spec types.NodeSpec) error {
69	return c.lockedManagerAction(func(_ context.Context, state nodeState) error {
70		nodeSpec, err := convert.NodeSpecToGRPC(spec)
71		if err != nil {
72			return errdefs.InvalidParameter(err)
73		}
74
75		ctx, cancel := c.getRequestContext()
76		defer cancel()
77
78		currentNode, err := getNode(ctx, state.controlClient, input)
79		if err != nil {
80			return err
81		}
82
83		_, err = state.controlClient.UpdateNode(
84			ctx,
85			&swarmapi.UpdateNodeRequest{
86				NodeID: currentNode.ID,
87				Spec:   &nodeSpec,
88				NodeVersion: &swarmapi.Version{
89					Index: version,
90				},
91			},
92		)
93		return err
94	})
95}
96
97// RemoveNode removes a node from a cluster
98func (c *Cluster) RemoveNode(input string, force bool) error {
99	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
100		node, err := getNode(ctx, state.controlClient, input)
101		if err != nil {
102			return err
103		}
104
105		_, err = state.controlClient.RemoveNode(ctx, &swarmapi.RemoveNodeRequest{NodeID: node.ID, Force: force})
106		return err
107	})
108}
109