github.com/smintz/nomad@v0.8.3/command/agent/alloc_endpoint.go (about) 1 package agent 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 8 "github.com/golang/snappy" 9 cstructs "github.com/hashicorp/nomad/client/structs" 10 "github.com/hashicorp/nomad/nomad/structs" 11 ) 12 13 const ( 14 allocNotFoundErr = "allocation not found" 15 resourceNotFoundErr = "resource not found" 16 ) 17 18 func (s *HTTPServer) AllocsRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 19 if req.Method != "GET" { 20 return nil, CodedError(405, ErrInvalidMethod) 21 } 22 23 args := structs.AllocListRequest{} 24 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 25 return nil, nil 26 } 27 28 var out structs.AllocListResponse 29 if err := s.agent.RPC("Alloc.List", &args, &out); err != nil { 30 return nil, err 31 } 32 33 setMeta(resp, &out.QueryMeta) 34 if out.Allocations == nil { 35 out.Allocations = make([]*structs.AllocListStub, 0) 36 } 37 for _, alloc := range out.Allocations { 38 alloc.SetEventDisplayMessages() 39 } 40 return out.Allocations, nil 41 } 42 43 func (s *HTTPServer) AllocSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 44 allocID := strings.TrimPrefix(req.URL.Path, "/v1/allocation/") 45 if req.Method != "GET" { 46 return nil, CodedError(405, ErrInvalidMethod) 47 } 48 49 args := structs.AllocSpecificRequest{ 50 AllocID: allocID, 51 } 52 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 53 return nil, nil 54 } 55 56 var out structs.SingleAllocResponse 57 if err := s.agent.RPC("Alloc.GetAlloc", &args, &out); err != nil { 58 return nil, err 59 } 60 61 setMeta(resp, &out.QueryMeta) 62 if out.Alloc == nil { 63 return nil, CodedError(404, "alloc not found") 64 } 65 66 // Decode the payload if there is any 67 alloc := out.Alloc 68 if alloc.Job != nil && len(alloc.Job.Payload) != 0 { 69 decoded, err := snappy.Decode(nil, alloc.Job.Payload) 70 if err != nil { 71 return nil, err 72 } 73 alloc = alloc.Copy() 74 alloc.Job.Payload = decoded 75 } 76 alloc.SetEventDisplayMessages() 77 78 return alloc, nil 79 } 80 81 func (s *HTTPServer) ClientAllocRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 82 83 reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/client/allocation/") 84 85 // tokenize the suffix of the path to get the alloc id and find the action 86 // invoked on the alloc id 87 tokens := strings.Split(reqSuffix, "/") 88 if len(tokens) != 2 { 89 return nil, CodedError(404, resourceNotFoundErr) 90 } 91 allocID := tokens[0] 92 switch tokens[1] { 93 case "stats": 94 return s.allocStats(allocID, resp, req) 95 case "snapshot": 96 if s.agent.client == nil { 97 return nil, clientNotRunning 98 } 99 100 return s.allocSnapshot(allocID, resp, req) 101 case "gc": 102 return s.allocGC(allocID, resp, req) 103 } 104 105 return nil, CodedError(404, resourceNotFoundErr) 106 } 107 108 func (s *HTTPServer) ClientGCRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 109 // Get the requested Node ID 110 requestedNode := req.URL.Query().Get("node_id") 111 112 // Build the request and parse the ACL token 113 args := structs.NodeSpecificRequest{ 114 NodeID: requestedNode, 115 } 116 s.parse(resp, req, &args.QueryOptions.Region, &args.QueryOptions) 117 118 // Determine the handler to use 119 useLocalClient, useClientRPC, useServerRPC := s.rpcHandlerForNode(requestedNode) 120 121 // Make the RPC 122 var reply structs.GenericResponse 123 var rpcErr error 124 if useLocalClient { 125 rpcErr = s.agent.Client().ClientRPC("Allocations.GarbageCollectAll", &args, &reply) 126 } else if useClientRPC { 127 rpcErr = s.agent.Client().RPC("ClientAllocations.GarbageCollectAll", &args, &reply) 128 } else if useServerRPC { 129 rpcErr = s.agent.Server().RPC("ClientAllocations.GarbageCollectAll", &args, &reply) 130 } else { 131 rpcErr = CodedError(400, "No local Node and node_id not provided") 132 } 133 134 if rpcErr != nil { 135 if structs.IsErrNoNodeConn(rpcErr) { 136 rpcErr = CodedError(404, rpcErr.Error()) 137 } 138 } 139 140 return nil, rpcErr 141 } 142 143 func (s *HTTPServer) allocGC(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 144 // Build the request and parse the ACL token 145 args := structs.AllocSpecificRequest{ 146 AllocID: allocID, 147 } 148 s.parse(resp, req, &args.QueryOptions.Region, &args.QueryOptions) 149 150 // Determine the handler to use 151 useLocalClient, useClientRPC, useServerRPC := s.rpcHandlerForAlloc(allocID) 152 153 // Make the RPC 154 var reply structs.GenericResponse 155 var rpcErr error 156 if useLocalClient { 157 rpcErr = s.agent.Client().ClientRPC("Allocations.GarbageCollect", &args, &reply) 158 } else if useClientRPC { 159 rpcErr = s.agent.Client().RPC("ClientAllocations.GarbageCollect", &args, &reply) 160 } else if useServerRPC { 161 rpcErr = s.agent.Server().RPC("ClientAllocations.GarbageCollect", &args, &reply) 162 } else { 163 rpcErr = CodedError(400, "No local Node and node_id not provided") 164 } 165 166 if rpcErr != nil { 167 if structs.IsErrNoNodeConn(rpcErr) || structs.IsErrUnknownAllocation(rpcErr) { 168 rpcErr = CodedError(404, rpcErr.Error()) 169 } 170 } 171 172 return nil, rpcErr 173 } 174 175 func (s *HTTPServer) allocSnapshot(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 176 var secret string 177 s.parseToken(req, &secret) 178 if !s.agent.Client().ValidateMigrateToken(allocID, secret) { 179 return nil, structs.ErrPermissionDenied 180 } 181 182 allocFS, err := s.agent.Client().GetAllocFS(allocID) 183 if err != nil { 184 return nil, fmt.Errorf(allocNotFoundErr) 185 } 186 if err := allocFS.Snapshot(resp); err != nil { 187 return nil, fmt.Errorf("error making snapshot: %v", err) 188 } 189 return nil, nil 190 } 191 192 func (s *HTTPServer) allocStats(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 193 194 // Build the request and parse the ACL token 195 task := req.URL.Query().Get("task") 196 args := cstructs.AllocStatsRequest{ 197 AllocID: allocID, 198 Task: task, 199 } 200 s.parse(resp, req, &args.QueryOptions.Region, &args.QueryOptions) 201 202 // Determine the handler to use 203 useLocalClient, useClientRPC, useServerRPC := s.rpcHandlerForAlloc(allocID) 204 205 // Make the RPC 206 var reply cstructs.AllocStatsResponse 207 var rpcErr error 208 if useLocalClient { 209 rpcErr = s.agent.Client().ClientRPC("Allocations.Stats", &args, &reply) 210 } else if useClientRPC { 211 rpcErr = s.agent.Client().RPC("ClientAllocations.Stats", &args, &reply) 212 } else if useServerRPC { 213 rpcErr = s.agent.Server().RPC("ClientAllocations.Stats", &args, &reply) 214 } else { 215 rpcErr = CodedError(400, "No local Node and node_id not provided") 216 } 217 218 if rpcErr != nil { 219 if structs.IsErrNoNodeConn(rpcErr) || structs.IsErrUnknownAllocation(rpcErr) { 220 rpcErr = CodedError(404, rpcErr.Error()) 221 } 222 } 223 224 return reply.Stats, rpcErr 225 }