// UpsertJob is used to register a job or update a job definition func (s *StateStore) UpsertJob(index uint64, job *structs.Job) error { txn := s.db.Txn(true) defer txn.Abort() watcher := watch.NewItems() watcher.Add(watch.Item{Table: "jobs"}) watcher.Add(watch.Item{Job: job.ID}) // Check if the job already exists existing, err := txn.First("jobs", "id", job.ID) if err != nil { return fmt.Errorf("job lookup failed: %v", err) } // Setup the indexes correctly if existing != nil { job.CreateIndex = existing.(*structs.Job).CreateIndex job.ModifyIndex = index job.JobModifyIndex = index // Compute the job status var err error job.Status, err = s.getJobStatus(txn, job, false) if err != nil { return fmt.Errorf("setting job status for %q failed: %v", job.ID, err) } } else { job.CreateIndex = index job.ModifyIndex = index job.JobModifyIndex = index // If we are inserting the job for the first time, we don't need to // calculate the jobs status as it is known. if job.IsPeriodic() { job.Status = structs.JobStatusRunning } else { job.Status = structs.JobStatusPending } } if err := s.updateSummaryWithJob(index, job, watcher, txn); err != nil { return fmt.Errorf("unable to create job summary: %v", err) } // Create the LocalDisk if it's nil by adding up DiskMB from task resources. // COMPAT 0.4.1 -> 0.5 s.addLocalDiskToTaskGroups(job) // Insert the job if err := txn.Insert("jobs", job); err != nil { return fmt.Errorf("job insert failed: %v", err) } if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil { return fmt.Errorf("index update failed: %v", err) } txn.Defer(func() { s.watch.notify(watcher) }) txn.Commit() return nil }
// UpsertJob is used to register a job or update a job definition func (s *StateStore) UpsertJob(index uint64, job *structs.Job) error { txn := s.db.Txn(true) defer txn.Abort() // Check if the job already exists existing, err := txn.First("jobs", "id", job.ID) if err != nil { return fmt.Errorf("job lookup failed: %v", err) } // Setup the indexes correctly if existing != nil { job.CreateIndex = existing.(*structs.Job).CreateIndex job.ModifyIndex = index } else { job.CreateIndex = index job.ModifyIndex = index } // Insert the job if err := txn.Insert("jobs", job); err != nil { return fmt.Errorf("job insert failed: %v", err) } if err := txn.Insert("index", &IndexEntry{"jobs", index}); err != nil { return fmt.Errorf("index update failed: %v", err) } txn.Commit() return nil }
func TestDiffAllocs(t *testing.T) { job := mock.Job() required := materializeTaskGroups(job) // The "old" job has a previous modify index oldJob := new(structs.Job) *oldJob = *job oldJob.ModifyIndex -= 1 tainted := map[string]bool{ "dead": true, "zip": false, } allocs := []*structs.Allocation{ // Update the 1st &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "zip", Name: "my-job.web[0]", Job: oldJob, }, // Ignore the 2rd &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "zip", Name: "my-job.web[1]", Job: job, }, // Evict 11th &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "zip", Name: "my-job.web[10]", }, // Migrate the 3rd &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "dead", Name: "my-job.web[2]", }, } diff := diffAllocs(job, tainted, required, allocs) place := diff.place update := diff.update migrate := diff.migrate stop := diff.stop ignore := diff.ignore // We should update the first alloc if len(update) != 1 || update[0].Alloc != allocs[0] { t.Fatalf("bad: %#v", update) } // We should ignore the second alloc if len(ignore) != 1 || ignore[0].Alloc != allocs[1] { t.Fatalf("bad: %#v", ignore) } // We should stop the 3rd alloc if len(stop) != 1 || stop[0].Alloc != allocs[2] { t.Fatalf("bad: %#v", stop) } // We should migrate the 4rd alloc if len(migrate) != 1 || migrate[0].Alloc != allocs[3] { t.Fatalf("bad: %#v", migrate) } // We should place 7 if len(place) != 7 { t.Fatalf("bad: %#v", place) } }
func TestDiffSystemAllocs(t *testing.T) { job := mock.SystemJob() // Create three alive nodes. nodes := []*structs.Node{{ID: "foo"}, {ID: "bar"}, {ID: "baz"}} // The "old" job has a previous modify index oldJob := new(structs.Job) *oldJob = *job oldJob.ModifyIndex -= 1 tainted := map[string]bool{ "dead": true, "baz": false, } allocs := []*structs.Allocation{ // Update allocation on baz &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "baz", Name: "my-job.web[0]", Job: oldJob, }, // Ignore allocation on bar &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "bar", Name: "my-job.web[0]", Job: job, }, // Stop allocation on dead. &structs.Allocation{ ID: structs.GenerateUUID(), NodeID: "dead", Name: "my-job.web[0]", }, } diff := diffSystemAllocs(job, nodes, tainted, allocs) place := diff.place update := diff.update migrate := diff.migrate stop := diff.stop ignore := diff.ignore // We should update the first alloc if len(update) != 1 || update[0].Alloc != allocs[0] { t.Fatalf("bad: %#v", update) } // We should ignore the second alloc if len(ignore) != 1 || ignore[0].Alloc != allocs[1] { t.Fatalf("bad: %#v", ignore) } // We should stop the third alloc if len(stop) != 1 || stop[0].Alloc != allocs[2] { t.Fatalf("bad: %#v", stop) } // There should be no migrates. if len(migrate) != 0 { t.Fatalf("bad: %#v", migrate) } // We should place 1 if len(place) != 1 { t.Fatalf("bad: %#v", place) } }