node.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package controlapi
  2. import (
  3. "github.com/docker/swarmkit/api"
  4. "github.com/docker/swarmkit/manager/state/raft/membership"
  5. "github.com/docker/swarmkit/manager/state/store"
  6. "golang.org/x/net/context"
  7. "google.golang.org/grpc"
  8. "google.golang.org/grpc/codes"
  9. )
  10. func validateNodeSpec(spec *api.NodeSpec) error {
  11. if spec == nil {
  12. return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  13. }
  14. return nil
  15. }
  16. // GetNode returns a Node given a NodeID.
  17. // - Returns `InvalidArgument` if NodeID is not provided.
  18. // - Returns `NotFound` if the Node is not found.
  19. func (s *Server) GetNode(ctx context.Context, request *api.GetNodeRequest) (*api.GetNodeResponse, error) {
  20. if request.NodeID == "" {
  21. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  22. }
  23. var node *api.Node
  24. s.store.View(func(tx store.ReadTx) {
  25. node = store.GetNode(tx, request.NodeID)
  26. })
  27. if node == nil {
  28. return nil, grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
  29. }
  30. if s.raft != nil {
  31. memberlist := s.raft.GetMemberlist()
  32. for _, member := range memberlist {
  33. if member.NodeID == node.ID {
  34. node.ManagerStatus = &api.ManagerStatus{
  35. RaftID: member.RaftID,
  36. Addr: member.Addr,
  37. Leader: member.Status.Leader,
  38. Reachability: member.Status.Reachability,
  39. }
  40. break
  41. }
  42. }
  43. }
  44. return &api.GetNodeResponse{
  45. Node: node,
  46. }, nil
  47. }
  48. func filterNodes(candidates []*api.Node, filters ...func(*api.Node) bool) []*api.Node {
  49. result := []*api.Node{}
  50. for _, c := range candidates {
  51. match := true
  52. for _, f := range filters {
  53. if !f(c) {
  54. match = false
  55. break
  56. }
  57. }
  58. if match {
  59. result = append(result, c)
  60. }
  61. }
  62. return result
  63. }
  64. // ListNodes returns a list of all nodes.
  65. func (s *Server) ListNodes(ctx context.Context, request *api.ListNodesRequest) (*api.ListNodesResponse, error) {
  66. var (
  67. nodes []*api.Node
  68. err error
  69. )
  70. s.store.View(func(tx store.ReadTx) {
  71. switch {
  72. case request.Filters != nil && len(request.Filters.Names) > 0:
  73. nodes, err = store.FindNodes(tx, buildFilters(store.ByName, request.Filters.Names))
  74. case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
  75. nodes, err = store.FindNodes(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
  76. case request.Filters != nil && len(request.Filters.Roles) > 0:
  77. filters := make([]store.By, 0, len(request.Filters.Roles))
  78. for _, v := range request.Filters.Roles {
  79. filters = append(filters, store.ByRole(v))
  80. }
  81. nodes, err = store.FindNodes(tx, store.Or(filters...))
  82. case request.Filters != nil && len(request.Filters.Memberships) > 0:
  83. filters := make([]store.By, 0, len(request.Filters.Memberships))
  84. for _, v := range request.Filters.Memberships {
  85. filters = append(filters, store.ByMembership(v))
  86. }
  87. nodes, err = store.FindNodes(tx, store.Or(filters...))
  88. default:
  89. nodes, err = store.FindNodes(tx, store.All)
  90. }
  91. })
  92. if err != nil {
  93. return nil, err
  94. }
  95. if request.Filters != nil {
  96. nodes = filterNodes(nodes,
  97. func(e *api.Node) bool {
  98. if len(request.Filters.Names) == 0 {
  99. return true
  100. }
  101. if e.Description == nil {
  102. return false
  103. }
  104. return filterContains(e.Description.Hostname, request.Filters.Names)
  105. },
  106. func(e *api.Node) bool {
  107. return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
  108. },
  109. func(e *api.Node) bool {
  110. if len(request.Filters.Labels) == 0 {
  111. return true
  112. }
  113. if e.Description == nil {
  114. return false
  115. }
  116. return filterMatchLabels(e.Description.Engine.Labels, request.Filters.Labels)
  117. },
  118. func(e *api.Node) bool {
  119. if len(request.Filters.Roles) == 0 {
  120. return true
  121. }
  122. for _, c := range request.Filters.Roles {
  123. if c == e.Spec.Role {
  124. return true
  125. }
  126. }
  127. return false
  128. },
  129. func(e *api.Node) bool {
  130. if len(request.Filters.Memberships) == 0 {
  131. return true
  132. }
  133. for _, c := range request.Filters.Memberships {
  134. if c == e.Spec.Membership {
  135. return true
  136. }
  137. }
  138. return false
  139. },
  140. )
  141. }
  142. // Add in manager information on nodes that are managers
  143. if s.raft != nil {
  144. memberlist := s.raft.GetMemberlist()
  145. for _, node := range nodes {
  146. for _, member := range memberlist {
  147. if member.NodeID == node.ID {
  148. node.ManagerStatus = &api.ManagerStatus{
  149. RaftID: member.RaftID,
  150. Addr: member.Addr,
  151. Leader: member.Status.Leader,
  152. Reachability: member.Status.Reachability,
  153. }
  154. break
  155. }
  156. }
  157. }
  158. }
  159. return &api.ListNodesResponse{
  160. Nodes: nodes,
  161. }, nil
  162. }
  163. // UpdateNode updates a Node referenced by NodeID with the given NodeSpec.
  164. // - Returns `NotFound` if the Node is not found.
  165. // - Returns `InvalidArgument` if the NodeSpec is malformed.
  166. // - Returns an error if the update fails.
  167. func (s *Server) UpdateNode(ctx context.Context, request *api.UpdateNodeRequest) (*api.UpdateNodeResponse, error) {
  168. if request.NodeID == "" || request.NodeVersion == nil {
  169. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  170. }
  171. if err := validateNodeSpec(request.Spec); err != nil {
  172. return nil, err
  173. }
  174. var (
  175. node *api.Node
  176. member *membership.Member
  177. demote bool
  178. )
  179. err := s.store.Update(func(tx store.Tx) error {
  180. node = store.GetNode(tx, request.NodeID)
  181. if node == nil {
  182. return nil
  183. }
  184. // Demotion sanity checks.
  185. if node.Spec.Role == api.NodeRoleManager && request.Spec.Role == api.NodeRoleWorker {
  186. demote = true
  187. // Check for manager entries in Store.
  188. managers, err := store.FindNodes(tx, store.ByRole(api.NodeRoleManager))
  189. if err != nil {
  190. return grpc.Errorf(codes.Internal, "internal store error: %v", err)
  191. }
  192. if len(managers) == 1 && managers[0].ID == node.ID {
  193. return grpc.Errorf(codes.FailedPrecondition, "attempting to demote the last manager of the swarm")
  194. }
  195. // Check for node in memberlist
  196. if member = s.raft.GetMemberByNodeID(request.NodeID); member == nil {
  197. return grpc.Errorf(codes.NotFound, "can't find manager in raft memberlist")
  198. }
  199. // Quorum safeguard
  200. if !s.raft.CanRemoveMember(member.RaftID) {
  201. return grpc.Errorf(codes.FailedPrecondition, "can't remove member from the raft: this would result in a loss of quorum")
  202. }
  203. }
  204. node.Meta.Version = *request.NodeVersion
  205. node.Spec = *request.Spec.Copy()
  206. return store.UpdateNode(tx, node)
  207. })
  208. if err != nil {
  209. return nil, err
  210. }
  211. if node == nil {
  212. return nil, grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
  213. }
  214. if demote && s.raft != nil {
  215. // TODO(abronan): the remove can potentially fail and leave the node with
  216. // an incorrect role (worker rather than manager), we need to reconcile the
  217. // memberlist with the desired state rather than attempting to remove the
  218. // member once.
  219. if err := s.raft.RemoveMember(ctx, member.RaftID); err != nil {
  220. return nil, grpc.Errorf(codes.Internal, "cannot demote manager to worker: %v", err)
  221. }
  222. }
  223. return &api.UpdateNodeResponse{
  224. Node: node,
  225. }, nil
  226. }
  227. // RemoveNode updates a Node referenced by NodeID with the given NodeSpec.
  228. // - Returns NotFound if the Node is not found.
  229. // - Returns FailedPrecondition if the Node has manager role or not shut down.
  230. // - Returns InvalidArgument if NodeID or NodeVersion is not valid.
  231. // - Returns an error if the delete fails.
  232. func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest) (*api.RemoveNodeResponse, error) {
  233. if request.NodeID == "" {
  234. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  235. }
  236. if s.raft != nil {
  237. memberlist := s.raft.GetMemberlist()
  238. for _, member := range memberlist {
  239. if member.NodeID == request.NodeID {
  240. return nil, grpc.Errorf(codes.FailedPrecondition, "node %s is a cluster manager and is part of the quorum. It must be demoted to worker before removal", request.NodeID)
  241. }
  242. }
  243. }
  244. err := s.store.Update(func(tx store.Tx) error {
  245. node := store.GetNode(tx, request.NodeID)
  246. if node == nil {
  247. return grpc.Errorf(codes.NotFound, "node %s not found", request.NodeID)
  248. }
  249. if node.Spec.Role == api.NodeRoleManager {
  250. return grpc.Errorf(codes.FailedPrecondition, "node %s role is set to manager. It should be demoted to worker for safe removal", request.NodeID)
  251. }
  252. if node.Status.State == api.NodeStatus_READY {
  253. return grpc.Errorf(codes.FailedPrecondition, "node %s is not down and can't be removed", request.NodeID)
  254. }
  255. return store.DeleteNode(tx, request.NodeID)
  256. })
  257. if err != nil {
  258. return nil, err
  259. }
  260. return &api.RemoveNodeResponse{}, nil
  261. }