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