github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/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 "github.com/hashicorp/nomad/acl" 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 if s.agent.client == nil { 83 return nil, clientNotRunning 84 } 85 86 reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/client/allocation/") 87 88 // tokenize the suffix of the path to get the alloc id and find the action 89 // invoked on the alloc id 90 tokens := strings.Split(reqSuffix, "/") 91 if len(tokens) != 2 { 92 return nil, CodedError(404, resourceNotFoundErr) 93 } 94 allocID := tokens[0] 95 switch tokens[1] { 96 case "stats": 97 return s.allocStats(allocID, resp, req) 98 case "snapshot": 99 return s.allocSnapshot(allocID, resp, req) 100 case "gc": 101 return s.allocGC(allocID, resp, req) 102 } 103 104 return nil, CodedError(404, resourceNotFoundErr) 105 } 106 107 func (s *HTTPServer) ClientGCRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 108 if s.agent.client == nil { 109 return nil, clientNotRunning 110 } 111 112 var secret string 113 s.parseToken(req, &secret) 114 115 // Check node write permissions 116 if aclObj, err := s.agent.Client().ResolveToken(secret); err != nil { 117 return nil, err 118 } else if aclObj != nil && !aclObj.AllowNodeWrite() { 119 return nil, structs.ErrPermissionDenied 120 } 121 122 s.agent.Client().CollectAllAllocs() 123 return nil, nil 124 } 125 126 func (s *HTTPServer) allocGC(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 127 var secret string 128 s.parseToken(req, &secret) 129 130 var namespace string 131 parseNamespace(req, &namespace) 132 133 // Check namespace submit-job permissions 134 if aclObj, err := s.agent.Client().ResolveToken(secret); err != nil { 135 return nil, err 136 } else if aclObj != nil && !aclObj.AllowNsOp(namespace, acl.NamespaceCapabilitySubmitJob) { 137 return nil, structs.ErrPermissionDenied 138 } 139 140 if !s.agent.Client().CollectAllocation(allocID) { 141 // Could not find alloc 142 return nil, fmt.Errorf("unable to collect allocation: not present") 143 } 144 return nil, nil 145 } 146 147 func (s *HTTPServer) allocSnapshot(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 148 var secret string 149 s.parseToken(req, &secret) 150 if !s.agent.Client().ValidateMigrateToken(allocID, secret) { 151 return nil, structs.ErrPermissionDenied 152 } 153 154 allocFS, err := s.agent.Client().GetAllocFS(allocID) 155 if err != nil { 156 return nil, fmt.Errorf(allocNotFoundErr) 157 } 158 if err := allocFS.Snapshot(resp); err != nil { 159 return nil, fmt.Errorf("error making snapshot: %v", err) 160 } 161 return nil, nil 162 } 163 164 func (s *HTTPServer) allocStats(allocID string, resp http.ResponseWriter, req *http.Request) (interface{}, error) { 165 var secret string 166 s.parseToken(req, &secret) 167 168 var namespace string 169 parseNamespace(req, &namespace) 170 171 // Check namespace read-job permissions 172 if aclObj, err := s.agent.Client().ResolveToken(secret); err != nil { 173 return nil, err 174 } else if aclObj != nil && !aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityReadJob) { 175 return nil, structs.ErrPermissionDenied 176 } 177 178 clientStats := s.agent.client.StatsReporter() 179 aStats, err := clientStats.GetAllocStats(allocID) 180 if err != nil { 181 return nil, err 182 } 183 184 task := req.URL.Query().Get("task") 185 return aStats.LatestAllocStats(task) 186 }