7 "github.com/docker/swarmkit/api"
8 "github.com/docker/swarmkit/manager/state/raft/membership"
9 "github.com/docker/swarmkit/manager/state/store"
10 gogotypes "github.com/gogo/protobuf/types"
11 "golang.org/x/net/context"
12 "google.golang.org/grpc"
13 "google.golang.org/grpc/codes"
16 func validateNodeSpec(spec *api.NodeSpec) error {
18 return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
23 // GetNode returns a Node given a NodeID.
24 // - Returns `InvalidArgument` if NodeID is not provided.
25 // - Returns `NotFound` if the Node is not found.
26 func (s *Server) GetNode(ctx context.Context, request *api.GetNodeRequest) (*api.GetNodeResponse, error) {
27 if request.NodeID == "" {
28 return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
32 s.store.View(func(tx store.ReadTx) {
33 node = store.GetNode(tx, request.NodeID)
36 return nil, grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
40 memberlist := s.raft.GetMemberlist()
41 for _, member := range memberlist {
42 if member.NodeID == node.ID {
43 node.ManagerStatus = &api.ManagerStatus{
44 RaftID: member.RaftID,
46 Leader: member.Status.Leader,
47 Reachability: member.Status.Reachability,
54 return &api.GetNodeResponse{
59 func filterNodes(candidates []*api.Node, filters ...func(*api.Node) bool) []*api.Node {
60 result := []*api.Node{}
62 for _, c := range candidates {
64 for _, f := range filters {
71 result = append(result, c)
78 // ListNodes returns a list of all nodes.
79 func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (*api.ListNodesResponse, error) {
84 s.store.View(func(tx store.ReadTx) {
86 case request.Filters != nil && len(request.Filters.Names) > 0:
87 nodes, err = store.FindNodes(tx, buildFilters(store.ByName, request.Filters.Names))
88 case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
89 nodes, err = store.FindNodes(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
90 case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
91 nodes, err = store.FindNodes(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
92 case request.Filters != nil && len(request.Filters.Roles) > 0:
93 filters := make([]store.By, 0, len(request.Filters.Roles))
94 for _, v := range request.Filters.Roles {
95 filters = append(filters, store.ByRole(v))
97 nodes, err = store.FindNodes(tx, store.Or(filters...))
98 case request.Filters != nil && len(request.Filters.Memberships) > 0:
99 filters := make([]store.By, 0, len(request.Filters.Memberships))
100 for _, v := range request.Filters.Memberships {
101 filters = append(filters, store.ByMembership(v))
103 nodes, err = store.FindNodes(tx, store.Or(filters...))
105 nodes, err = store.FindNodes(tx, store.All)
112 if request.Filters != nil {
113 nodes = filterNodes(nodes,
114 func(e *api.Node) bool {
115 if len(request.Filters.Names) == 0 {
118 if e.Description == nil {
121 return filterContains(e.Description.Hostname, request.Filters.Names)
123 func(e *api.Node) bool {
124 if len(request.Filters.NamePrefixes) == 0 {
127 if e.Description == nil {
130 return filterContainsPrefix(e.Description.Hostname, request.Filters.NamePrefixes)
132 func(e *api.Node) bool {
133 return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
135 func(e *api.Node) bool {
136 if len(request.Filters.Labels) == 0 {
139 if e.Description == nil {
142 return filterMatchLabels(e.Description.Engine.Labels, request.Filters.Labels)
144 func(e *api.Node) bool {
145 if len(request.Filters.Roles) == 0 {
148 for _, c := range request.Filters.Roles {
155 func(e *api.Node) bool {
156 if len(request.Filters.Memberships) == 0 {
159 for _, c := range request.Filters.Memberships {
160 if c == e.Spec.Membership {
169 // Add in manager information on nodes that are managers
171 memberlist := s.raft.GetMemberlist()
173 for _, node := range nodes {
174 for _, member := range memberlist {
175 if member.NodeID == node.ID {
176 node.ManagerStatus = &api.ManagerStatus{
177 RaftID: member.RaftID,
179 Leader: member.Status.Leader,
180 Reachability: member.Status.Reachability,
188 return &api.ListNodesResponse{
193 // UpdateNode updates a Node referenced by NodeID with the given NodeSpec.
194 // - Returns `NotFound` if the Node is not found.
195 // - Returns `InvalidArgument` if the NodeSpec is malformed.
196 // - Returns an error if the update fails.
197 func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest) (*api.UpdateNodeResponse, error) {
198 if request.NodeID == "" || request.NodeVersion == nil {
199 return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
201 if err := validateNodeSpec(request.Spec); err != nil {
207 member *membership.Member
210 err := s.store.Update(func(tx store.Tx) error {
211 node = store.GetNode(tx, request.NodeID)
213 return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
216 // Demotion sanity checks.
217 if node.Spec.DesiredRole == api.NodeRoleManager && request.Spec.DesiredRole == api.NodeRoleWorker {
218 // Check for manager entries in Store.
219 managers, err := store.FindNodes(tx, store.ByRole(api.NodeRoleManager))
221 return grpc.Errorf(codes.Internal, "internal store error: %v", err)
223 if len(managers) == 1 && managers[0].ID == node.ID {
224 return grpc.Errorf(codes.FailedPrecondition, "attempting to demote the last manager of the swarm")
227 // Check for node in memberlist
228 if member = s.raft.GetMemberByNodeID(request.NodeID); member == nil {
229 return grpc.Errorf(codes.NotFound, "can't find manager in raft memberlist")
233 if !s.raft.CanRemoveMember(member.RaftID) {
234 return grpc.Errorf(codes.FailedPrecondition, "can't remove member from the raft: this would result in a loss of quorum")
238 node.Meta.Version = *request.NodeVersion
239 node.Spec = *request.Spec.Copy()
240 return store.UpdateNode(tx, node)
246 return &api.UpdateNodeResponse{
251 // RemoveNode removes a Node referenced by NodeID with the given NodeSpec.
252 // - Returns NotFound if the Node is not found.
253 // - Returns FailedPrecondition if the Node has manager role (and is part of the memberlist) or is not shut down.
254 // - Returns InvalidArgument if NodeID or NodeVersion is not valid.
255 // - Returns an error if the delete fails.
256 func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest) (*api.RemoveNodeResponse, error) {
257 if request.NodeID == "" {
258 return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
261 err := s.store.Update(func(tx store.Tx) error {
262 node := store.GetNode(tx, request.NodeID)
264 return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
266 if node.Spec.DesiredRole == api.NodeRoleManager {
268 return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
270 if member := s.raft.GetMemberByNodeID(request.NodeID); member != nil {
271 return grpc.Errorf(codes.FailedPrecondition, "node %s is a cluster manager and is a member of the raft cluster. It must be demoted to worker before removal", request.NodeID)
274 if !request.Force && node.Status.State == api.NodeStatus_READY {
275 return grpc.Errorf(codes.FailedPrecondition, "node %s is not down and can't be removed", request.NodeID)
278 // lookup the cluster
279 clusters, err := store.FindClusters(tx, store.ByName("default"))
283 if len(clusters) != 1 {
284 return grpc.Errorf(codes.Internal, "could not fetch cluster object")
286 cluster := clusters[0]
288 blacklistedCert := &api.BlacklistedCertificate{}
290 // Set an expiry time for this RemovedNode if a certificate
291 // exists and can be parsed.
292 if len(node.Certificate.Certificate) != 0 {
293 certBlock, _ := pem.Decode(node.Certificate.Certificate)
294 if certBlock != nil {
295 X509Cert, err := x509.ParseCertificate(certBlock.Bytes)
296 if err == nil && !X509Cert.NotAfter.IsZero() {
297 expiry, err := gogotypes.TimestampProto(X509Cert.NotAfter)
299 blacklistedCert.Expiry = expiry
305 if cluster.BlacklistedCertificates == nil {
306 cluster.BlacklistedCertificates = make(map[string]*api.BlacklistedCertificate)
308 cluster.BlacklistedCertificates[node.ID] = blacklistedCert
310 expireBlacklistedCerts(cluster)
312 if err := store.UpdateCluster(tx, cluster); err != nil {
316 return store.DeleteNode(tx, request.NodeID)
321 return &api.RemoveNodeResponse{}, nil