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