123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- package resourceapi
- import (
- "errors"
- "time"
- "github.com/docker/swarmkit/api"
- "github.com/docker/swarmkit/ca"
- "github.com/docker/swarmkit/identity"
- "github.com/docker/swarmkit/manager/state/store"
- "github.com/docker/swarmkit/protobuf/ptypes"
- "golang.org/x/net/context"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- )
- var (
- errInvalidArgument = errors.New("invalid argument")
- )
- // ResourceAllocator handles resource allocation of cluster entities.
- type ResourceAllocator struct {
- store *store.MemoryStore
- }
- // New returns an instance of the allocator
- func New(store *store.MemoryStore) *ResourceAllocator {
- return &ResourceAllocator{store: store}
- }
- // AttachNetwork allows the node to request the resources
- // allocation needed for a network attachment on the specific node.
- // - Returns `InvalidArgument` if the Spec is malformed.
- // - Returns `NotFound` if the Network is not found.
- // - Returns `PermissionDenied` if the Network is not manually attachable.
- // - Returns an error if the creation fails.
- func (ra *ResourceAllocator) AttachNetwork(ctx context.Context, request *api.AttachNetworkRequest) (*api.AttachNetworkResponse, error) {
- nodeInfo, err := ca.RemoteNode(ctx)
- if err != nil {
- return nil, err
- }
- var network *api.Network
- ra.store.View(func(tx store.ReadTx) {
- network = store.GetNetwork(tx, request.Config.Target)
- if network == nil {
- if networks, err := store.FindNetworks(tx, store.ByName(request.Config.Target)); err == nil && len(networks) == 1 {
- network = networks[0]
- }
- }
- })
- if network == nil {
- return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.Config.Target)
- }
- if !network.Spec.Attachable {
- return nil, grpc.Errorf(codes.PermissionDenied, "network %s not manually attachable", request.Config.Target)
- }
- t := &api.Task{
- ID: identity.NewID(),
- NodeID: nodeInfo.NodeID,
- Spec: api.TaskSpec{
- Runtime: &api.TaskSpec_Attachment{
- Attachment: &api.NetworkAttachmentSpec{
- ContainerID: request.ContainerID,
- },
- },
- Networks: []*api.NetworkAttachmentConfig{
- {
- Target: network.ID,
- Addresses: request.Config.Addresses,
- },
- },
- },
- Status: api.TaskStatus{
- State: api.TaskStateNew,
- Timestamp: ptypes.MustTimestampProto(time.Now()),
- Message: "created",
- },
- DesiredState: api.TaskStateRunning,
- // TODO: Add Network attachment.
- }
- if err := ra.store.Update(func(tx store.Tx) error {
- return store.CreateTask(tx, t)
- }); err != nil {
- return nil, err
- }
- return &api.AttachNetworkResponse{AttachmentID: t.ID}, nil
- }
- // DetachNetwork allows the node to request the release of
- // the resources associated to the network attachment.
- // - Returns `InvalidArgument` if attachment ID is not provided.
- // - Returns `NotFound` if the attachment is not found.
- // - Returns an error if the deletion fails.
- func (ra *ResourceAllocator) DetachNetwork(ctx context.Context, request *api.DetachNetworkRequest) (*api.DetachNetworkResponse, error) {
- if request.AttachmentID == "" {
- return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
- }
- nodeInfo, err := ca.RemoteNode(ctx)
- if err != nil {
- return nil, err
- }
- if err := ra.store.Update(func(tx store.Tx) error {
- t := store.GetTask(tx, request.AttachmentID)
- if t == nil {
- return grpc.Errorf(codes.NotFound, "attachment %s not found", request.AttachmentID)
- }
- if t.NodeID != nodeInfo.NodeID {
- return grpc.Errorf(codes.PermissionDenied, "attachment %s doesn't belong to this node", request.AttachmentID)
- }
- return store.DeleteTask(tx, request.AttachmentID)
- }); err != nil {
- return nil, err
- }
- return &api.DetachNetworkResponse{}, nil
- }
|