github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/client_alloc_endpoint.go (about)

     1  package nomad
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	metrics "github.com/armon/go-metrics"
     8  	"github.com/hashicorp/nomad/acl"
     9  	cstructs "github.com/hashicorp/nomad/client/structs"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  )
    12  
    13  // ClientAllocations is used to forward RPC requests to the targed Nomad client's
    14  // Allocation endpoint.
    15  type ClientAllocations struct {
    16  	srv *Server
    17  }
    18  
    19  // GarbageCollectAll is used to garbage collect all allocations on a client.
    20  func (a *ClientAllocations) GarbageCollectAll(args *structs.NodeSpecificRequest, reply *structs.GenericResponse) error {
    21  	// We only allow stale reads since the only potentially stale information is
    22  	// the Node registration and the cost is fairly high for adding another hope
    23  	// in the forwarding chain.
    24  	args.QueryOptions.AllowStale = true
    25  
    26  	// Potentially forward to a different region.
    27  	if done, err := a.srv.forward("ClientAllocations.GarbageCollectAll", args, args, reply); done {
    28  		return err
    29  	}
    30  	defer metrics.MeasureSince([]string{"nomad", "client_allocations", "garbage_collect_all"}, time.Now())
    31  
    32  	// Check node read permissions
    33  	if aclObj, err := a.srv.ResolveToken(args.AuthToken); err != nil {
    34  		return err
    35  	} else if aclObj != nil && !aclObj.AllowNodeWrite() {
    36  		return structs.ErrPermissionDenied
    37  	}
    38  
    39  	// Verify the arguments.
    40  	if args.NodeID == "" {
    41  		return errors.New("missing NodeID")
    42  	}
    43  
    44  	// Make sure Node is valid and new enough to support RPC
    45  	snap, err := a.srv.State().Snapshot()
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	_, err = getNodeForRpc(snap, args.NodeID)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	// Get the connection to the client
    56  	state, ok := a.srv.getNodeConn(args.NodeID)
    57  	if !ok {
    58  		return findNodeConnAndForward(a.srv, args.NodeID, "ClientAllocations.GarbageCollectAll", args, reply)
    59  	}
    60  
    61  	// Make the RPC
    62  	return NodeRpc(state.Session, "Allocations.GarbageCollectAll", args, reply)
    63  }
    64  
    65  // GarbageCollect is used to garbage collect an allocation on a client.
    66  func (a *ClientAllocations) GarbageCollect(args *structs.AllocSpecificRequest, reply *structs.GenericResponse) error {
    67  	// We only allow stale reads since the only potentially stale information is
    68  	// the Node registration and the cost is fairly high for adding another hope
    69  	// in the forwarding chain.
    70  	args.QueryOptions.AllowStale = true
    71  
    72  	// Potentially forward to a different region.
    73  	if done, err := a.srv.forward("ClientAllocations.GarbageCollect", args, args, reply); done {
    74  		return err
    75  	}
    76  	defer metrics.MeasureSince([]string{"nomad", "client_allocations", "garbage_collect"}, time.Now())
    77  
    78  	// Check node read permissions
    79  	if aclObj, err := a.srv.ResolveToken(args.AuthToken); err != nil {
    80  		return err
    81  	} else if aclObj != nil && !aclObj.AllowNsOp(args.Namespace, acl.NamespaceCapabilitySubmitJob) {
    82  		return structs.ErrPermissionDenied
    83  	}
    84  
    85  	// Verify the arguments.
    86  	if args.AllocID == "" {
    87  		return errors.New("missing AllocID")
    88  	}
    89  
    90  	// Find the allocation
    91  	snap, err := a.srv.State().Snapshot()
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	alloc, err := snap.AllocByID(nil, args.AllocID)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	if alloc == nil {
   102  		return structs.NewErrUnknownAllocation(args.AllocID)
   103  	}
   104  
   105  	// Make sure Node is valid and new enough to support RPC
   106  	_, err = getNodeForRpc(snap, alloc.NodeID)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	// Get the connection to the client
   112  	state, ok := a.srv.getNodeConn(alloc.NodeID)
   113  	if !ok {
   114  		return findNodeConnAndForward(a.srv, alloc.NodeID, "ClientAllocations.GarbageCollect", args, reply)
   115  	}
   116  
   117  	// Make the RPC
   118  	return NodeRpc(state.Session, "Allocations.GarbageCollect", args, reply)
   119  }
   120  
   121  // Stats is used to collect allocation statistics
   122  func (a *ClientAllocations) Stats(args *cstructs.AllocStatsRequest, reply *cstructs.AllocStatsResponse) error {
   123  	// We only allow stale reads since the only potentially stale information is
   124  	// the Node registration and the cost is fairly high for adding another hope
   125  	// in the forwarding chain.
   126  	args.QueryOptions.AllowStale = true
   127  
   128  	// Potentially forward to a different region.
   129  	if done, err := a.srv.forward("ClientAllocations.Stats", args, args, reply); done {
   130  		return err
   131  	}
   132  	defer metrics.MeasureSince([]string{"nomad", "client_allocations", "stats"}, time.Now())
   133  
   134  	// Check node read permissions
   135  	if aclObj, err := a.srv.ResolveToken(args.AuthToken); err != nil {
   136  		return err
   137  	} else if aclObj != nil && !aclObj.AllowNsOp(args.Namespace, acl.NamespaceCapabilityReadJob) {
   138  		return structs.ErrPermissionDenied
   139  	}
   140  
   141  	// Verify the arguments.
   142  	if args.AllocID == "" {
   143  		return errors.New("missing AllocID")
   144  	}
   145  
   146  	// Find the allocation
   147  	snap, err := a.srv.State().Snapshot()
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	alloc, err := snap.AllocByID(nil, args.AllocID)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	if alloc == nil {
   158  		return structs.NewErrUnknownAllocation(args.AllocID)
   159  	}
   160  
   161  	// Make sure Node is valid and new enough to support RPC
   162  	_, err = getNodeForRpc(snap, alloc.NodeID)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	// Get the connection to the client
   168  	state, ok := a.srv.getNodeConn(alloc.NodeID)
   169  	if !ok {
   170  		return findNodeConnAndForward(a.srv, alloc.NodeID, "ClientAllocations.Stats", args, reply)
   171  	}
   172  
   173  	// Make the RPC
   174  	return NodeRpc(state.Session, "Allocations.Stats", args, reply)
   175  }