github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/fsm.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "io" 6 "log" 7 "reflect" 8 "sync" 9 "time" 10 11 "github.com/armon/go-metrics" 12 memdb "github.com/hashicorp/go-memdb" 13 "github.com/hashicorp/nomad/helper/uuid" 14 "github.com/hashicorp/nomad/nomad/state" 15 "github.com/hashicorp/nomad/nomad/structs" 16 "github.com/hashicorp/nomad/scheduler" 17 "github.com/hashicorp/raft" 18 "github.com/ugorji/go/codec" 19 ) 20 21 const ( 22 // timeTableGranularity is the granularity of index to time tracking 23 timeTableGranularity = 5 * time.Minute 24 25 // timeTableLimit is the maximum limit of our tracking 26 timeTableLimit = 72 * time.Hour 27 ) 28 29 // SnapshotType is prefixed to a record in the FSM snapshot 30 // so that we can determine the type for restore 31 type SnapshotType byte 32 33 const ( 34 NodeSnapshot SnapshotType = iota 35 JobSnapshot 36 IndexSnapshot 37 EvalSnapshot 38 AllocSnapshot 39 TimeTableSnapshot 40 PeriodicLaunchSnapshot 41 JobSummarySnapshot 42 VaultAccessorSnapshot 43 JobVersionSnapshot 44 DeploymentSnapshot 45 ACLPolicySnapshot 46 ACLTokenSnapshot 47 ) 48 49 // LogApplier is the definition of a function that can apply a Raft log 50 type LogApplier func(buf []byte, index uint64) interface{} 51 52 // LogAppliers is a mapping of the Raft MessageType to the appropriate log 53 // applier 54 type LogAppliers map[structs.MessageType]LogApplier 55 56 // SnapshotRestorer is the definition of a function that can apply a Raft log 57 type SnapshotRestorer func(restore *state.StateRestore, dec *codec.Decoder) error 58 59 // SnapshotRestorers is a mapping of the SnapshotType to the appropriate 60 // snapshot restorer. 61 type SnapshotRestorers map[SnapshotType]SnapshotRestorer 62 63 // nomadFSM implements a finite state machine that is used 64 // along with Raft to provide strong consistency. We implement 65 // this outside the Server to avoid exposing this outside the package. 66 type nomadFSM struct { 67 evalBroker *EvalBroker 68 blockedEvals *BlockedEvals 69 periodicDispatcher *PeriodicDispatch 70 logger *log.Logger 71 state *state.StateStore 72 timetable *TimeTable 73 74 // config is the FSM config 75 config *FSMConfig 76 77 // enterpriseAppliers holds the set of enterprise only LogAppliers 78 enterpriseAppliers LogAppliers 79 80 // enterpriseRestorers holds the set of enterprise only snapshot restorers 81 enterpriseRestorers SnapshotRestorers 82 83 // stateLock is only used to protect outside callers to State() from 84 // racing with Restore(), which is called by Raft (it puts in a totally 85 // new state store). Everything internal here is synchronized by the 86 // Raft side, so doesn't need to lock this. 87 stateLock sync.RWMutex 88 } 89 90 // nomadSnapshot is used to provide a snapshot of the current 91 // state in a way that can be accessed concurrently with operations 92 // that may modify the live state. 93 type nomadSnapshot struct { 94 snap *state.StateSnapshot 95 timetable *TimeTable 96 } 97 98 // snapshotHeader is the first entry in our snapshot 99 type snapshotHeader struct { 100 } 101 102 // FSMConfig is used to configure the FSM 103 type FSMConfig struct { 104 // EvalBroker is the evaluation broker evaluations should be added to 105 EvalBroker *EvalBroker 106 107 // Periodic is the periodic job dispatcher that periodic jobs should be 108 // added/removed from 109 Periodic *PeriodicDispatch 110 111 // BlockedEvals is the blocked eval tracker that blocked evaluations should 112 // be added to. 113 Blocked *BlockedEvals 114 115 // LogOutput is the writer logs should be written to 116 LogOutput io.Writer 117 118 // Region is the region of the server embedding the FSM 119 Region string 120 } 121 122 // NewFSMPath is used to construct a new FSM with a blank state 123 func NewFSM(config *FSMConfig) (*nomadFSM, error) { 124 // Create a state store 125 sconfig := &state.StateStoreConfig{ 126 LogOutput: config.LogOutput, 127 Region: config.Region, 128 } 129 state, err := state.NewStateStore(sconfig) 130 if err != nil { 131 return nil, err 132 } 133 134 fsm := &nomadFSM{ 135 evalBroker: config.EvalBroker, 136 periodicDispatcher: config.Periodic, 137 blockedEvals: config.Blocked, 138 logger: log.New(config.LogOutput, "", log.LstdFlags|log.Lmicroseconds), 139 config: config, 140 state: state, 141 timetable: NewTimeTable(timeTableGranularity, timeTableLimit), 142 enterpriseAppliers: make(map[structs.MessageType]LogApplier, 8), 143 enterpriseRestorers: make(map[SnapshotType]SnapshotRestorer, 8), 144 } 145 146 // Register all the log applier functions 147 fsm.registerLogAppliers() 148 149 // Register all the snapshot restorer functions 150 fsm.registerSnapshotRestorers() 151 152 return fsm, nil 153 } 154 155 // Close is used to cleanup resources associated with the FSM 156 func (n *nomadFSM) Close() error { 157 return nil 158 } 159 160 // State is used to return a handle to the current state 161 func (n *nomadFSM) State() *state.StateStore { 162 n.stateLock.RLock() 163 defer n.stateLock.RUnlock() 164 return n.state 165 } 166 167 // TimeTable returns the time table of transactions 168 func (n *nomadFSM) TimeTable() *TimeTable { 169 return n.timetable 170 } 171 172 func (n *nomadFSM) Apply(log *raft.Log) interface{} { 173 buf := log.Data 174 msgType := structs.MessageType(buf[0]) 175 176 // Witness this write 177 n.timetable.Witness(log.Index, time.Now().UTC()) 178 179 // Check if this message type should be ignored when unknown. This is 180 // used so that new commands can be added with developer control if older 181 // versions can safely ignore the command, or if they should crash. 182 ignoreUnknown := false 183 if msgType&structs.IgnoreUnknownTypeFlag == structs.IgnoreUnknownTypeFlag { 184 msgType &= ^structs.IgnoreUnknownTypeFlag 185 ignoreUnknown = true 186 } 187 188 switch msgType { 189 case structs.NodeRegisterRequestType: 190 return n.applyUpsertNode(buf[1:], log.Index) 191 case structs.NodeDeregisterRequestType: 192 return n.applyDeregisterNode(buf[1:], log.Index) 193 case structs.NodeUpdateStatusRequestType: 194 return n.applyStatusUpdate(buf[1:], log.Index) 195 case structs.NodeUpdateDrainRequestType: 196 return n.applyDrainUpdate(buf[1:], log.Index) 197 case structs.JobRegisterRequestType: 198 return n.applyUpsertJob(buf[1:], log.Index) 199 case structs.JobDeregisterRequestType: 200 return n.applyDeregisterJob(buf[1:], log.Index) 201 case structs.EvalUpdateRequestType: 202 return n.applyUpdateEval(buf[1:], log.Index) 203 case structs.EvalDeleteRequestType: 204 return n.applyDeleteEval(buf[1:], log.Index) 205 case structs.AllocUpdateRequestType: 206 return n.applyAllocUpdate(buf[1:], log.Index) 207 case structs.AllocClientUpdateRequestType: 208 return n.applyAllocClientUpdate(buf[1:], log.Index) 209 case structs.ReconcileJobSummariesRequestType: 210 return n.applyReconcileSummaries(buf[1:], log.Index) 211 case structs.VaultAccessorRegisterRequestType: 212 return n.applyUpsertVaultAccessor(buf[1:], log.Index) 213 case structs.VaultAccessorDeregisterRequestType: 214 return n.applyDeregisterVaultAccessor(buf[1:], log.Index) 215 case structs.ApplyPlanResultsRequestType: 216 return n.applyPlanResults(buf[1:], log.Index) 217 case structs.DeploymentStatusUpdateRequestType: 218 return n.applyDeploymentStatusUpdate(buf[1:], log.Index) 219 case structs.DeploymentPromoteRequestType: 220 return n.applyDeploymentPromotion(buf[1:], log.Index) 221 case structs.DeploymentAllocHealthRequestType: 222 return n.applyDeploymentAllocHealth(buf[1:], log.Index) 223 case structs.DeploymentDeleteRequestType: 224 return n.applyDeploymentDelete(buf[1:], log.Index) 225 case structs.JobStabilityRequestType: 226 return n.applyJobStability(buf[1:], log.Index) 227 case structs.ACLPolicyUpsertRequestType: 228 return n.applyACLPolicyUpsert(buf[1:], log.Index) 229 case structs.ACLPolicyDeleteRequestType: 230 return n.applyACLPolicyDelete(buf[1:], log.Index) 231 case structs.ACLTokenUpsertRequestType: 232 return n.applyACLTokenUpsert(buf[1:], log.Index) 233 case structs.ACLTokenDeleteRequestType: 234 return n.applyACLTokenDelete(buf[1:], log.Index) 235 case structs.ACLTokenBootstrapRequestType: 236 return n.applyACLTokenBootstrap(buf[1:], log.Index) 237 case structs.AutopilotRequestType: 238 return n.applyAutopilotUpdate(buf[1:], log.Index) 239 case structs.UpsertNodeEventsType: 240 return n.applyUpsertNodeEvent(buf[1:], log.Index) 241 case structs.JobBatchDeregisterRequestType: 242 return n.applyBatchDeregisterJob(buf[1:], log.Index) 243 case structs.AllocUpdateDesiredTransitionRequestType: 244 return n.applyAllocUpdateDesiredTransition(buf[1:], log.Index) 245 case structs.NodeUpdateEligibilityRequestType: 246 return n.applyNodeEligibilityUpdate(buf[1:], log.Index) 247 case structs.BatchNodeUpdateDrainRequestType: 248 return n.applyBatchDrainUpdate(buf[1:], log.Index) 249 } 250 251 // Check enterprise only message types. 252 if applier, ok := n.enterpriseAppliers[msgType]; ok { 253 return applier(buf[1:], log.Index) 254 } 255 256 // We didn't match anything, either panic or ignore 257 if ignoreUnknown { 258 n.logger.Printf("[WARN] nomad.fsm: ignoring unknown message type (%d), upgrade to newer version", msgType) 259 return nil 260 } 261 262 panic(fmt.Errorf("failed to apply request: %#v", buf)) 263 } 264 265 func (n *nomadFSM) applyUpsertNode(buf []byte, index uint64) interface{} { 266 defer metrics.MeasureSince([]string{"nomad", "fsm", "register_node"}, time.Now()) 267 var req structs.NodeRegisterRequest 268 if err := structs.Decode(buf, &req); err != nil { 269 panic(fmt.Errorf("failed to decode request: %v", err)) 270 } 271 272 // Handle upgrade paths 273 req.Node.Canonicalize() 274 275 if err := n.state.UpsertNode(index, req.Node); err != nil { 276 n.logger.Printf("[ERR] nomad.fsm: UpsertNode failed: %v", err) 277 return err 278 } 279 280 // Unblock evals for the nodes computed node class if it is in a ready 281 // state. 282 if req.Node.Status == structs.NodeStatusReady { 283 n.blockedEvals.Unblock(req.Node.ComputedClass, index) 284 } 285 286 return nil 287 } 288 289 func (n *nomadFSM) applyDeregisterNode(buf []byte, index uint64) interface{} { 290 defer metrics.MeasureSince([]string{"nomad", "fsm", "deregister_node"}, time.Now()) 291 var req structs.NodeDeregisterRequest 292 if err := structs.Decode(buf, &req); err != nil { 293 panic(fmt.Errorf("failed to decode request: %v", err)) 294 } 295 296 if err := n.state.DeleteNode(index, req.NodeID); err != nil { 297 n.logger.Printf("[ERR] nomad.fsm: DeleteNode failed: %v", err) 298 return err 299 } 300 return nil 301 } 302 303 func (n *nomadFSM) applyStatusUpdate(buf []byte, index uint64) interface{} { 304 defer metrics.MeasureSince([]string{"nomad", "fsm", "node_status_update"}, time.Now()) 305 var req structs.NodeUpdateStatusRequest 306 if err := structs.Decode(buf, &req); err != nil { 307 panic(fmt.Errorf("failed to decode request: %v", err)) 308 } 309 310 if err := n.state.UpdateNodeStatus(index, req.NodeID, req.Status, req.NodeEvent); err != nil { 311 n.logger.Printf("[ERR] nomad.fsm: UpdateNodeStatus failed: %v", err) 312 return err 313 } 314 315 // Unblock evals for the nodes computed node class if it is in a ready 316 // state. 317 if req.Status == structs.NodeStatusReady { 318 ws := memdb.NewWatchSet() 319 node, err := n.state.NodeByID(ws, req.NodeID) 320 if err != nil { 321 n.logger.Printf("[ERR] nomad.fsm: looking up node %q failed: %v", req.NodeID, err) 322 return err 323 324 } 325 n.blockedEvals.Unblock(node.ComputedClass, index) 326 } 327 328 return nil 329 } 330 331 func (n *nomadFSM) applyDrainUpdate(buf []byte, index uint64) interface{} { 332 defer metrics.MeasureSince([]string{"nomad", "fsm", "node_drain_update"}, time.Now()) 333 var req structs.NodeUpdateDrainRequest 334 if err := structs.Decode(buf, &req); err != nil { 335 panic(fmt.Errorf("failed to decode request: %v", err)) 336 } 337 338 // COMPAT Remove in version 0.10 339 // As part of Nomad 0.8 we have deprecated the drain boolean in favor of a 340 // drain strategy but we need to handle the upgrade path where the Raft log 341 // contains drain updates with just the drain boolean being manipulated. 342 if req.Drain && req.DrainStrategy == nil { 343 // Mark the drain strategy as a force to imitate the old style drain 344 // functionality. 345 req.DrainStrategy = &structs.DrainStrategy{ 346 DrainSpec: structs.DrainSpec{ 347 Deadline: -1 * time.Second, 348 }, 349 } 350 } 351 352 if err := n.state.UpdateNodeDrain(index, req.NodeID, req.DrainStrategy, req.MarkEligible, req.NodeEvent); err != nil { 353 n.logger.Printf("[ERR] nomad.fsm: UpdateNodeDrain failed: %v", err) 354 return err 355 } 356 return nil 357 } 358 359 func (n *nomadFSM) applyBatchDrainUpdate(buf []byte, index uint64) interface{} { 360 defer metrics.MeasureSince([]string{"nomad", "fsm", "batch_node_drain_update"}, time.Now()) 361 var req structs.BatchNodeUpdateDrainRequest 362 if err := structs.Decode(buf, &req); err != nil { 363 panic(fmt.Errorf("failed to decode request: %v", err)) 364 } 365 366 if err := n.state.BatchUpdateNodeDrain(index, req.Updates, req.NodeEvents); err != nil { 367 n.logger.Printf("[ERR] nomad.fsm: BatchUpdateNodeDrain failed: %v", err) 368 return err 369 } 370 return nil 371 } 372 373 func (n *nomadFSM) applyNodeEligibilityUpdate(buf []byte, index uint64) interface{} { 374 defer metrics.MeasureSince([]string{"nomad", "fsm", "node_eligibility_update"}, time.Now()) 375 var req structs.NodeUpdateEligibilityRequest 376 if err := structs.Decode(buf, &req); err != nil { 377 panic(fmt.Errorf("failed to decode request: %v", err)) 378 } 379 380 // Lookup the existing node 381 node, err := n.state.NodeByID(nil, req.NodeID) 382 if err != nil { 383 n.logger.Printf("[ERR] nomad.fsm: UpdateNodeEligibility failed to lookup node %q: %v", req.NodeID, err) 384 return err 385 } 386 387 if err := n.state.UpdateNodeEligibility(index, req.NodeID, req.Eligibility, req.NodeEvent); err != nil { 388 n.logger.Printf("[ERR] nomad.fsm: UpdateNodeEligibility failed: %v", err) 389 return err 390 } 391 392 // Unblock evals for the nodes computed node class if it is in a ready 393 // state. 394 if node != nil && node.SchedulingEligibility == structs.NodeSchedulingIneligible && 395 req.Eligibility == structs.NodeSchedulingEligible { 396 n.blockedEvals.Unblock(node.ComputedClass, index) 397 } 398 399 return nil 400 } 401 402 func (n *nomadFSM) applyUpsertJob(buf []byte, index uint64) interface{} { 403 defer metrics.MeasureSince([]string{"nomad", "fsm", "register_job"}, time.Now()) 404 var req structs.JobRegisterRequest 405 if err := structs.Decode(buf, &req); err != nil { 406 panic(fmt.Errorf("failed to decode request: %v", err)) 407 } 408 409 /* Handle upgrade paths: 410 * - Empty maps and slices should be treated as nil to avoid 411 * un-intended destructive updates in scheduler since we use 412 * reflect.DeepEqual. Starting Nomad 0.4.1, job submission sanitizes 413 * the incoming job. 414 * - Migrate from old style upgrade stanza that used only a stagger. 415 */ 416 req.Job.Canonicalize() 417 418 if err := n.state.UpsertJob(index, req.Job); err != nil { 419 n.logger.Printf("[ERR] nomad.fsm: UpsertJob failed: %v", err) 420 return err 421 } 422 423 // We always add the job to the periodic dispatcher because there is the 424 // possibility that the periodic spec was removed and then we should stop 425 // tracking it. 426 if err := n.periodicDispatcher.Add(req.Job); err != nil { 427 n.logger.Printf("[ERR] nomad.fsm: periodicDispatcher.Add failed: %v", err) 428 return fmt.Errorf("failed adding job to periodic dispatcher: %v", err) 429 } 430 431 // Create a watch set 432 ws := memdb.NewWatchSet() 433 434 // If it is an active periodic job, record the time it was inserted. This is 435 // necessary for recovering during leader election. It is possible that from 436 // the time it is added to when it was suppose to launch, leader election 437 // occurs and the job was not launched. In this case, we use the insertion 438 // time to determine if a launch was missed. 439 if req.Job.IsPeriodicActive() { 440 prevLaunch, err := n.state.PeriodicLaunchByID(ws, req.Namespace, req.Job.ID) 441 if err != nil { 442 n.logger.Printf("[ERR] nomad.fsm: PeriodicLaunchByID failed: %v", err) 443 return err 444 } 445 446 // Record the insertion time as a launch. We overload the launch table 447 // such that the first entry is the insertion time. 448 if prevLaunch == nil { 449 launch := &structs.PeriodicLaunch{ 450 ID: req.Job.ID, 451 Namespace: req.Namespace, 452 Launch: time.Now(), 453 } 454 if err := n.state.UpsertPeriodicLaunch(index, launch); err != nil { 455 n.logger.Printf("[ERR] nomad.fsm: UpsertPeriodicLaunch failed: %v", err) 456 return err 457 } 458 } 459 } 460 461 // Check if the parent job is periodic and mark the launch time. 462 parentID := req.Job.ParentID 463 if parentID != "" { 464 parent, err := n.state.JobByID(ws, req.Namespace, parentID) 465 if err != nil { 466 n.logger.Printf("[ERR] nomad.fsm: JobByID(%v) lookup for parent failed: %v", parentID, err) 467 return err 468 } else if parent == nil { 469 // The parent has been deregistered. 470 return nil 471 } 472 473 if parent.IsPeriodic() && !parent.IsParameterized() { 474 t, err := n.periodicDispatcher.LaunchTime(req.Job.ID) 475 if err != nil { 476 n.logger.Printf("[ERR] nomad.fsm: LaunchTime(%v) failed: %v", req.Job.ID, err) 477 return err 478 } 479 480 launch := &structs.PeriodicLaunch{ 481 ID: parentID, 482 Namespace: req.Namespace, 483 Launch: t, 484 } 485 if err := n.state.UpsertPeriodicLaunch(index, launch); err != nil { 486 n.logger.Printf("[ERR] nomad.fsm: UpsertPeriodicLaunch failed: %v", err) 487 return err 488 } 489 } 490 } 491 492 return nil 493 } 494 495 func (n *nomadFSM) applyDeregisterJob(buf []byte, index uint64) interface{} { 496 defer metrics.MeasureSince([]string{"nomad", "fsm", "deregister_job"}, time.Now()) 497 var req structs.JobDeregisterRequest 498 if err := structs.Decode(buf, &req); err != nil { 499 panic(fmt.Errorf("failed to decode request: %v", err)) 500 } 501 502 if err := n.handleJobDeregister(index, req.JobID, req.Namespace, req.Purge); err != nil { 503 n.logger.Printf("[ERR] nomad.fsm: deregistering job failed: %v", err) 504 return err 505 } 506 507 return nil 508 } 509 510 func (n *nomadFSM) applyBatchDeregisterJob(buf []byte, index uint64) interface{} { 511 defer metrics.MeasureSince([]string{"nomad", "fsm", "batch_deregister_job"}, time.Now()) 512 var req structs.JobBatchDeregisterRequest 513 if err := structs.Decode(buf, &req); err != nil { 514 panic(fmt.Errorf("failed to decode request: %v", err)) 515 } 516 517 for jobNS, options := range req.Jobs { 518 if err := n.handleJobDeregister(index, jobNS.ID, jobNS.Namespace, options.Purge); err != nil { 519 n.logger.Printf("[ERR] nomad.fsm: deregistering %v failed: %v", jobNS, err) 520 return err 521 } 522 } 523 524 return n.upsertEvals(index, req.Evals) 525 } 526 527 // handleJobDeregister is used to deregister a job. 528 func (n *nomadFSM) handleJobDeregister(index uint64, jobID, namespace string, purge bool) error { 529 // If it is periodic remove it from the dispatcher 530 if err := n.periodicDispatcher.Remove(namespace, jobID); err != nil { 531 n.logger.Printf("[ERR] nomad.fsm: periodicDispatcher.Remove failed: %v", err) 532 return err 533 } 534 535 if purge { 536 if err := n.state.DeleteJob(index, namespace, jobID); err != nil { 537 n.logger.Printf("[ERR] nomad.fsm: DeleteJob failed: %v", err) 538 return err 539 } 540 541 // We always delete from the periodic launch table because it is possible that 542 // the job was updated to be non-periodic, thus checking if it is periodic 543 // doesn't ensure we clean it up properly. 544 n.state.DeletePeriodicLaunch(index, namespace, jobID) 545 } else { 546 // Get the current job and mark it as stopped and re-insert it. 547 ws := memdb.NewWatchSet() 548 current, err := n.state.JobByID(ws, namespace, jobID) 549 if err != nil { 550 n.logger.Printf("[ERR] nomad.fsm: JobByID lookup failed: %v", err) 551 return err 552 } 553 554 if current == nil { 555 return fmt.Errorf("job %q in namespace %q doesn't exist to be deregistered", jobID, namespace) 556 } 557 558 stopped := current.Copy() 559 stopped.Stop = true 560 561 if err := n.state.UpsertJob(index, stopped); err != nil { 562 n.logger.Printf("[ERR] nomad.fsm: UpsertJob failed: %v", err) 563 return err 564 } 565 } 566 567 return nil 568 } 569 570 func (n *nomadFSM) applyUpdateEval(buf []byte, index uint64) interface{} { 571 defer metrics.MeasureSince([]string{"nomad", "fsm", "update_eval"}, time.Now()) 572 var req structs.EvalUpdateRequest 573 if err := structs.Decode(buf, &req); err != nil { 574 panic(fmt.Errorf("failed to decode request: %v", err)) 575 } 576 return n.upsertEvals(index, req.Evals) 577 } 578 579 func (n *nomadFSM) upsertEvals(index uint64, evals []*structs.Evaluation) error { 580 if err := n.state.UpsertEvals(index, evals); err != nil { 581 n.logger.Printf("[ERR] nomad.fsm: UpsertEvals failed: %v", err) 582 return err 583 } 584 585 n.handleUpsertedEvals(evals) 586 return nil 587 } 588 589 // handleUpsertingEval is a helper for taking action after upserting 590 // evaluations. 591 func (n *nomadFSM) handleUpsertedEvals(evals []*structs.Evaluation) { 592 for _, eval := range evals { 593 n.handleUpsertedEval(eval) 594 } 595 } 596 597 // handleUpsertingEval is a helper for taking action after upserting an eval. 598 func (n *nomadFSM) handleUpsertedEval(eval *structs.Evaluation) { 599 if eval == nil { 600 return 601 } 602 603 if eval.ShouldEnqueue() { 604 n.evalBroker.Enqueue(eval) 605 } else if eval.ShouldBlock() { 606 n.blockedEvals.Block(eval) 607 } else if eval.Status == structs.EvalStatusComplete && 608 len(eval.FailedTGAllocs) == 0 { 609 // If we have a successful evaluation for a node, untrack any 610 // blocked evaluation 611 n.blockedEvals.Untrack(eval.JobID) 612 } 613 } 614 615 func (n *nomadFSM) applyDeleteEval(buf []byte, index uint64) interface{} { 616 defer metrics.MeasureSince([]string{"nomad", "fsm", "delete_eval"}, time.Now()) 617 var req structs.EvalDeleteRequest 618 if err := structs.Decode(buf, &req); err != nil { 619 panic(fmt.Errorf("failed to decode request: %v", err)) 620 } 621 622 if err := n.state.DeleteEval(index, req.Evals, req.Allocs); err != nil { 623 n.logger.Printf("[ERR] nomad.fsm: DeleteEval failed: %v", err) 624 return err 625 } 626 return nil 627 } 628 629 func (n *nomadFSM) applyAllocUpdate(buf []byte, index uint64) interface{} { 630 defer metrics.MeasureSince([]string{"nomad", "fsm", "alloc_update"}, time.Now()) 631 var req structs.AllocUpdateRequest 632 if err := structs.Decode(buf, &req); err != nil { 633 panic(fmt.Errorf("failed to decode request: %v", err)) 634 } 635 636 // Attach the job to all the allocations. It is pulled out in the 637 // payload to avoid the redundancy of encoding, but should be denormalized 638 // prior to being inserted into MemDB. 639 structs.DenormalizeAllocationJobs(req.Job, req.Alloc) 640 641 // Calculate the total resources of allocations. It is pulled out in the 642 // payload to avoid encoding something that can be computed, but should be 643 // denormalized prior to being inserted into MemDB. 644 for _, alloc := range req.Alloc { 645 if alloc.Resources != nil { 646 // COMPAT 0.4.1 -> 0.5 647 // Set the shared resources for allocations which don't have them 648 if alloc.SharedResources == nil { 649 alloc.SharedResources = &structs.Resources{ 650 DiskMB: alloc.Resources.DiskMB, 651 } 652 } 653 654 continue 655 } 656 657 alloc.Resources = new(structs.Resources) 658 for _, task := range alloc.TaskResources { 659 alloc.Resources.Add(task) 660 } 661 662 // Add the shared resources 663 alloc.Resources.Add(alloc.SharedResources) 664 } 665 666 if err := n.state.UpsertAllocs(index, req.Alloc); err != nil { 667 n.logger.Printf("[ERR] nomad.fsm: UpsertAllocs failed: %v", err) 668 return err 669 } 670 return nil 671 } 672 673 func (n *nomadFSM) applyAllocClientUpdate(buf []byte, index uint64) interface{} { 674 defer metrics.MeasureSince([]string{"nomad", "fsm", "alloc_client_update"}, time.Now()) 675 var req structs.AllocUpdateRequest 676 if err := structs.Decode(buf, &req); err != nil { 677 panic(fmt.Errorf("failed to decode request: %v", err)) 678 } 679 if len(req.Alloc) == 0 { 680 return nil 681 } 682 683 // Create a watch set 684 ws := memdb.NewWatchSet() 685 686 // Updating the allocs with the job id and task group name 687 for _, alloc := range req.Alloc { 688 if existing, _ := n.state.AllocByID(ws, alloc.ID); existing != nil { 689 alloc.JobID = existing.JobID 690 alloc.TaskGroup = existing.TaskGroup 691 } 692 } 693 694 // Update all the client allocations 695 if err := n.state.UpdateAllocsFromClient(index, req.Alloc); err != nil { 696 n.logger.Printf("[ERR] nomad.fsm: UpdateAllocFromClient failed: %v", err) 697 return err 698 } 699 700 // Update any evals 701 if len(req.Evals) > 0 { 702 if err := n.upsertEvals(index, req.Evals); err != nil { 703 n.logger.Printf("[ERR] nomad.fsm: applyAllocClientUpdate failed to update evaluations: %v", err) 704 return err 705 } 706 } 707 708 // Unblock evals for the nodes computed node class if the client has 709 // finished running an allocation. 710 for _, alloc := range req.Alloc { 711 if alloc.ClientStatus == structs.AllocClientStatusComplete || 712 alloc.ClientStatus == structs.AllocClientStatusFailed { 713 nodeID := alloc.NodeID 714 node, err := n.state.NodeByID(ws, nodeID) 715 if err != nil || node == nil { 716 n.logger.Printf("[ERR] nomad.fsm: looking up node %q failed: %v", nodeID, err) 717 return err 718 719 } 720 721 // Unblock any associated quota 722 quota, err := n.allocQuota(alloc.ID) 723 if err != nil { 724 n.logger.Printf("[ERR] nomad.fsm: looking up quota associated with alloc %q failed: %v", alloc.ID, err) 725 return err 726 } 727 728 n.blockedEvals.UnblockClassAndQuota(node.ComputedClass, quota, index) 729 } 730 } 731 732 return nil 733 } 734 735 // applyAllocUpdateDesiredTransition is used to update the desired transitions 736 // of a set of allocations. 737 func (n *nomadFSM) applyAllocUpdateDesiredTransition(buf []byte, index uint64) interface{} { 738 defer metrics.MeasureSince([]string{"nomad", "fsm", "alloc_update_desired_transition"}, time.Now()) 739 var req structs.AllocUpdateDesiredTransitionRequest 740 if err := structs.Decode(buf, &req); err != nil { 741 panic(fmt.Errorf("failed to decode request: %v", err)) 742 } 743 744 if err := n.state.UpdateAllocsDesiredTransitions(index, req.Allocs, req.Evals); err != nil { 745 n.logger.Printf("[ERR] nomad.fsm: UpdateAllocsDesiredTransitions failed: %v", err) 746 return err 747 } 748 749 n.handleUpsertedEvals(req.Evals) 750 return nil 751 } 752 753 // applyReconcileSummaries reconciles summaries for all the jobs 754 func (n *nomadFSM) applyReconcileSummaries(buf []byte, index uint64) interface{} { 755 if err := n.state.ReconcileJobSummaries(index); err != nil { 756 return err 757 } 758 return n.reconcileQueuedAllocations(index) 759 } 760 761 // applyUpsertNodeEvent tracks the given node events. 762 func (n *nomadFSM) applyUpsertNodeEvent(buf []byte, index uint64) interface{} { 763 defer metrics.MeasureSince([]string{"nomad", "fsm", "upsert_node_events"}, time.Now()) 764 var req structs.EmitNodeEventsRequest 765 if err := structs.Decode(buf, &req); err != nil { 766 n.logger.Printf("[ERR] nomad.fsm: failed to decode EmitNodeEventsRequest: %v", err) 767 return err 768 } 769 770 if err := n.state.UpsertNodeEvents(index, req.NodeEvents); err != nil { 771 n.logger.Printf("[ERR] nomad.fsm: failed to add node events: %v", err) 772 return err 773 } 774 775 return nil 776 } 777 778 // applyUpsertVaultAccessor stores the Vault accessors for a given allocation 779 // and task 780 func (n *nomadFSM) applyUpsertVaultAccessor(buf []byte, index uint64) interface{} { 781 defer metrics.MeasureSince([]string{"nomad", "fsm", "upsert_vault_accessor"}, time.Now()) 782 var req structs.VaultAccessorsRequest 783 if err := structs.Decode(buf, &req); err != nil { 784 panic(fmt.Errorf("failed to decode request: %v", err)) 785 } 786 787 if err := n.state.UpsertVaultAccessor(index, req.Accessors); err != nil { 788 n.logger.Printf("[ERR] nomad.fsm: UpsertVaultAccessor failed: %v", err) 789 return err 790 } 791 792 return nil 793 } 794 795 // applyDeregisterVaultAccessor deregisters a set of Vault accessors 796 func (n *nomadFSM) applyDeregisterVaultAccessor(buf []byte, index uint64) interface{} { 797 defer metrics.MeasureSince([]string{"nomad", "fsm", "deregister_vault_accessor"}, time.Now()) 798 var req structs.VaultAccessorsRequest 799 if err := structs.Decode(buf, &req); err != nil { 800 panic(fmt.Errorf("failed to decode request: %v", err)) 801 } 802 803 if err := n.state.DeleteVaultAccessors(index, req.Accessors); err != nil { 804 n.logger.Printf("[ERR] nomad.fsm: DeregisterVaultAccessor failed: %v", err) 805 return err 806 } 807 808 return nil 809 } 810 811 // applyPlanApply applies the results of a plan application 812 func (n *nomadFSM) applyPlanResults(buf []byte, index uint64) interface{} { 813 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_plan_results"}, time.Now()) 814 var req structs.ApplyPlanResultsRequest 815 if err := structs.Decode(buf, &req); err != nil { 816 panic(fmt.Errorf("failed to decode request: %v", err)) 817 } 818 819 if err := n.state.UpsertPlanResults(index, &req); err != nil { 820 n.logger.Printf("[ERR] nomad.fsm: ApplyPlan failed: %v", err) 821 return err 822 } 823 824 return nil 825 } 826 827 // applyDeploymentStatusUpdate is used to update the status of an existing 828 // deployment 829 func (n *nomadFSM) applyDeploymentStatusUpdate(buf []byte, index uint64) interface{} { 830 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_deployment_status_update"}, time.Now()) 831 var req structs.DeploymentStatusUpdateRequest 832 if err := structs.Decode(buf, &req); err != nil { 833 panic(fmt.Errorf("failed to decode request: %v", err)) 834 } 835 836 if err := n.state.UpdateDeploymentStatus(index, &req); err != nil { 837 n.logger.Printf("[ERR] nomad.fsm: UpsertDeploymentStatusUpdate failed: %v", err) 838 return err 839 } 840 841 n.handleUpsertedEval(req.Eval) 842 return nil 843 } 844 845 // applyDeploymentPromotion is used to promote canaries in a deployment 846 func (n *nomadFSM) applyDeploymentPromotion(buf []byte, index uint64) interface{} { 847 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_deployment_promotion"}, time.Now()) 848 var req structs.ApplyDeploymentPromoteRequest 849 if err := structs.Decode(buf, &req); err != nil { 850 panic(fmt.Errorf("failed to decode request: %v", err)) 851 } 852 853 if err := n.state.UpdateDeploymentPromotion(index, &req); err != nil { 854 n.logger.Printf("[ERR] nomad.fsm: UpsertDeploymentPromotion failed: %v", err) 855 return err 856 } 857 858 n.handleUpsertedEval(req.Eval) 859 return nil 860 } 861 862 // applyDeploymentAllocHealth is used to set the health of allocations as part 863 // of a deployment 864 func (n *nomadFSM) applyDeploymentAllocHealth(buf []byte, index uint64) interface{} { 865 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_deployment_alloc_health"}, time.Now()) 866 var req structs.ApplyDeploymentAllocHealthRequest 867 if err := structs.Decode(buf, &req); err != nil { 868 panic(fmt.Errorf("failed to decode request: %v", err)) 869 } 870 871 if err := n.state.UpdateDeploymentAllocHealth(index, &req); err != nil { 872 n.logger.Printf("[ERR] nomad.fsm: UpsertDeploymentAllocHealth failed: %v", err) 873 return err 874 } 875 876 n.handleUpsertedEval(req.Eval) 877 return nil 878 } 879 880 // applyDeploymentDelete is used to delete a set of deployments 881 func (n *nomadFSM) applyDeploymentDelete(buf []byte, index uint64) interface{} { 882 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_deployment_delete"}, time.Now()) 883 var req structs.DeploymentDeleteRequest 884 if err := structs.Decode(buf, &req); err != nil { 885 panic(fmt.Errorf("failed to decode request: %v", err)) 886 } 887 888 if err := n.state.DeleteDeployment(index, req.Deployments); err != nil { 889 n.logger.Printf("[ERR] nomad.fsm: DeleteDeployment failed: %v", err) 890 return err 891 } 892 893 return nil 894 } 895 896 // applyJobStability is used to set the stability of a job 897 func (n *nomadFSM) applyJobStability(buf []byte, index uint64) interface{} { 898 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_job_stability"}, time.Now()) 899 var req structs.JobStabilityRequest 900 if err := structs.Decode(buf, &req); err != nil { 901 panic(fmt.Errorf("failed to decode request: %v", err)) 902 } 903 904 if err := n.state.UpdateJobStability(index, req.Namespace, req.JobID, req.JobVersion, req.Stable); err != nil { 905 n.logger.Printf("[ERR] nomad.fsm: UpdateJobStability failed: %v", err) 906 return err 907 } 908 909 return nil 910 } 911 912 // applyACLPolicyUpsert is used to upsert a set of policies 913 func (n *nomadFSM) applyACLPolicyUpsert(buf []byte, index uint64) interface{} { 914 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_acl_policy_upsert"}, time.Now()) 915 var req structs.ACLPolicyUpsertRequest 916 if err := structs.Decode(buf, &req); err != nil { 917 panic(fmt.Errorf("failed to decode request: %v", err)) 918 } 919 920 if err := n.state.UpsertACLPolicies(index, req.Policies); err != nil { 921 n.logger.Printf("[ERR] nomad.fsm: UpsertACLPolicies failed: %v", err) 922 return err 923 } 924 return nil 925 } 926 927 // applyACLPolicyDelete is used to delete a set of policies 928 func (n *nomadFSM) applyACLPolicyDelete(buf []byte, index uint64) interface{} { 929 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_acl_policy_delete"}, time.Now()) 930 var req structs.ACLPolicyDeleteRequest 931 if err := structs.Decode(buf, &req); err != nil { 932 panic(fmt.Errorf("failed to decode request: %v", err)) 933 } 934 935 if err := n.state.DeleteACLPolicies(index, req.Names); err != nil { 936 n.logger.Printf("[ERR] nomad.fsm: DeleteACLPolicies failed: %v", err) 937 return err 938 } 939 return nil 940 } 941 942 // applyACLTokenUpsert is used to upsert a set of policies 943 func (n *nomadFSM) applyACLTokenUpsert(buf []byte, index uint64) interface{} { 944 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_acl_token_upsert"}, time.Now()) 945 var req structs.ACLTokenUpsertRequest 946 if err := structs.Decode(buf, &req); err != nil { 947 panic(fmt.Errorf("failed to decode request: %v", err)) 948 } 949 950 if err := n.state.UpsertACLTokens(index, req.Tokens); err != nil { 951 n.logger.Printf("[ERR] nomad.fsm: UpsertACLTokens failed: %v", err) 952 return err 953 } 954 return nil 955 } 956 957 // applyACLTokenDelete is used to delete a set of policies 958 func (n *nomadFSM) applyACLTokenDelete(buf []byte, index uint64) interface{} { 959 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_acl_token_delete"}, time.Now()) 960 var req structs.ACLTokenDeleteRequest 961 if err := structs.Decode(buf, &req); err != nil { 962 panic(fmt.Errorf("failed to decode request: %v", err)) 963 } 964 965 if err := n.state.DeleteACLTokens(index, req.AccessorIDs); err != nil { 966 n.logger.Printf("[ERR] nomad.fsm: DeleteACLTokens failed: %v", err) 967 return err 968 } 969 return nil 970 } 971 972 // applyACLTokenBootstrap is used to bootstrap an ACL token 973 func (n *nomadFSM) applyACLTokenBootstrap(buf []byte, index uint64) interface{} { 974 defer metrics.MeasureSince([]string{"nomad", "fsm", "apply_acl_token_bootstrap"}, time.Now()) 975 var req structs.ACLTokenBootstrapRequest 976 if err := structs.Decode(buf, &req); err != nil { 977 panic(fmt.Errorf("failed to decode request: %v", err)) 978 } 979 980 if err := n.state.BootstrapACLTokens(index, req.ResetIndex, req.Token); err != nil { 981 n.logger.Printf("[ERR] nomad.fsm: BootstrapACLToken failed: %v", err) 982 return err 983 } 984 return nil 985 } 986 987 func (n *nomadFSM) applyAutopilotUpdate(buf []byte, index uint64) interface{} { 988 var req structs.AutopilotSetConfigRequest 989 if err := structs.Decode(buf, &req); err != nil { 990 panic(fmt.Errorf("failed to decode request: %v", err)) 991 } 992 defer metrics.MeasureSince([]string{"nomad", "fsm", "autopilot"}, time.Now()) 993 994 if req.CAS { 995 act, err := n.state.AutopilotCASConfig(index, req.Config.ModifyIndex, &req.Config) 996 if err != nil { 997 return err 998 } 999 return act 1000 } 1001 return n.state.AutopilotSetConfig(index, &req.Config) 1002 } 1003 1004 func (n *nomadFSM) Snapshot() (raft.FSMSnapshot, error) { 1005 // Create a new snapshot 1006 snap, err := n.state.Snapshot() 1007 if err != nil { 1008 return nil, err 1009 } 1010 1011 ns := &nomadSnapshot{ 1012 snap: snap, 1013 timetable: n.timetable, 1014 } 1015 return ns, nil 1016 } 1017 1018 func (n *nomadFSM) Restore(old io.ReadCloser) error { 1019 defer old.Close() 1020 1021 // Create a new state store 1022 config := &state.StateStoreConfig{ 1023 LogOutput: n.config.LogOutput, 1024 Region: n.config.Region, 1025 } 1026 newState, err := state.NewStateStore(config) 1027 if err != nil { 1028 return err 1029 } 1030 1031 // Start the state restore 1032 restore, err := newState.Restore() 1033 if err != nil { 1034 return err 1035 } 1036 defer restore.Abort() 1037 1038 // Create a decoder 1039 dec := codec.NewDecoder(old, structs.MsgpackHandle) 1040 1041 // Read in the header 1042 var header snapshotHeader 1043 if err := dec.Decode(&header); err != nil { 1044 return err 1045 } 1046 1047 // Populate the new state 1048 msgType := make([]byte, 1) 1049 for { 1050 // Read the message type 1051 _, err := old.Read(msgType) 1052 if err == io.EOF { 1053 break 1054 } else if err != nil { 1055 return err 1056 } 1057 1058 // Decode 1059 snapType := SnapshotType(msgType[0]) 1060 switch snapType { 1061 case TimeTableSnapshot: 1062 if err := n.timetable.Deserialize(dec); err != nil { 1063 return fmt.Errorf("time table deserialize failed: %v", err) 1064 } 1065 1066 case NodeSnapshot: 1067 node := new(structs.Node) 1068 if err := dec.Decode(node); err != nil { 1069 return err 1070 } 1071 1072 // Handle upgrade paths 1073 node.Canonicalize() 1074 1075 if err := restore.NodeRestore(node); err != nil { 1076 return err 1077 } 1078 1079 case JobSnapshot: 1080 job := new(structs.Job) 1081 if err := dec.Decode(job); err != nil { 1082 return err 1083 } 1084 1085 /* Handle upgrade paths: 1086 * - Empty maps and slices should be treated as nil to avoid 1087 * un-intended destructive updates in scheduler since we use 1088 * reflect.DeepEqual. Starting Nomad 0.4.1, job submission sanitizes 1089 * the incoming job. 1090 * - Migrate from old style upgrade stanza that used only a stagger. 1091 */ 1092 job.Canonicalize() 1093 1094 if err := restore.JobRestore(job); err != nil { 1095 return err 1096 } 1097 1098 case EvalSnapshot: 1099 eval := new(structs.Evaluation) 1100 if err := dec.Decode(eval); err != nil { 1101 return err 1102 } 1103 1104 // COMPAT: Handle upgrade to v0.7.0 1105 if eval.Namespace == "" { 1106 eval.Namespace = structs.DefaultNamespace 1107 } 1108 1109 if err := restore.EvalRestore(eval); err != nil { 1110 return err 1111 } 1112 1113 case AllocSnapshot: 1114 alloc := new(structs.Allocation) 1115 if err := dec.Decode(alloc); err != nil { 1116 return err 1117 } 1118 1119 // COMPAT: Handle upgrade to v0.7.0 1120 if alloc.Namespace == "" { 1121 alloc.Namespace = structs.DefaultNamespace 1122 } 1123 1124 if err := restore.AllocRestore(alloc); err != nil { 1125 return err 1126 } 1127 1128 case IndexSnapshot: 1129 idx := new(state.IndexEntry) 1130 if err := dec.Decode(idx); err != nil { 1131 return err 1132 } 1133 if err := restore.IndexRestore(idx); err != nil { 1134 return err 1135 } 1136 1137 case PeriodicLaunchSnapshot: 1138 launch := new(structs.PeriodicLaunch) 1139 if err := dec.Decode(launch); err != nil { 1140 return err 1141 } 1142 1143 // COMPAT: Handle upgrade to v0.7.0 1144 if launch.Namespace == "" { 1145 launch.Namespace = structs.DefaultNamespace 1146 } 1147 1148 if err := restore.PeriodicLaunchRestore(launch); err != nil { 1149 return err 1150 } 1151 1152 case JobSummarySnapshot: 1153 summary := new(structs.JobSummary) 1154 if err := dec.Decode(summary); err != nil { 1155 return err 1156 } 1157 1158 // COMPAT: Handle upgrade to v0.7.0 1159 if summary.Namespace == "" { 1160 summary.Namespace = structs.DefaultNamespace 1161 } 1162 1163 if err := restore.JobSummaryRestore(summary); err != nil { 1164 return err 1165 } 1166 1167 case VaultAccessorSnapshot: 1168 accessor := new(structs.VaultAccessor) 1169 if err := dec.Decode(accessor); err != nil { 1170 return err 1171 } 1172 if err := restore.VaultAccessorRestore(accessor); err != nil { 1173 return err 1174 } 1175 1176 case JobVersionSnapshot: 1177 version := new(structs.Job) 1178 if err := dec.Decode(version); err != nil { 1179 return err 1180 } 1181 1182 // COMPAT: Handle upgrade to v0.7.0 1183 if version.Namespace == "" { 1184 version.Namespace = structs.DefaultNamespace 1185 } 1186 1187 if err := restore.JobVersionRestore(version); err != nil { 1188 return err 1189 } 1190 1191 case DeploymentSnapshot: 1192 deployment := new(structs.Deployment) 1193 if err := dec.Decode(deployment); err != nil { 1194 return err 1195 } 1196 1197 // COMPAT: Handle upgrade to v0.7.0 1198 if deployment.Namespace == "" { 1199 deployment.Namespace = structs.DefaultNamespace 1200 } 1201 1202 if err := restore.DeploymentRestore(deployment); err != nil { 1203 return err 1204 } 1205 1206 case ACLPolicySnapshot: 1207 policy := new(structs.ACLPolicy) 1208 if err := dec.Decode(policy); err != nil { 1209 return err 1210 } 1211 if err := restore.ACLPolicyRestore(policy); err != nil { 1212 return err 1213 } 1214 1215 case ACLTokenSnapshot: 1216 token := new(structs.ACLToken) 1217 if err := dec.Decode(token); err != nil { 1218 return err 1219 } 1220 if err := restore.ACLTokenRestore(token); err != nil { 1221 return err 1222 } 1223 1224 default: 1225 // Check if this is an enterprise only object being restored 1226 restorer, ok := n.enterpriseRestorers[snapType] 1227 if !ok { 1228 return fmt.Errorf("Unrecognized snapshot type: %v", msgType) 1229 } 1230 1231 // Restore the enterprise only object 1232 if err := restorer(restore, dec); err != nil { 1233 return err 1234 } 1235 } 1236 } 1237 1238 restore.Commit() 1239 1240 // Create Job Summaries 1241 // COMPAT 0.4 -> 0.4.1 1242 // We can remove this in 0.5. This exists so that the server creates job 1243 // summaries if they were not present previously. When users upgrade to 0.5 1244 // from 0.4.1, the snapshot will contain job summaries so it will be safe to 1245 // remove this block. 1246 index, err := newState.Index("job_summary") 1247 if err != nil { 1248 return fmt.Errorf("couldn't fetch index of job summary table: %v", err) 1249 } 1250 1251 // If the index is 0 that means there is no job summary in the snapshot so 1252 // we will have to create them 1253 if index == 0 { 1254 // query the latest index 1255 latestIndex, err := newState.LatestIndex() 1256 if err != nil { 1257 return fmt.Errorf("unable to query latest index: %v", index) 1258 } 1259 if err := newState.ReconcileJobSummaries(latestIndex); err != nil { 1260 return fmt.Errorf("error reconciling summaries: %v", err) 1261 } 1262 } 1263 1264 // COMPAT Remove in 0.10 1265 // Clean up active deployments that do not have a job 1266 if err := n.failLeakedDeployments(newState); err != nil { 1267 return err 1268 } 1269 1270 // External code might be calling State(), so we need to synchronize 1271 // here to make sure we swap in the new state store atomically. 1272 n.stateLock.Lock() 1273 stateOld := n.state 1274 n.state = newState 1275 n.stateLock.Unlock() 1276 1277 // Signal that the old state store has been abandoned. This is required 1278 // because we don't operate on it any more, we just throw it away, so 1279 // blocking queries won't see any changes and need to be woken up. 1280 stateOld.Abandon() 1281 1282 return nil 1283 } 1284 1285 // failLeakedDeployments is used to fail deployments that do not have a job. 1286 // This state is a broken invariant that should not occur since 0.8.X. 1287 func (n *nomadFSM) failLeakedDeployments(state *state.StateStore) error { 1288 // Scan for deployments that are referencing a job that no longer exists. 1289 // This could happen if multiple deployments were created for a given job 1290 // and thus the older deployment leaks and then the job is removed. 1291 iter, err := state.Deployments(nil) 1292 if err != nil { 1293 return fmt.Errorf("failed to query deployments: %v", err) 1294 } 1295 1296 dindex, err := state.Index("deployment") 1297 if err != nil { 1298 return fmt.Errorf("couldn't fetch index of deployments table: %v", err) 1299 } 1300 1301 for { 1302 raw := iter.Next() 1303 if raw == nil { 1304 break 1305 } 1306 1307 d := raw.(*structs.Deployment) 1308 1309 // We are only looking for active deployments where the job no longer 1310 // exists 1311 if !d.Active() { 1312 continue 1313 } 1314 1315 // Find the job 1316 job, err := state.JobByID(nil, d.Namespace, d.JobID) 1317 if err != nil { 1318 return fmt.Errorf("failed to lookup job %s from deployment %q: %v", d.JobID, d.ID, err) 1319 } 1320 1321 // Job exists. 1322 if job != nil { 1323 continue 1324 } 1325 1326 // Update the deployment to be terminal 1327 failed := d.Copy() 1328 failed.Status = structs.DeploymentStatusCancelled 1329 failed.StatusDescription = structs.DeploymentStatusDescriptionStoppedJob 1330 if err := state.UpsertDeployment(dindex, failed); err != nil { 1331 return fmt.Errorf("failed to mark leaked deployment %q as failed: %v", failed.ID, err) 1332 } 1333 } 1334 1335 return nil 1336 } 1337 1338 // reconcileQueuedAllocations re-calculates the queued allocations for every job that we 1339 // created a Job Summary during the snap shot restore 1340 func (n *nomadFSM) reconcileQueuedAllocations(index uint64) error { 1341 // Get all the jobs 1342 ws := memdb.NewWatchSet() 1343 iter, err := n.state.Jobs(ws) 1344 if err != nil { 1345 return err 1346 } 1347 1348 snap, err := n.state.Snapshot() 1349 if err != nil { 1350 return fmt.Errorf("unable to create snapshot: %v", err) 1351 } 1352 1353 // Invoking the scheduler for every job so that we can populate the number 1354 // of queued allocations for every job 1355 for { 1356 rawJob := iter.Next() 1357 if rawJob == nil { 1358 break 1359 } 1360 job := rawJob.(*structs.Job) 1361 planner := &scheduler.Harness{ 1362 State: &snap.StateStore, 1363 } 1364 // Create an eval and mark it as requiring annotations and insert that as well 1365 eval := &structs.Evaluation{ 1366 ID: uuid.Generate(), 1367 Namespace: job.Namespace, 1368 Priority: job.Priority, 1369 Type: job.Type, 1370 TriggeredBy: structs.EvalTriggerJobRegister, 1371 JobID: job.ID, 1372 JobModifyIndex: job.JobModifyIndex + 1, 1373 Status: structs.EvalStatusPending, 1374 AnnotatePlan: true, 1375 } 1376 snap.UpsertEvals(100, []*structs.Evaluation{eval}) 1377 // Create the scheduler and run it 1378 sched, err := scheduler.NewScheduler(eval.Type, n.logger, snap, planner) 1379 if err != nil { 1380 return err 1381 } 1382 1383 if err := sched.Process(eval); err != nil { 1384 return err 1385 } 1386 1387 // Get the job summary from the fsm state store 1388 originalSummary, err := n.state.JobSummaryByID(ws, job.Namespace, job.ID) 1389 if err != nil { 1390 return err 1391 } 1392 summary := originalSummary.Copy() 1393 1394 // Add the allocations scheduler has made to queued since these 1395 // allocations are never getting placed until the scheduler is invoked 1396 // with a real planner 1397 if l := len(planner.Plans); l != 1 { 1398 return fmt.Errorf("unexpected number of plans during restore %d. Please file an issue including the logs", l) 1399 } 1400 for _, allocations := range planner.Plans[0].NodeAllocation { 1401 for _, allocation := range allocations { 1402 tgSummary, ok := summary.Summary[allocation.TaskGroup] 1403 if !ok { 1404 return fmt.Errorf("task group %q not found while updating queued count", allocation.TaskGroup) 1405 } 1406 tgSummary.Queued += 1 1407 summary.Summary[allocation.TaskGroup] = tgSummary 1408 } 1409 } 1410 1411 // Add the queued allocations attached to the evaluation to the queued 1412 // counter of the job summary 1413 if l := len(planner.Evals); l != 1 { 1414 return fmt.Errorf("unexpected number of evals during restore %d. Please file an issue including the logs", l) 1415 } 1416 for tg, queued := range planner.Evals[0].QueuedAllocations { 1417 tgSummary, ok := summary.Summary[tg] 1418 if !ok { 1419 return fmt.Errorf("task group %q not found while updating queued count", tg) 1420 } 1421 1422 // We add instead of setting here because we want to take into 1423 // consideration what the scheduler with a mock planner thinks it 1424 // placed. Those should be counted as queued as well 1425 tgSummary.Queued += queued 1426 summary.Summary[tg] = tgSummary 1427 } 1428 1429 if !reflect.DeepEqual(summary, originalSummary) { 1430 summary.ModifyIndex = index 1431 if err := n.state.UpsertJobSummary(index, summary); err != nil { 1432 return err 1433 } 1434 } 1435 } 1436 return nil 1437 } 1438 1439 func (s *nomadSnapshot) Persist(sink raft.SnapshotSink) error { 1440 defer metrics.MeasureSince([]string{"nomad", "fsm", "persist"}, time.Now()) 1441 // Register the nodes 1442 encoder := codec.NewEncoder(sink, structs.MsgpackHandle) 1443 1444 // Write the header 1445 header := snapshotHeader{} 1446 if err := encoder.Encode(&header); err != nil { 1447 sink.Cancel() 1448 return err 1449 } 1450 1451 // Write the time table 1452 sink.Write([]byte{byte(TimeTableSnapshot)}) 1453 if err := s.timetable.Serialize(encoder); err != nil { 1454 sink.Cancel() 1455 return err 1456 } 1457 1458 // Write all the data out 1459 if err := s.persistIndexes(sink, encoder); err != nil { 1460 sink.Cancel() 1461 return err 1462 } 1463 if err := s.persistNodes(sink, encoder); err != nil { 1464 sink.Cancel() 1465 return err 1466 } 1467 if err := s.persistJobs(sink, encoder); err != nil { 1468 sink.Cancel() 1469 return err 1470 } 1471 if err := s.persistEvals(sink, encoder); err != nil { 1472 sink.Cancel() 1473 return err 1474 } 1475 if err := s.persistAllocs(sink, encoder); err != nil { 1476 sink.Cancel() 1477 return err 1478 } 1479 if err := s.persistPeriodicLaunches(sink, encoder); err != nil { 1480 sink.Cancel() 1481 return err 1482 } 1483 if err := s.persistJobSummaries(sink, encoder); err != nil { 1484 sink.Cancel() 1485 return err 1486 } 1487 if err := s.persistVaultAccessors(sink, encoder); err != nil { 1488 sink.Cancel() 1489 return err 1490 } 1491 if err := s.persistJobVersions(sink, encoder); err != nil { 1492 sink.Cancel() 1493 return err 1494 } 1495 if err := s.persistDeployments(sink, encoder); err != nil { 1496 sink.Cancel() 1497 return err 1498 } 1499 if err := s.persistACLPolicies(sink, encoder); err != nil { 1500 sink.Cancel() 1501 return err 1502 } 1503 if err := s.persistACLTokens(sink, encoder); err != nil { 1504 sink.Cancel() 1505 return err 1506 } 1507 if err := s.persistEnterpriseTables(sink, encoder); err != nil { 1508 sink.Cancel() 1509 return err 1510 } 1511 return nil 1512 } 1513 1514 func (s *nomadSnapshot) persistIndexes(sink raft.SnapshotSink, 1515 encoder *codec.Encoder) error { 1516 // Get all the indexes 1517 iter, err := s.snap.Indexes() 1518 if err != nil { 1519 return err 1520 } 1521 1522 for { 1523 // Get the next item 1524 raw := iter.Next() 1525 if raw == nil { 1526 break 1527 } 1528 1529 // Prepare the request struct 1530 idx := raw.(*state.IndexEntry) 1531 1532 // Write out a node registration 1533 sink.Write([]byte{byte(IndexSnapshot)}) 1534 if err := encoder.Encode(idx); err != nil { 1535 return err 1536 } 1537 } 1538 return nil 1539 } 1540 1541 func (s *nomadSnapshot) persistNodes(sink raft.SnapshotSink, 1542 encoder *codec.Encoder) error { 1543 // Get all the nodes 1544 ws := memdb.NewWatchSet() 1545 nodes, err := s.snap.Nodes(ws) 1546 if err != nil { 1547 return err 1548 } 1549 1550 for { 1551 // Get the next item 1552 raw := nodes.Next() 1553 if raw == nil { 1554 break 1555 } 1556 1557 // Prepare the request struct 1558 node := raw.(*structs.Node) 1559 1560 // Write out a node registration 1561 sink.Write([]byte{byte(NodeSnapshot)}) 1562 if err := encoder.Encode(node); err != nil { 1563 return err 1564 } 1565 } 1566 return nil 1567 } 1568 1569 func (s *nomadSnapshot) persistJobs(sink raft.SnapshotSink, 1570 encoder *codec.Encoder) error { 1571 // Get all the jobs 1572 ws := memdb.NewWatchSet() 1573 jobs, err := s.snap.Jobs(ws) 1574 if err != nil { 1575 return err 1576 } 1577 1578 for { 1579 // Get the next item 1580 raw := jobs.Next() 1581 if raw == nil { 1582 break 1583 } 1584 1585 // Prepare the request struct 1586 job := raw.(*structs.Job) 1587 1588 // Write out a job registration 1589 sink.Write([]byte{byte(JobSnapshot)}) 1590 if err := encoder.Encode(job); err != nil { 1591 return err 1592 } 1593 } 1594 return nil 1595 } 1596 1597 func (s *nomadSnapshot) persistEvals(sink raft.SnapshotSink, 1598 encoder *codec.Encoder) error { 1599 // Get all the evaluations 1600 ws := memdb.NewWatchSet() 1601 evals, err := s.snap.Evals(ws) 1602 if err != nil { 1603 return err 1604 } 1605 1606 for { 1607 // Get the next item 1608 raw := evals.Next() 1609 if raw == nil { 1610 break 1611 } 1612 1613 // Prepare the request struct 1614 eval := raw.(*structs.Evaluation) 1615 1616 // Write out the evaluation 1617 sink.Write([]byte{byte(EvalSnapshot)}) 1618 if err := encoder.Encode(eval); err != nil { 1619 return err 1620 } 1621 } 1622 return nil 1623 } 1624 1625 func (s *nomadSnapshot) persistAllocs(sink raft.SnapshotSink, 1626 encoder *codec.Encoder) error { 1627 // Get all the allocations 1628 ws := memdb.NewWatchSet() 1629 allocs, err := s.snap.Allocs(ws) 1630 if err != nil { 1631 return err 1632 } 1633 1634 for { 1635 // Get the next item 1636 raw := allocs.Next() 1637 if raw == nil { 1638 break 1639 } 1640 1641 // Prepare the request struct 1642 alloc := raw.(*structs.Allocation) 1643 1644 // Write out the evaluation 1645 sink.Write([]byte{byte(AllocSnapshot)}) 1646 if err := encoder.Encode(alloc); err != nil { 1647 return err 1648 } 1649 } 1650 return nil 1651 } 1652 1653 func (s *nomadSnapshot) persistPeriodicLaunches(sink raft.SnapshotSink, 1654 encoder *codec.Encoder) error { 1655 // Get all the jobs 1656 ws := memdb.NewWatchSet() 1657 launches, err := s.snap.PeriodicLaunches(ws) 1658 if err != nil { 1659 return err 1660 } 1661 1662 for { 1663 // Get the next item 1664 raw := launches.Next() 1665 if raw == nil { 1666 break 1667 } 1668 1669 // Prepare the request struct 1670 launch := raw.(*structs.PeriodicLaunch) 1671 1672 // Write out a job registration 1673 sink.Write([]byte{byte(PeriodicLaunchSnapshot)}) 1674 if err := encoder.Encode(launch); err != nil { 1675 return err 1676 } 1677 } 1678 return nil 1679 } 1680 1681 func (s *nomadSnapshot) persistJobSummaries(sink raft.SnapshotSink, 1682 encoder *codec.Encoder) error { 1683 1684 ws := memdb.NewWatchSet() 1685 summaries, err := s.snap.JobSummaries(ws) 1686 if err != nil { 1687 return err 1688 } 1689 1690 for { 1691 raw := summaries.Next() 1692 if raw == nil { 1693 break 1694 } 1695 1696 jobSummary := raw.(*structs.JobSummary) 1697 1698 sink.Write([]byte{byte(JobSummarySnapshot)}) 1699 if err := encoder.Encode(jobSummary); err != nil { 1700 return err 1701 } 1702 } 1703 return nil 1704 } 1705 1706 func (s *nomadSnapshot) persistVaultAccessors(sink raft.SnapshotSink, 1707 encoder *codec.Encoder) error { 1708 1709 ws := memdb.NewWatchSet() 1710 accessors, err := s.snap.VaultAccessors(ws) 1711 if err != nil { 1712 return err 1713 } 1714 1715 for { 1716 raw := accessors.Next() 1717 if raw == nil { 1718 break 1719 } 1720 1721 accessor := raw.(*structs.VaultAccessor) 1722 1723 sink.Write([]byte{byte(VaultAccessorSnapshot)}) 1724 if err := encoder.Encode(accessor); err != nil { 1725 return err 1726 } 1727 } 1728 return nil 1729 } 1730 1731 func (s *nomadSnapshot) persistJobVersions(sink raft.SnapshotSink, 1732 encoder *codec.Encoder) error { 1733 // Get all the jobs 1734 ws := memdb.NewWatchSet() 1735 versions, err := s.snap.JobVersions(ws) 1736 if err != nil { 1737 return err 1738 } 1739 1740 for { 1741 // Get the next item 1742 raw := versions.Next() 1743 if raw == nil { 1744 break 1745 } 1746 1747 // Prepare the request struct 1748 job := raw.(*structs.Job) 1749 1750 // Write out a job registration 1751 sink.Write([]byte{byte(JobVersionSnapshot)}) 1752 if err := encoder.Encode(job); err != nil { 1753 return err 1754 } 1755 } 1756 return nil 1757 } 1758 1759 func (s *nomadSnapshot) persistDeployments(sink raft.SnapshotSink, 1760 encoder *codec.Encoder) error { 1761 // Get all the jobs 1762 ws := memdb.NewWatchSet() 1763 deployments, err := s.snap.Deployments(ws) 1764 if err != nil { 1765 return err 1766 } 1767 1768 for { 1769 // Get the next item 1770 raw := deployments.Next() 1771 if raw == nil { 1772 break 1773 } 1774 1775 // Prepare the request struct 1776 deployment := raw.(*structs.Deployment) 1777 1778 // Write out a job registration 1779 sink.Write([]byte{byte(DeploymentSnapshot)}) 1780 if err := encoder.Encode(deployment); err != nil { 1781 return err 1782 } 1783 } 1784 return nil 1785 } 1786 1787 func (s *nomadSnapshot) persistACLPolicies(sink raft.SnapshotSink, 1788 encoder *codec.Encoder) error { 1789 // Get all the policies 1790 ws := memdb.NewWatchSet() 1791 policies, err := s.snap.ACLPolicies(ws) 1792 if err != nil { 1793 return err 1794 } 1795 1796 for { 1797 // Get the next item 1798 raw := policies.Next() 1799 if raw == nil { 1800 break 1801 } 1802 1803 // Prepare the request struct 1804 policy := raw.(*structs.ACLPolicy) 1805 1806 // Write out a policy registration 1807 sink.Write([]byte{byte(ACLPolicySnapshot)}) 1808 if err := encoder.Encode(policy); err != nil { 1809 return err 1810 } 1811 } 1812 return nil 1813 } 1814 1815 func (s *nomadSnapshot) persistACLTokens(sink raft.SnapshotSink, 1816 encoder *codec.Encoder) error { 1817 // Get all the policies 1818 ws := memdb.NewWatchSet() 1819 tokens, err := s.snap.ACLTokens(ws) 1820 if err != nil { 1821 return err 1822 } 1823 1824 for { 1825 // Get the next item 1826 raw := tokens.Next() 1827 if raw == nil { 1828 break 1829 } 1830 1831 // Prepare the request struct 1832 token := raw.(*structs.ACLToken) 1833 1834 // Write out a token registration 1835 sink.Write([]byte{byte(ACLTokenSnapshot)}) 1836 if err := encoder.Encode(token); err != nil { 1837 return err 1838 } 1839 } 1840 return nil 1841 } 1842 1843 // Release is a no-op, as we just need to GC the pointer 1844 // to the state store snapshot. There is nothing to explicitly 1845 // cleanup. 1846 func (s *nomadSnapshot) Release() {}