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 }