github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/eval_endpoint.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/armon/go-metrics" 8 "github.com/hashicorp/nomad/nomad/structs" 9 ) 10 11 const ( 12 // DefaultDequeueTimeout is used if no dequeue timeout is provided 13 DefaultDequeueTimeout = time.Second 14 ) 15 16 // Eval endpoint is used for eval interactions 17 type Eval struct { 18 srv *Server 19 } 20 21 // GetEval is used to request information about a specific evaluation 22 func (e *Eval) GetEval(args *structs.EvalSpecificRequest, 23 reply *structs.SingleEvalResponse) error { 24 if done, err := e.srv.forward("Eval.GetEval", args, args, reply); done { 25 return err 26 } 27 defer metrics.MeasureSince([]string{"nomad", "eval", "get_eval"}, time.Now()) 28 29 // Look for the job 30 snap, err := e.srv.fsm.State().Snapshot() 31 if err != nil { 32 return err 33 } 34 out, err := snap.EvalByID(args.EvalID) 35 if err != nil { 36 return err 37 } 38 39 // Setup the output 40 if out != nil { 41 reply.Eval = out 42 reply.Index = out.ModifyIndex 43 } else { 44 // Use the last index that affected the nodes table 45 index, err := snap.Index("evals") 46 if err != nil { 47 return err 48 } 49 reply.Index = index 50 } 51 52 // Set the query response 53 e.srv.setQueryMeta(&reply.QueryMeta) 54 return nil 55 } 56 57 // Dequeue is used to dequeue a pending evaluation 58 func (e *Eval) Dequeue(args *structs.EvalDequeueRequest, 59 reply *structs.EvalDequeueResponse) error { 60 if done, err := e.srv.forward("Eval.Dequeue", args, args, reply); done { 61 return err 62 } 63 defer metrics.MeasureSince([]string{"nomad", "eval", "dequeue"}, time.Now()) 64 65 // Ensure there is at least one scheduler 66 if len(args.Schedulers) == 0 { 67 return fmt.Errorf("dequeue requires at least one scheduler type") 68 } 69 70 // Ensure there is a default timeout 71 if args.Timeout <= 0 { 72 args.Timeout = DefaultDequeueTimeout 73 } 74 75 // Attempt the dequeue 76 eval, token, err := e.srv.evalBroker.Dequeue(args.Schedulers, args.Timeout) 77 if err != nil { 78 return err 79 } 80 81 // Provide the output if any 82 if eval != nil { 83 reply.Eval = eval 84 reply.Token = token 85 } 86 87 // Set the query response 88 e.srv.setQueryMeta(&reply.QueryMeta) 89 return nil 90 } 91 92 // Ack is used to acknowledge completion of a dequeued evaluation 93 func (e *Eval) Ack(args *structs.EvalAckRequest, 94 reply *structs.GenericResponse) error { 95 if done, err := e.srv.forward("Eval.Ack", args, args, reply); done { 96 return err 97 } 98 defer metrics.MeasureSince([]string{"nomad", "eval", "ack"}, time.Now()) 99 100 // Ack the EvalID 101 if err := e.srv.evalBroker.Ack(args.EvalID, args.Token); err != nil { 102 return err 103 } 104 return nil 105 } 106 107 // NAck is used to negative acknowledge completion of a dequeued evaluation 108 func (e *Eval) Nack(args *structs.EvalAckRequest, 109 reply *structs.GenericResponse) error { 110 if done, err := e.srv.forward("Eval.Nack", args, args, reply); done { 111 return err 112 } 113 defer metrics.MeasureSince([]string{"nomad", "eval", "nack"}, time.Now()) 114 115 // Nack the EvalID 116 if err := e.srv.evalBroker.Nack(args.EvalID, args.Token); err != nil { 117 return err 118 } 119 return nil 120 } 121 122 // Update is used to perform an update of an Eval if it is outstanding. 123 func (e *Eval) Update(args *structs.EvalUpdateRequest, 124 reply *structs.GenericResponse) error { 125 if done, err := e.srv.forward("Eval.Update", args, args, reply); done { 126 return err 127 } 128 defer metrics.MeasureSince([]string{"nomad", "eval", "update"}, time.Now()) 129 130 // Ensure there is only a single update with token 131 if len(args.Evals) != 1 { 132 return fmt.Errorf("only a single eval can be updated") 133 } 134 eval := args.Evals[0] 135 136 // Verify the evaluation is outstanding, and that the tokens match. 137 token, ok := e.srv.evalBroker.Outstanding(eval.ID) 138 if !ok { 139 return fmt.Errorf("evaluation is not outstanding") 140 } 141 if args.EvalToken != token { 142 return fmt.Errorf("evaluation token does not match") 143 } 144 145 // Update via Raft 146 _, index, err := e.srv.raftApply(structs.EvalUpdateRequestType, args) 147 if err != nil { 148 return err 149 } 150 151 // Update the index 152 reply.Index = index 153 return nil 154 } 155 156 // Create is used to make a new evaluation 157 func (e *Eval) Create(args *structs.EvalUpdateRequest, 158 reply *structs.GenericResponse) error { 159 if done, err := e.srv.forward("Eval.Create", args, args, reply); done { 160 return err 161 } 162 defer metrics.MeasureSince([]string{"nomad", "eval", "create"}, time.Now()) 163 164 // Ensure there is only a single update with token 165 if len(args.Evals) != 1 { 166 return fmt.Errorf("only a single eval can be created") 167 } 168 eval := args.Evals[0] 169 170 // Verify the parent evaluation is outstanding, and that the tokens match. 171 token, ok := e.srv.evalBroker.Outstanding(eval.PreviousEval) 172 if !ok { 173 return fmt.Errorf("previous evaluation is not outstanding") 174 } 175 if args.EvalToken != token { 176 return fmt.Errorf("previous evaluation token does not match") 177 } 178 179 // Look for the eval 180 snap, err := e.srv.fsm.State().Snapshot() 181 if err != nil { 182 return err 183 } 184 out, err := snap.EvalByID(eval.ID) 185 if err != nil { 186 return err 187 } 188 if out != nil { 189 return fmt.Errorf("evaluation already exists") 190 } 191 192 // Update via Raft 193 _, index, err := e.srv.raftApply(structs.EvalUpdateRequestType, args) 194 if err != nil { 195 return err 196 } 197 198 // Update the index 199 reply.Index = index 200 return nil 201 } 202 203 // Reap is used to cleanup dead evaluations and allocations 204 func (e *Eval) Reap(args *structs.EvalDeleteRequest, 205 reply *structs.GenericResponse) error { 206 if done, err := e.srv.forward("Eval.Reap", args, args, reply); done { 207 return err 208 } 209 defer metrics.MeasureSince([]string{"nomad", "eval", "reap"}, time.Now()) 210 211 // Update via Raft 212 _, index, err := e.srv.raftApply(structs.EvalDeleteRequestType, args) 213 if err != nil { 214 return err 215 } 216 217 // Update the index 218 reply.Index = index 219 return nil 220 } 221 222 // List is used to get a list of the evaluations in the system 223 func (e *Eval) List(args *structs.EvalListRequest, 224 reply *structs.EvalListResponse) error { 225 if done, err := e.srv.forward("Eval.List", args, args, reply); done { 226 return err 227 } 228 defer metrics.MeasureSince([]string{"nomad", "eval", "list"}, time.Now()) 229 230 // Scan all the evaluations 231 snap, err := e.srv.fsm.State().Snapshot() 232 if err != nil { 233 return err 234 } 235 iter, err := snap.Evals() 236 if err != nil { 237 return err 238 } 239 240 for { 241 raw := iter.Next() 242 if raw == nil { 243 break 244 } 245 eval := raw.(*structs.Evaluation) 246 reply.Evaluations = append(reply.Evaluations, eval) 247 } 248 249 // Use the last index that affected the jobs table 250 index, err := snap.Index("evals") 251 if err != nil { 252 return err 253 } 254 reply.Index = index 255 256 // Set the query response 257 e.srv.setQueryMeta(&reply.QueryMeta) 258 return nil 259 } 260 261 // Allocations is used to list the allocations for an evaluation 262 func (e *Eval) Allocations(args *structs.EvalSpecificRequest, 263 reply *structs.EvalAllocationsResponse) error { 264 if done, err := e.srv.forward("Eval.Allocations", args, args, reply); done { 265 return err 266 } 267 defer metrics.MeasureSince([]string{"nomad", "eval", "allocations"}, time.Now()) 268 269 // Capture the allocations 270 snap, err := e.srv.fsm.State().Snapshot() 271 if err != nil { 272 return err 273 } 274 allocs, err := snap.AllocsByEval(args.EvalID) 275 if err != nil { 276 return err 277 } 278 279 // Convert to a stub 280 if len(allocs) > 0 { 281 reply.Allocations = make([]*structs.AllocListStub, 0, len(allocs)) 282 for _, alloc := range allocs { 283 reply.Allocations = append(reply.Allocations, alloc.Stub()) 284 } 285 } 286 287 // Use the last index that affected the allocs table 288 index, err := snap.Index("allocs") 289 if err != nil { 290 return err 291 } 292 reply.Index = index 293 294 // Set the query response 295 e.srv.setQueryMeta(&reply.QueryMeta) 296 return nil 297 }