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  }