github.com/mongey/nomad@v0.5.2/command/agent/job_endpoint.go (about) 1 package agent 2 3 import ( 4 "net/http" 5 "strconv" 6 "strings" 7 8 "github.com/hashicorp/nomad/nomad/structs" 9 ) 10 11 func (s *HTTPServer) JobsRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 12 switch req.Method { 13 case "GET": 14 return s.jobListRequest(resp, req) 15 case "PUT", "POST": 16 return s.jobUpdate(resp, req, "") 17 default: 18 return nil, CodedError(405, ErrInvalidMethod) 19 } 20 } 21 22 func (s *HTTPServer) jobListRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 23 args := structs.JobListRequest{} 24 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 25 return nil, nil 26 } 27 28 var out structs.JobListResponse 29 if err := s.agent.RPC("Job.List", &args, &out); err != nil { 30 return nil, err 31 } 32 33 setMeta(resp, &out.QueryMeta) 34 if out.Jobs == nil { 35 out.Jobs = make([]*structs.JobListStub, 0) 36 } 37 return out.Jobs, nil 38 } 39 40 func (s *HTTPServer) JobSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { 41 path := strings.TrimPrefix(req.URL.Path, "/v1/job/") 42 switch { 43 case strings.HasSuffix(path, "/evaluate"): 44 jobName := strings.TrimSuffix(path, "/evaluate") 45 return s.jobForceEvaluate(resp, req, jobName) 46 case strings.HasSuffix(path, "/allocations"): 47 jobName := strings.TrimSuffix(path, "/allocations") 48 return s.jobAllocations(resp, req, jobName) 49 case strings.HasSuffix(path, "/evaluations"): 50 jobName := strings.TrimSuffix(path, "/evaluations") 51 return s.jobEvaluations(resp, req, jobName) 52 case strings.HasSuffix(path, "/periodic/force"): 53 jobName := strings.TrimSuffix(path, "/periodic/force") 54 return s.periodicForceRequest(resp, req, jobName) 55 case strings.HasSuffix(path, "/plan"): 56 jobName := strings.TrimSuffix(path, "/plan") 57 return s.jobPlan(resp, req, jobName) 58 case strings.HasSuffix(path, "/summary"): 59 jobName := strings.TrimSuffix(path, "/summary") 60 return s.jobSummaryRequest(resp, req, jobName) 61 default: 62 return s.jobCRUD(resp, req, path) 63 } 64 } 65 66 func (s *HTTPServer) jobForceEvaluate(resp http.ResponseWriter, req *http.Request, 67 jobName string) (interface{}, error) { 68 if req.Method != "PUT" && req.Method != "POST" { 69 return nil, CodedError(405, ErrInvalidMethod) 70 } 71 args := structs.JobEvaluateRequest{ 72 JobID: jobName, 73 } 74 s.parseRegion(req, &args.Region) 75 76 var out structs.JobRegisterResponse 77 if err := s.agent.RPC("Job.Evaluate", &args, &out); err != nil { 78 return nil, err 79 } 80 setIndex(resp, out.Index) 81 return out, nil 82 } 83 84 func (s *HTTPServer) jobPlan(resp http.ResponseWriter, req *http.Request, 85 jobName string) (interface{}, error) { 86 if req.Method != "PUT" && req.Method != "POST" { 87 return nil, CodedError(405, ErrInvalidMethod) 88 } 89 90 var args structs.JobPlanRequest 91 if err := decodeBody(req, &args); err != nil { 92 return nil, CodedError(400, err.Error()) 93 } 94 if args.Job == nil { 95 return nil, CodedError(400, "Job must be specified") 96 } 97 if jobName != "" && args.Job.ID != jobName { 98 return nil, CodedError(400, "Job ID does not match") 99 } 100 s.parseRegion(req, &args.Region) 101 102 var out structs.JobPlanResponse 103 if err := s.agent.RPC("Job.Plan", &args, &out); err != nil { 104 return nil, err 105 } 106 setIndex(resp, out.Index) 107 return out, nil 108 } 109 110 func (s *HTTPServer) periodicForceRequest(resp http.ResponseWriter, req *http.Request, 111 jobName string) (interface{}, error) { 112 if req.Method != "PUT" && req.Method != "POST" { 113 return nil, CodedError(405, ErrInvalidMethod) 114 } 115 116 args := structs.PeriodicForceRequest{ 117 JobID: jobName, 118 } 119 s.parseRegion(req, &args.Region) 120 121 var out structs.PeriodicForceResponse 122 if err := s.agent.RPC("Periodic.Force", &args, &out); err != nil { 123 return nil, err 124 } 125 setIndex(resp, out.Index) 126 return out, nil 127 } 128 129 func (s *HTTPServer) jobAllocations(resp http.ResponseWriter, req *http.Request, 130 jobName string) (interface{}, error) { 131 if req.Method != "GET" { 132 return nil, CodedError(405, ErrInvalidMethod) 133 } 134 allAllocs, _ := strconv.ParseBool(req.URL.Query().Get("all")) 135 136 args := structs.JobSpecificRequest{ 137 JobID: jobName, 138 AllAllocs: allAllocs, 139 } 140 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 141 return nil, nil 142 } 143 144 var out structs.JobAllocationsResponse 145 if err := s.agent.RPC("Job.Allocations", &args, &out); err != nil { 146 return nil, err 147 } 148 149 setMeta(resp, &out.QueryMeta) 150 if out.Allocations == nil { 151 out.Allocations = make([]*structs.AllocListStub, 0) 152 } 153 return out.Allocations, nil 154 } 155 156 func (s *HTTPServer) jobEvaluations(resp http.ResponseWriter, req *http.Request, 157 jobName string) (interface{}, error) { 158 if req.Method != "GET" { 159 return nil, CodedError(405, ErrInvalidMethod) 160 } 161 args := structs.JobSpecificRequest{ 162 JobID: jobName, 163 } 164 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 165 return nil, nil 166 } 167 168 var out structs.JobEvaluationsResponse 169 if err := s.agent.RPC("Job.Evaluations", &args, &out); err != nil { 170 return nil, err 171 } 172 173 setMeta(resp, &out.QueryMeta) 174 if out.Evaluations == nil { 175 out.Evaluations = make([]*structs.Evaluation, 0) 176 } 177 return out.Evaluations, nil 178 } 179 180 func (s *HTTPServer) jobCRUD(resp http.ResponseWriter, req *http.Request, 181 jobName string) (interface{}, error) { 182 switch req.Method { 183 case "GET": 184 return s.jobQuery(resp, req, jobName) 185 case "PUT", "POST": 186 return s.jobUpdate(resp, req, jobName) 187 case "DELETE": 188 return s.jobDelete(resp, req, jobName) 189 default: 190 return nil, CodedError(405, ErrInvalidMethod) 191 } 192 } 193 194 func (s *HTTPServer) jobQuery(resp http.ResponseWriter, req *http.Request, 195 jobName string) (interface{}, error) { 196 args := structs.JobSpecificRequest{ 197 JobID: jobName, 198 } 199 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 200 return nil, nil 201 } 202 203 var out structs.SingleJobResponse 204 if err := s.agent.RPC("Job.GetJob", &args, &out); err != nil { 205 return nil, err 206 } 207 208 setMeta(resp, &out.QueryMeta) 209 if out.Job == nil { 210 return nil, CodedError(404, "job not found") 211 } 212 return out.Job, nil 213 } 214 215 func (s *HTTPServer) jobUpdate(resp http.ResponseWriter, req *http.Request, 216 jobName string) (interface{}, error) { 217 var args structs.JobRegisterRequest 218 if err := decodeBody(req, &args); err != nil { 219 return nil, CodedError(400, err.Error()) 220 } 221 if args.Job == nil { 222 return nil, CodedError(400, "Job must be specified") 223 } 224 if jobName != "" && args.Job.ID != jobName { 225 return nil, CodedError(400, "Job ID does not match") 226 } 227 s.parseRegion(req, &args.Region) 228 229 var out structs.JobRegisterResponse 230 if err := s.agent.RPC("Job.Register", &args, &out); err != nil { 231 return nil, err 232 } 233 setIndex(resp, out.Index) 234 return out, nil 235 } 236 237 func (s *HTTPServer) jobDelete(resp http.ResponseWriter, req *http.Request, 238 jobName string) (interface{}, error) { 239 args := structs.JobDeregisterRequest{ 240 JobID: jobName, 241 } 242 s.parseRegion(req, &args.Region) 243 244 var out structs.JobDeregisterResponse 245 if err := s.agent.RPC("Job.Deregister", &args, &out); err != nil { 246 return nil, err 247 } 248 setIndex(resp, out.Index) 249 return out, nil 250 } 251 252 func (s *HTTPServer) jobSummaryRequest(resp http.ResponseWriter, req *http.Request, name string) (interface{}, error) { 253 args := structs.JobSummaryRequest{ 254 JobID: name, 255 } 256 if s.parse(resp, req, &args.Region, &args.QueryOptions) { 257 return nil, nil 258 } 259 260 var out structs.JobSummaryResponse 261 if err := s.agent.RPC("Job.Summary", &args, &out); err != nil { 262 return nil, err 263 } 264 265 setMeta(resp, &out.QueryMeta) 266 if out.JobSummary == nil { 267 return nil, CodedError(404, "job not found") 268 } 269 setIndex(resp, out.Index) 270 return out.JobSummary, nil 271 }