Skip to content

Commit

Permalink
Merge pull request #2566 from hashicorp/f-job-versions
Browse files Browse the repository at this point in the history
Track multiple job versions and introduce a stop state for jobs
  • Loading branch information
dadgar committed Apr 19, 2017
2 parents c6fede8 + 019bb3a commit e281c97
Show file tree
Hide file tree
Showing 28 changed files with 1,807 additions and 271 deletions.
34 changes: 31 additions & 3 deletions api/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) {
return &resp, qm, nil
}

// Versions is used to retrieve all versions of a particular
// job given its unique ID.
func (j *Jobs) Versions(jobID string, q *QueryOptions) ([]*Job, *QueryMeta, error) {
var resp []*Job
qm, err := j.client.query("/v1/job/"+jobID+"/versions", &resp, q)
if err != nil {
return nil, nil, err
}
return resp, qm, nil
}

// Allocations is used to return the allocs for a given job ID.
func (j *Jobs) Allocations(jobID string, allAllocs bool, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
var resp []*AllocationListStub
Expand Down Expand Up @@ -138,10 +149,12 @@ func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *Query
return resp, qm, nil
}

// Deregister is used to remove an existing job.
func (j *Jobs) Deregister(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
// Deregister is used to remove an existing job. If purge is set to true, the job
// is deregistered and purged from the system versus still being queryable and
// eventually GC'ed from the system. Most callers should not specify purge.
func (j *Jobs) Deregister(jobID string, purge bool, q *WriteOptions) (string, *WriteMeta, error) {
var resp deregisterJobResponse
wm, err := j.client.delete("/v1/job/"+jobID, &resp, q)
wm, err := j.client.delete(fmt.Sprintf("/v1/job/%v?purge=%t", jobID, purge), &resp, q)
if err != nil {
return "", nil, err
}
Expand Down Expand Up @@ -279,6 +292,7 @@ type ParameterizedJobConfig struct {

// Job is used to serialize a job.
type Job struct {
Stop *bool
Region *string
ID *string
ParentID *string
Expand All @@ -297,6 +311,8 @@ type Job struct {
VaultToken *string `mapstructure:"vault_token"`
Status *string
StatusDescription *string
Stable *bool
Version *uint64
CreateIndex *uint64
ModifyIndex *uint64
JobModifyIndex *uint64
Expand Down Expand Up @@ -325,6 +341,9 @@ func (j *Job) Canonicalize() {
if j.Priority == nil {
j.Priority = helper.IntToPtr(50)
}
if j.Stop == nil {
j.Stop = helper.BoolToPtr(false)
}
if j.Region == nil {
j.Region = helper.StringToPtr("global")
}
Expand All @@ -343,6 +362,12 @@ func (j *Job) Canonicalize() {
if j.StatusDescription == nil {
j.StatusDescription = helper.StringToPtr("")
}
if j.Stable == nil {
j.Stable = helper.BoolToPtr(false)
}
if j.Version == nil {
j.Version = helper.Uint64ToPtr(0)
}
if j.CreateIndex == nil {
j.CreateIndex = helper.Uint64ToPtr(0)
}
Expand Down Expand Up @@ -406,6 +431,9 @@ type JobListStub struct {
Name string
Type string
Priority int
Periodic bool
ParameterizedJob bool
Stop bool
Status string
StatusDescription string
JobSummary *JobSummary
Expand Down
73 changes: 69 additions & 4 deletions api/jobs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/hashicorp/nomad/helper"
"github.com/hashicorp/nomad/testutil"
"github.com/kr/pretty"
)

func TestJobs_Register(t *testing.T) {
Expand Down Expand Up @@ -107,6 +108,9 @@ func TestJobs_Canonicalize(t *testing.T) {
VaultToken: helper.StringToPtr(""),
Status: helper.StringToPtr(""),
StatusDescription: helper.StringToPtr(""),
Stop: helper.BoolToPtr(false),
Stable: helper.BoolToPtr(false),
Version: helper.Uint64ToPtr(0),
CreateIndex: helper.Uint64ToPtr(0),
ModifyIndex: helper.Uint64ToPtr(0),
JobModifyIndex: helper.Uint64ToPtr(0),
Expand Down Expand Up @@ -162,6 +166,9 @@ func TestJobs_Canonicalize(t *testing.T) {
Priority: helper.IntToPtr(50),
AllAtOnce: helper.BoolToPtr(false),
VaultToken: helper.StringToPtr(""),
Stop: helper.BoolToPtr(false),
Stable: helper.BoolToPtr(false),
Version: helper.Uint64ToPtr(0),
Status: helper.StringToPtr(""),
StatusDescription: helper.StringToPtr(""),
CreateIndex: helper.Uint64ToPtr(0),
Expand Down Expand Up @@ -277,6 +284,9 @@ func TestJobs_Canonicalize(t *testing.T) {
Type: helper.StringToPtr("service"),
AllAtOnce: helper.BoolToPtr(false),
VaultToken: helper.StringToPtr(""),
Stop: helper.BoolToPtr(false),
Stable: helper.BoolToPtr(false),
Version: helper.Uint64ToPtr(0),
Status: helper.StringToPtr(""),
StatusDescription: helper.StringToPtr(""),
CreateIndex: helper.Uint64ToPtr(0),
Expand Down Expand Up @@ -379,6 +389,9 @@ func TestJobs_Canonicalize(t *testing.T) {
Priority: helper.IntToPtr(50),
AllAtOnce: helper.BoolToPtr(false),
VaultToken: helper.StringToPtr(""),
Stop: helper.BoolToPtr(false),
Stable: helper.BoolToPtr(false),
Version: helper.Uint64ToPtr(0),
Status: helper.StringToPtr(""),
StatusDescription: helper.StringToPtr(""),
CreateIndex: helper.Uint64ToPtr(0),
Expand All @@ -399,6 +412,7 @@ func TestJobs_Canonicalize(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
tc.input.Canonicalize()
if !reflect.DeepEqual(tc.input, tc.expected) {
t.Logf("Name: %v, Diffs:\n%v", tc.name, pretty.Diff(tc.expected, tc.input))
t.Fatalf("Name: %v, expected:\n%#v\nactual:\n%#v", tc.name, tc.expected, tc.input)
}
})
Expand Down Expand Up @@ -506,6 +520,38 @@ func TestJobs_Info(t *testing.T) {
}
}

func TestJobs_Versions(t *testing.T) {
c, s := makeClient(t, nil, nil)
defer s.Stop()
jobs := c.Jobs()

// Trying to retrieve a job by ID before it exists returns an error
_, _, err := jobs.Versions("job1", nil)
if err == nil || !strings.Contains(err.Error(), "not found") {
t.Fatalf("expected not found error, got: %#v", err)
}

// Register the job
job := testJob()
_, wm, err := jobs.Register(job, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
assertWriteMeta(t, wm)

// Query the job again and ensure it exists
result, qm, err := jobs.Versions("job1", nil)
if err != nil {
t.Fatalf("err: %s", err)
}
assertQueryMeta(t, qm)

// Check that the result is what we expect
if len(result) == 0 || *result[0].ID != *job.ID {
t.Fatalf("expect: %#v, got: %#v", job, result)
}
}

func TestJobs_PrefixList(t *testing.T) {
c, s := makeClient(t, nil, nil)
defer s.Stop()
Expand Down Expand Up @@ -658,13 +704,12 @@ func TestJobs_Deregister(t *testing.T) {
assertWriteMeta(t, wm)

// Attempting delete on non-existing job returns an error
if _, _, err = jobs.Deregister("nope", nil); err != nil {
if _, _, err = jobs.Deregister("nope", false, nil); err != nil {
t.Fatalf("unexpected error deregistering job: %v", err)

}

// Deleting an existing job works
evalID, wm3, err := jobs.Deregister("job1", nil)
// Do a soft deregister of an existing job
evalID, wm3, err := jobs.Deregister("job1", false, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
Expand All @@ -673,6 +718,26 @@ func TestJobs_Deregister(t *testing.T) {
t.Fatalf("missing eval ID")
}

// Check that the job is still queryable
out, qm1, err := jobs.Info("job1", nil)
if err != nil {
t.Fatalf("err: %s", err)
}
assertQueryMeta(t, qm1)
if out == nil {
t.Fatalf("missing job")
}

// Do a purge deregister of an existing job
evalID, wm4, err := jobs.Deregister("job1", true, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
assertWriteMeta(t, wm4)
if evalID == "" {
t.Fatalf("missing eval ID")
}

// Check that the job is really gone
result, qm, err := jobs.List(nil)
if err != nil {
Expand Down
Loading

0 comments on commit e281c97

Please sign in to comment.