Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / swarmkit / manager / controlapi / node.go
1 package controlapi
2
3 import (
4         "crypto/x509"
5         "encoding/pem"
6
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"
14 )
15
16 func validateNodeSpec(spec *api.NodeSpec) error {
17         if spec == nil {
18                 return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
19         }
20         return nil
21 }
22
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())
29         }
30
31         var node *api.Node
32         s.store.View(func(tx store.ReadTx) {
33                 node = store.GetNode(tx, request.NodeID)
34         })
35         if node == nil {
36                 return nil, grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
37         }
38
39         if s.raft != nil {
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,
45                                         Addr:         member.Addr,
46                                         Leader:       member.Status.Leader,
47                                         Reachability: member.Status.Reachability,
48                                 }
49                                 break
50                         }
51                 }
52         }
53
54         return &api.GetNodeResponse{
55                 Node: node,
56         }, nil
57 }
58
59 func filterNodes(candidates []*api.Node, filters ...func(*api.Node) bool) []*api.Node {
60         result := []*api.Node{}
61
62         for _, c := range candidates {
63                 match := true
64                 for _, f := range filters {
65                         if !f(c) {
66                                 match = false
67                                 break
68                         }
69                 }
70                 if match {
71                         result = append(result, c)
72                 }
73         }
74
75         return result
76 }
77
78 // ListNodes returns a list of all nodes.
79 func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (*api.ListNodesResponse, error) {
80         var (
81                 nodes []*api.Node
82                 err   error
83         )
84         s.store.View(func(tx store.ReadTx) {
85                 switch {
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))
96                         }
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))
102                         }
103                         nodes, err = store.FindNodes(tx, store.Or(filters...))
104                 default:
105                         nodes, err = store.FindNodes(tx, store.All)
106                 }
107         })
108         if err != nil {
109                 return nil, err
110         }
111
112         if request.Filters != nil {
113                 nodes = filterNodes(nodes,
114                         func(e *api.Node) bool {
115                                 if len(request.Filters.Names) == 0 {
116                                         return true
117                                 }
118                                 if e.Description == nil {
119                                         return false
120                                 }
121                                 return filterContains(e.Description.Hostname, request.Filters.Names)
122                         },
123                         func(e *api.Node) bool {
124                                 if len(request.Filters.NamePrefixes) == 0 {
125                                         return true
126                                 }
127                                 if e.Description == nil {
128                                         return false
129                                 }
130                                 return filterContainsPrefix(e.Description.Hostname, request.Filters.NamePrefixes)
131                         },
132                         func(e *api.Node) bool {
133                                 return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
134                         },
135                         func(e *api.Node) bool {
136                                 if len(request.Filters.Labels) == 0 {
137                                         return true
138                                 }
139                                 if e.Description == nil {
140                                         return false
141                                 }
142                                 return filterMatchLabels(e.Description.Engine.Labels, request.Filters.Labels)
143                         },
144                         func(e *api.Node) bool {
145                                 if len(request.Filters.Roles) == 0 {
146                                         return true
147                                 }
148                                 for _, c := range request.Filters.Roles {
149                                         if c == e.Role {
150                                                 return true
151                                         }
152                                 }
153                                 return false
154                         },
155                         func(e *api.Node) bool {
156                                 if len(request.Filters.Memberships) == 0 {
157                                         return true
158                                 }
159                                 for _, c := range request.Filters.Memberships {
160                                         if c == e.Spec.Membership {
161                                                 return true
162                                         }
163                                 }
164                                 return false
165                         },
166                 )
167         }
168
169         // Add in manager information on nodes that are managers
170         if s.raft != nil {
171                 memberlist := s.raft.GetMemberlist()
172
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,
178                                                 Addr:         member.Addr,
179                                                 Leader:       member.Status.Leader,
180                                                 Reachability: member.Status.Reachability,
181                                         }
182                                         break
183                                 }
184                         }
185                 }
186         }
187
188         return &api.ListNodesResponse{
189                 Nodes: nodes,
190         }, nil
191 }
192
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())
200         }
201         if err := validateNodeSpec(request.Spec); err != nil {
202                 return nil, err
203         }
204
205         var (
206                 node   *api.Node
207                 member *membership.Member
208         )
209
210         err := s.store.Update(func(tx store.Tx) error {
211                 node = store.GetNode(tx, request.NodeID)
212                 if node == nil {
213                         return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
214                 }
215
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))
220                         if err != nil {
221                                 return grpc.Errorf(codes.Internal, "internal store error: %v", err)
222                         }
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")
225                         }
226
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")
230                         }
231
232                         // Quorum safeguard
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")
235                         }
236                 }
237
238                 node.Meta.Version = *request.NodeVersion
239                 node.Spec = *request.Spec.Copy()
240                 return store.UpdateNode(tx, node)
241         })
242         if err != nil {
243                 return nil, err
244         }
245
246         return &api.UpdateNodeResponse{
247                 Node: node,
248         }, nil
249 }
250
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())
259         }
260
261         err := s.store.Update(func(tx store.Tx) error {
262                 node := store.GetNode(tx, request.NodeID)
263                 if node == nil {
264                         return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
265                 }
266                 if node.Spec.DesiredRole == api.NodeRoleManager {
267                         if s.raft == nil {
268                                 return grpc.Errorf(codes.FailedPrecondition, "node %s is a manager but cannot access node information from the raft memberlist", request.NodeID)
269                         }
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)
272                         }
273                 }
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)
276                 }
277
278                 // lookup the cluster
279                 clusters, err := store.FindClusters(tx, store.ByName("default"))
280                 if err != nil {
281                         return err
282                 }
283                 if len(clusters) != 1 {
284                         return grpc.Errorf(codes.Internal, "could not fetch cluster object")
285                 }
286                 cluster := clusters[0]
287
288                 blacklistedCert := &api.BlacklistedCertificate{}
289
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)
298                                         if err == nil {
299                                                 blacklistedCert.Expiry = expiry
300                                         }
301                                 }
302                         }
303                 }
304
305                 if cluster.BlacklistedCertificates == nil {
306                         cluster.BlacklistedCertificates = make(map[string]*api.BlacklistedCertificate)
307                 }
308                 cluster.BlacklistedCertificates[node.ID] = blacklistedCert
309
310                 expireBlacklistedCerts(cluster)
311
312                 if err := store.UpdateCluster(tx, cluster); err != nil {
313                         return err
314                 }
315
316                 return store.DeleteNode(tx, request.NodeID)
317         })
318         if err != nil {
319                 return nil, err
320         }
321         return &api.RemoveNodeResponse{}, nil
322 }