This commit is contained in:
Alex Dadgar
2016-05-11 18:51:48 -07:00
parent 8a58fa4e7c
commit 614a93e1e8
5 changed files with 161 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
package api
import (
"fmt"
"sort"
"time"
)
@@ -116,6 +117,24 @@ func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta,
return resp.EvalID, wm, nil
}
func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {
if job == nil {
return nil, nil, fmt.Errorf("must pass non-nil job")
}
var resp JobPlanResponse
req := &JobPlanRequest{
Job: job,
Diff: diff,
}
wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}
// periodicForceResponse is used to deserialize a force response
type periodicForceResponse struct {
EvalID string
@@ -256,3 +275,72 @@ type registerJobResponse struct {
type deregisterJobResponse struct {
EvalID string
}
type JobPlanRequest struct {
Job *Job
Diff bool
}
type JobPlanResponse struct {
Cas uint64
CreatedEvals []*Evaluation
Diff *JobDiff
SchedulerOutput *SchedulerOutput `json:"Plan"`
}
type JobDiff struct {
Type string
ID string
Fields []*FieldDiff
Objects []*ObjectDiff
TaskGroups []*TaskGroupDiff
}
type TaskGroupDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
Tasks []*TaskDiff
Updates map[string]uint64
}
type TaskDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
Annotations []string
}
type FieldDiff struct {
Type string
Name string
Old, New string
Annotations []string
}
type ObjectDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
}
type SchedulerOutput struct {
FailedAllocs []*Allocations
Annotations *PlanAnnotations
}
type PlanAnnotations struct {
DesiredTGUpdates map[string]*DesiredUpdates
}
type DesiredUpdates struct {
Ignore uint64
Place uint64
Migrate uint64
Stop uint64
InPlaceUpdate uint64
DestructiveUpdate uint64
}

View File

@@ -350,6 +350,76 @@ func TestJobs_PeriodicForce(t *testing.T) {
t.Fatalf("evaluation %q missing", evalID)
}
func TestJobs_Plan(t *testing.T) {
c, s := makeClient(t, nil, nil)
defer s.Stop()
jobs := c.Jobs()
// Create a job and attempt to register it
job := testJob()
eval, wm, err := jobs.Register(job, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
if eval == "" {
t.Fatalf("missing eval id")
}
assertWriteMeta(t, wm)
// Check that passing a nil job fails
if _, _, err := jobs.Plan(nil, true, nil); err == nil {
t.Fatalf("expect an error when job isn't provided")
}
// Make a plan request
planResp, wm, err := jobs.Plan(job, true, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
if planResp == nil {
t.Fatalf("nil response")
}
if planResp.Cas == 0 {
t.Fatalf("bad Cas value: %#v", planResp)
}
if planResp.Diff == nil {
t.Fatalf("got nil diff: %#v", planResp)
}
if planResp.SchedulerOutput == nil {
t.Fatalf("got nil scheduler output: %#v", planResp)
}
// Can make this assertion because there are no clients.
if len(planResp.CreatedEvals) == 0 {
t.Fatalf("got no CreatedEvals: %#v", planResp)
}
// Make a plan request w/o the diff
planResp, wm, err = jobs.Plan(job, false, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
assertWriteMeta(t, wm)
if planResp == nil {
t.Fatalf("nil response")
}
if planResp.Cas == 0 {
t.Fatalf("bad Cas value: %d", planResp.Cas)
}
if planResp.Diff != nil {
t.Fatalf("got non-nil diff: %#v", planResp)
}
if planResp.SchedulerOutput == nil {
t.Fatalf("got nil scheduler output: %#v", planResp)
}
// Can make this assertion because there are no clients.
if len(planResp.CreatedEvals) == 0 {
t.Fatalf("got no CreatedEvals: %#v", planResp)
}
}
func TestJobs_NewBatchJob(t *testing.T) {
job := NewBatchJob("job1", "myjob", "region1", 5)
expect := &Job{

View File

@@ -99,6 +99,7 @@ func (s *HTTPServer) jobPlan(resp http.ResponseWriter, req *http.Request,
if err := s.agent.RPC("Job.Plan", &args, &out); err != nil {
return nil, err
}
setIndex(resp, out.Index)
return out, nil
}

View File

@@ -474,6 +474,7 @@ func (j *Job) Plan(args *structs.JobPlanRequest, reply *structs.JobPlanResponse)
reply.Cas = index
reply.Plan = planner.Plan
reply.CreatedEvals = planner.CreatedEvals
reply.Index = index
return nil
}

View File

@@ -416,7 +416,7 @@ type JobPlanResponse struct {
// causes an in-place update or create/destroy
Diff *JobDiff
QueryMeta
WriteMeta
}
// SingleAllocResponse is used to return a single allocation