Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making the API default missing values #2300

Merged
merged 18 commits into from
Feb 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
language: go

go:
- 1.7
- 1.8

branches:
only:
Expand Down
15 changes: 9 additions & 6 deletions api/allocations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"reflect"
"sort"
"testing"

"github.com/hashicorp/nomad/helper"
)

func TestAllocations_List(t *testing.T) {
Expand All @@ -28,9 +30,9 @@ func TestAllocations_List(t *testing.T) {
return

job := &Job{
ID: "job1",
Name: "Job #1",
Type: JobTypeService,
ID: helper.StringToPtr("job1"),
Name: helper.StringToPtr("Job #1"),
Type: helper.StringToPtr(JobTypeService),
}
eval, _, err := c.Jobs().Register(job, nil)
if err != nil {
Expand Down Expand Up @@ -74,10 +76,11 @@ func TestAllocations_PrefixList(t *testing.T) {
return

job := &Job{
ID: "job1",
Name: "Job #1",
Type: JobTypeService,
ID: helper.StringToPtr("job1"),
Name: helper.StringToPtr("Job #1"),
Type: helper.StringToPtr(JobTypeService),
}

eval, _, err := c.Jobs().Register(job, nil)
if err != nil {
t.Fatalf("err: %s", err)
Expand Down
36 changes: 19 additions & 17 deletions api/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package api
import (
"reflect"
"testing"

"github.com/hashicorp/nomad/helper"
)

func TestCompose(t *testing.T) {
Expand All @@ -12,14 +14,14 @@ func TestCompose(t *testing.T) {
SetMeta("foo", "bar").
Constrain(NewConstraint("kernel.name", "=", "linux")).
Require(&Resources{
CPU: 1250,
MemoryMB: 1024,
DiskMB: 2048,
IOPS: 500,
CPU: helper.IntToPtr(1250),
MemoryMB: helper.IntToPtr(1024),
DiskMB: helper.IntToPtr(2048),
IOPS: helper.IntToPtr(500),
Networks: []*NetworkResource{
&NetworkResource{
CIDR: "0.0.0.0/0",
MBits: 100,
MBits: helper.IntToPtr(100),
ReservedPorts: []Port{{"", 80}, {"", 443}},
},
},
Expand All @@ -40,11 +42,11 @@ func TestCompose(t *testing.T) {

// Check that the composed result looks correct
expect := &Job{
Region: "region1",
ID: "job1",
Name: "myjob",
Type: JobTypeService,
Priority: 2,
Region: helper.StringToPtr("region1"),
ID: helper.StringToPtr("job1"),
Name: helper.StringToPtr("myjob"),
Type: helper.StringToPtr(JobTypeService),
Priority: helper.IntToPtr(2),
Datacenters: []string{
"dc1",
},
Expand All @@ -60,8 +62,8 @@ func TestCompose(t *testing.T) {
},
TaskGroups: []*TaskGroup{
&TaskGroup{
Name: "grp1",
Count: 2,
Name: helper.StringToPtr("grp1"),
Count: helper.IntToPtr(2),
Constraints: []*Constraint{
&Constraint{
LTarget: "kernel.name",
Expand All @@ -74,14 +76,14 @@ func TestCompose(t *testing.T) {
Name: "task1",
Driver: "exec",
Resources: &Resources{
CPU: 1250,
MemoryMB: 1024,
DiskMB: 2048,
IOPS: 500,
CPU: helper.IntToPtr(1250),
MemoryMB: helper.IntToPtr(1024),
DiskMB: helper.IntToPtr(2048),
IOPS: helper.IntToPtr(500),
Networks: []*NetworkResource{
&NetworkResource{
CIDR: "0.0.0.0/0",
MBits: 100,
MBits: helper.IntToPtr(100),
ReservedPorts: []Port{
{"", 80},
{"", 443},
Expand Down
184 changes: 161 additions & 23 deletions api/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (
"sort"
"strconv"
"time"

"github.com/gorhill/cronexpr"
"github.com/hashicorp/nomad/helper"
)

const (
Expand All @@ -14,6 +17,9 @@ const (

// JobTypeBatch indicates a short-lived process
JobTypeBatch = "batch"

// PeriodicSpecCron is used for a cron spec.
PeriodicSpecCron = "cron"
)

const (
Expand All @@ -32,6 +38,16 @@ func (c *Client) Jobs() *Jobs {
return &Jobs{client: c}
}

func (j *Jobs) Validate(job *Job, q *WriteOptions) (*JobValidateResponse, *WriteMeta, error) {
var resp JobValidateResponse
req := &JobValidateRequest{Job: job}
if q != nil {
req.WriteRequest = WriteRequest{Region: q.Region}
}
wm, err := j.client.write("/v1/validate/job", req, &resp, q)
return &resp, wm, err
}

// Register is used to register a new job. It returns the ID
// of the evaluation, along with any errors encountered.
func (j *Jobs) Register(job *Job, q *WriteOptions) (string, *WriteMeta, error) {
Expand Down Expand Up @@ -162,7 +178,7 @@ func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *Wr
Job: job,
Diff: diff,
}
wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
wm, err := j.client.write("/v1/job/"+*job.ID+"/plan", req, &resp, q)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -207,13 +223,42 @@ type UpdateStrategy struct {

// PeriodicConfig is for serializing periodic config for a job.
type PeriodicConfig struct {
Enabled bool
Spec string
SpecType string
ProhibitOverlap bool
Enabled *bool
Spec *string
SpecType *string
ProhibitOverlap *bool
TimeZone *string
}

func (p *PeriodicConfig) Canonicalize() {
if p.Enabled == nil {
p.Enabled = helper.BoolToPtr(true)
}
if p.SpecType == nil {
p.SpecType = helper.StringToPtr(PeriodicSpecCron)
}
if p.ProhibitOverlap == nil {
p.ProhibitOverlap = helper.BoolToPtr(false)
}
if p.TimeZone == nil || *p.TimeZone == "" {
p.TimeZone = helper.StringToPtr("UTC")
}
}

// Next returns the closest time instant matching the spec that is after the
// passed time. If no matching instance exists, the zero value of time.Time is
// returned. The `time.Location` of the returned value matches that of the
// passed time.
func (p *PeriodicConfig) Next(fromTime time.Time) time.Time {
if *p.SpecType == PeriodicSpecCron {
if e, err := cronexpr.Parse(*p.Spec); err == nil {
return e.Next(fromTime)
}
}

return time.Time{}
}

func (p *PeriodicConfig) GetLocation() (*time.Location, error) {
if p.TimeZone == nil || *p.TimeZone == "" {
return time.UTC, nil
Expand All @@ -231,13 +276,13 @@ type ParameterizedJobConfig struct {

// Job is used to serialize a job.
type Job struct {
Region string
ID string
ParentID string
Name string
Type string
Priority int
AllAtOnce bool
Region *string
ID *string
ParentID *string
Name *string
Type *string
Priority *int
AllAtOnce *bool
Datacenters []string
Constraints []*Constraint
TaskGroups []*TaskGroup
Expand All @@ -246,12 +291,71 @@ type Job struct {
ParameterizedJob *ParameterizedJobConfig
Payload []byte
Meta map[string]string
VaultToken string
Status string
StatusDescription string
CreateIndex uint64
ModifyIndex uint64
JobModifyIndex uint64
VaultToken *string
Status *string
StatusDescription *string
CreateIndex *uint64
ModifyIndex *uint64
JobModifyIndex *uint64
}

// IsPeriodic returns whether a job is periodic.
func (j *Job) IsPeriodic() bool {
return j.Periodic != nil
}

// IsParameterized returns whether a job is parameterized job.
func (j *Job) IsParameterized() bool {
return j.ParameterizedJob != nil
}

func (j *Job) Canonicalize() {
if j.ID == nil {
j.ID = helper.StringToPtr("")
}
if j.Name == nil {
j.Name = j.ID
}
if j.ParentID == nil {
j.ParentID = helper.StringToPtr("")
}
if j.Priority == nil {
j.Priority = helper.IntToPtr(50)
}
if j.Region == nil {
j.Region = helper.StringToPtr("global")
}
if j.Type == nil {
j.Type = helper.StringToPtr("service")
}
if j.AllAtOnce == nil {
j.AllAtOnce = helper.BoolToPtr(false)
}
if j.VaultToken == nil {
j.VaultToken = helper.StringToPtr("")
}
if j.Status == nil {
j.Status = helper.StringToPtr("")
}
if j.StatusDescription == nil {
j.StatusDescription = helper.StringToPtr("")
}
if j.CreateIndex == nil {
j.CreateIndex = helper.Uint64ToPtr(0)
}
if j.ModifyIndex == nil {
j.ModifyIndex = helper.Uint64ToPtr(0)
}
if j.JobModifyIndex == nil {
j.JobModifyIndex = helper.Uint64ToPtr(0)
}
if j.Periodic != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar block for update strategy and parameterized?

j.Periodic.Canonicalize()
}

for _, tg := range j.TaskGroups {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break these up into different functions

tg.Canonicalize(*j.Type)
}
}

// JobSummary summarizes the state of the allocations of a job
Expand Down Expand Up @@ -339,11 +443,11 @@ func NewBatchJob(id, name, region string, pri int) *Job {
// newJob is used to create a new Job struct.
func newJob(id, name, region, typ string, pri int) *Job {
return &Job{
Region: region,
ID: id,
Name: name,
Type: typ,
Priority: pri,
Region: &region,
ID: &id,
Name: &name,
Type: &typ,
Priority: &pri,
}
}

Expand Down Expand Up @@ -380,6 +484,39 @@ func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job {
return j
}

type WriteRequest struct {
// The target region for this write
Region string
}

// JobValidateRequest is used to validate a job
type JobValidateRequest struct {
Job *Job
WriteRequest
}

// JobValidateResponse is the response from validate request
type JobValidateResponse struct {
// DriverConfigValidated indicates whether the agent validated the driver
// config
DriverConfigValidated bool

// ValidationErrors is a list of validation errors
ValidationErrors []string
}

// JobUpdateRequest is used to update a job
type JobRegisterRequest struct {
Job *Job
// If EnforceIndex is set then the job will only be registered if the passed
// JobModifyIndex matches the current Jobs index. If the index is zero, the
// register only occurs if the job is new.
EnforceIndex bool
JobModifyIndex uint64

WriteRequest
}

// RegisterJobRequest is used to serialize a job registration
type RegisterJobRequest struct {
Job *Job
Expand All @@ -400,6 +537,7 @@ type deregisterJobResponse struct {
type JobPlanRequest struct {
Job *Job
Diff bool
WriteRequest
}

type JobPlanResponse struct {
Expand Down
Loading