allocator.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package resourceapi
  2. import (
  3. "errors"
  4. "time"
  5. "github.com/docker/swarmkit/api"
  6. "github.com/docker/swarmkit/ca"
  7. "github.com/docker/swarmkit/identity"
  8. "github.com/docker/swarmkit/manager/state/store"
  9. "github.com/docker/swarmkit/protobuf/ptypes"
  10. "golang.org/x/net/context"
  11. "google.golang.org/grpc"
  12. "google.golang.org/grpc/codes"
  13. )
  14. var (
  15. errInvalidArgument = errors.New("invalid argument")
  16. )
  17. // ResourceAllocator handles resource allocation of cluster entities.
  18. type ResourceAllocator struct {
  19. store *store.MemoryStore
  20. }
  21. // New returns an instance of the allocator
  22. func New(store *store.MemoryStore) *ResourceAllocator {
  23. return &ResourceAllocator{store: store}
  24. }
  25. // AttachNetwork allows the node to request the resources
  26. // allocation needed for a network attachment on the specific node.
  27. // - Returns `InvalidArgument` if the Spec is malformed.
  28. // - Returns `NotFound` if the Network is not found.
  29. // - Returns `PermissionDenied` if the Network is not manually attachable.
  30. // - Returns an error if the creation fails.
  31. func (ra *ResourceAllocator) AttachNetwork(ctx context.Context, request *api.AttachNetworkRequest) (*api.AttachNetworkResponse, error) {
  32. nodeInfo, err := ca.RemoteNode(ctx)
  33. if err != nil {
  34. return nil, err
  35. }
  36. var network *api.Network
  37. ra.store.View(func(tx store.ReadTx) {
  38. network = store.GetNetwork(tx, request.Config.Target)
  39. if network == nil {
  40. if networks, err := store.FindNetworks(tx, store.ByName(request.Config.Target)); err == nil && len(networks) == 1 {
  41. network = networks[0]
  42. }
  43. }
  44. })
  45. if network == nil {
  46. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.Config.Target)
  47. }
  48. if !network.Spec.Attachable {
  49. return nil, grpc.Errorf(codes.PermissionDenied, "network %s not manually attachable", request.Config.Target)
  50. }
  51. t := &api.Task{
  52. ID: identity.NewID(),
  53. NodeID: nodeInfo.NodeID,
  54. Spec: api.TaskSpec{
  55. Runtime: &api.TaskSpec_Attachment{
  56. Attachment: &api.NetworkAttachmentSpec{
  57. ContainerID: request.ContainerID,
  58. },
  59. },
  60. Networks: []*api.NetworkAttachmentConfig{
  61. {
  62. Target: network.ID,
  63. Addresses: request.Config.Addresses,
  64. },
  65. },
  66. },
  67. Status: api.TaskStatus{
  68. State: api.TaskStateNew,
  69. Timestamp: ptypes.MustTimestampProto(time.Now()),
  70. Message: "created",
  71. },
  72. DesiredState: api.TaskStateRunning,
  73. // TODO: Add Network attachment.
  74. }
  75. if err := ra.store.Update(func(tx store.Tx) error {
  76. return store.CreateTask(tx, t)
  77. }); err != nil {
  78. return nil, err
  79. }
  80. return &api.AttachNetworkResponse{AttachmentID: t.ID}, nil
  81. }
  82. // DetachNetwork allows the node to request the release of
  83. // the resources associated to the network attachment.
  84. // - Returns `InvalidArgument` if attachment ID is not provided.
  85. // - Returns `NotFound` if the attachment is not found.
  86. // - Returns an error if the deletion fails.
  87. func (ra *ResourceAllocator) DetachNetwork(ctx context.Context, request *api.DetachNetworkRequest) (*api.DetachNetworkResponse, error) {
  88. if request.AttachmentID == "" {
  89. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  90. }
  91. nodeInfo, err := ca.RemoteNode(ctx)
  92. if err != nil {
  93. return nil, err
  94. }
  95. if err := ra.store.Update(func(tx store.Tx) error {
  96. t := store.GetTask(tx, request.AttachmentID)
  97. if t == nil {
  98. return grpc.Errorf(codes.NotFound, "attachment %s not found", request.AttachmentID)
  99. }
  100. if t.NodeID != nodeInfo.NodeID {
  101. return grpc.Errorf(codes.PermissionDenied, "attachment %s doesn't belong to this node", request.AttachmentID)
  102. }
  103. return store.DeleteTask(tx, request.AttachmentID)
  104. }); err != nil {
  105. return nil, err
  106. }
  107. return &api.DetachNetworkResponse{}, nil
  108. }