Skip to content

Commit

Permalink
Merge pull request #2300 from hashicorp/refactor-parser
Browse files Browse the repository at this point in the history
Making the API default missing values
  • Loading branch information
dadgar committed Feb 21, 2017
2 parents 1e3e475 + 7cef0d7 commit 139bb3d
Show file tree
Hide file tree
Showing 34 changed files with 2,060 additions and 406 deletions.
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 {
j.Periodic.Canonicalize()
}

for _, tg := range j.TaskGroups {
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

0 comments on commit 139bb3d

Please sign in to comment.