github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/api/jobs.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"time"
     7  )
     8  
     9  const (
    10  	// JobTypeService indicates a long-running processes
    11  	JobTypeService = "service"
    12  
    13  	// JobTypeBatch indicates a short-lived process
    14  	JobTypeBatch = "batch"
    15  )
    16  
    17  // Jobs is used to access the job-specific endpoints.
    18  type Jobs struct {
    19  	client *Client
    20  }
    21  
    22  // Jobs returns a handle on the jobs endpoints.
    23  func (c *Client) Jobs() *Jobs {
    24  	return &Jobs{client: c}
    25  }
    26  
    27  // Register is used to register a new job. It returns the ID
    28  // of the evaluation, along with any errors encountered.
    29  func (j *Jobs) Register(job *Job, q *WriteOptions) (string, *WriteMeta, error) {
    30  	var resp registerJobResponse
    31  
    32  	req := &RegisterJobRequest{job}
    33  	wm, err := j.client.write("/v1/jobs", req, &resp, q)
    34  	if err != nil {
    35  		return "", nil, err
    36  	}
    37  	return resp.EvalID, wm, nil
    38  }
    39  
    40  // List is used to list all of the existing jobs.
    41  func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
    42  	var resp []*JobListStub
    43  	qm, err := j.client.query("/v1/jobs", &resp, q)
    44  	if err != nil {
    45  		return nil, qm, err
    46  	}
    47  	sort.Sort(JobIDSort(resp))
    48  	return resp, qm, nil
    49  }
    50  
    51  // PrefixList is used to list all existing jobs that match the prefix.
    52  func (j *Jobs) PrefixList(prefix string) ([]*JobListStub, *QueryMeta, error) {
    53  	return j.List(&QueryOptions{Prefix: prefix})
    54  }
    55  
    56  // Info is used to retrieve information about a particular
    57  // job given its unique ID.
    58  func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) {
    59  	var resp Job
    60  	qm, err := j.client.query("/v1/job/"+jobID, &resp, q)
    61  	if err != nil {
    62  		return nil, nil, err
    63  	}
    64  	return &resp, qm, nil
    65  }
    66  
    67  // Allocations is used to return the allocs for a given job ID.
    68  func (j *Jobs) Allocations(jobID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
    69  	var resp []*AllocationListStub
    70  	qm, err := j.client.query("/v1/job/"+jobID+"/allocations", &resp, q)
    71  	if err != nil {
    72  		return nil, nil, err
    73  	}
    74  	sort.Sort(AllocIndexSort(resp))
    75  	return resp, qm, nil
    76  }
    77  
    78  // Evaluations is used to query the evaluations associated with
    79  // the given job ID.
    80  func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
    81  	var resp []*Evaluation
    82  	qm, err := j.client.query("/v1/job/"+jobID+"/evaluations", &resp, q)
    83  	if err != nil {
    84  		return nil, nil, err
    85  	}
    86  	sort.Sort(EvalIndexSort(resp))
    87  	return resp, qm, nil
    88  }
    89  
    90  // Deregister is used to remove an existing job.
    91  func (j *Jobs) Deregister(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
    92  	var resp deregisterJobResponse
    93  	wm, err := j.client.delete("/v1/job/"+jobID, &resp, q)
    94  	if err != nil {
    95  		return "", nil, err
    96  	}
    97  	return resp.EvalID, wm, nil
    98  }
    99  
   100  // ForceEvaluate is used to force-evaluate an existing job.
   101  func (j *Jobs) ForceEvaluate(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
   102  	var resp registerJobResponse
   103  	wm, err := j.client.write("/v1/job/"+jobID+"/evaluate", nil, &resp, q)
   104  	if err != nil {
   105  		return "", nil, err
   106  	}
   107  	return resp.EvalID, wm, nil
   108  }
   109  
   110  // PeriodicForce spawns a new instance of the periodic job and returns the eval ID
   111  func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
   112  	var resp periodicForceResponse
   113  	wm, err := j.client.write("/v1/job/"+jobID+"/periodic/force", nil, &resp, q)
   114  	if err != nil {
   115  		return "", nil, err
   116  	}
   117  	return resp.EvalID, wm, nil
   118  }
   119  
   120  func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {
   121  	if job == nil {
   122  		return nil, nil, fmt.Errorf("must pass non-nil job")
   123  	}
   124  
   125  	var resp JobPlanResponse
   126  	req := &JobPlanRequest{
   127  		Job:  job,
   128  		Diff: diff,
   129  	}
   130  	wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
   131  	if err != nil {
   132  		return nil, nil, err
   133  	}
   134  
   135  	return &resp, wm, nil
   136  }
   137  
   138  // periodicForceResponse is used to deserialize a force response
   139  type periodicForceResponse struct {
   140  	EvalID string
   141  }
   142  
   143  // UpdateStrategy is for serializing update strategy for a job.
   144  type UpdateStrategy struct {
   145  	Stagger     time.Duration
   146  	MaxParallel int
   147  }
   148  
   149  // PeriodicConfig is for serializing periodic config for a job.
   150  type PeriodicConfig struct {
   151  	Enabled         bool
   152  	Spec            string
   153  	SpecType        string
   154  	ProhibitOverlap bool
   155  }
   156  
   157  // Job is used to serialize a job.
   158  type Job struct {
   159  	Region            string
   160  	ID                string
   161  	Name              string
   162  	Type              string
   163  	Priority          int
   164  	AllAtOnce         bool
   165  	Datacenters       []string
   166  	Constraints       []*Constraint
   167  	TaskGroups        []*TaskGroup
   168  	Update            *UpdateStrategy
   169  	Periodic          *PeriodicConfig
   170  	Meta              map[string]string
   171  	Status            string
   172  	StatusDescription string
   173  	CreateIndex       uint64
   174  	ModifyIndex       uint64
   175  }
   176  
   177  // JobListStub is used to return a subset of information about
   178  // jobs during list operations.
   179  type JobListStub struct {
   180  	ID                string
   181  	ParentID          string
   182  	Name              string
   183  	Type              string
   184  	Priority          int
   185  	Status            string
   186  	StatusDescription string
   187  	CreateIndex       uint64
   188  	ModifyIndex       uint64
   189  }
   190  
   191  // JobIDSort is used to sort jobs by their job ID's.
   192  type JobIDSort []*JobListStub
   193  
   194  func (j JobIDSort) Len() int {
   195  	return len(j)
   196  }
   197  
   198  func (j JobIDSort) Less(a, b int) bool {
   199  	return j[a].ID < j[b].ID
   200  }
   201  
   202  func (j JobIDSort) Swap(a, b int) {
   203  	j[a], j[b] = j[b], j[a]
   204  }
   205  
   206  // NewServiceJob creates and returns a new service-style job
   207  // for long-lived processes using the provided name, ID, and
   208  // relative job priority.
   209  func NewServiceJob(id, name, region string, pri int) *Job {
   210  	return newJob(id, name, region, JobTypeService, pri)
   211  }
   212  
   213  // NewBatchJob creates and returns a new batch-style job for
   214  // short-lived processes using the provided name and ID along
   215  // with the relative job priority.
   216  func NewBatchJob(id, name, region string, pri int) *Job {
   217  	return newJob(id, name, region, JobTypeBatch, pri)
   218  }
   219  
   220  // newJob is used to create a new Job struct.
   221  func newJob(id, name, region, typ string, pri int) *Job {
   222  	return &Job{
   223  		Region:   region,
   224  		ID:       id,
   225  		Name:     name,
   226  		Type:     typ,
   227  		Priority: pri,
   228  	}
   229  }
   230  
   231  // SetMeta is used to set arbitrary k/v pairs of metadata on a job.
   232  func (j *Job) SetMeta(key, val string) *Job {
   233  	if j.Meta == nil {
   234  		j.Meta = make(map[string]string)
   235  	}
   236  	j.Meta[key] = val
   237  	return j
   238  }
   239  
   240  // AddDatacenter is used to add a datacenter to a job.
   241  func (j *Job) AddDatacenter(dc string) *Job {
   242  	j.Datacenters = append(j.Datacenters, dc)
   243  	return j
   244  }
   245  
   246  // Constrain is used to add a constraint to a job.
   247  func (j *Job) Constrain(c *Constraint) *Job {
   248  	j.Constraints = append(j.Constraints, c)
   249  	return j
   250  }
   251  
   252  // AddTaskGroup adds a task group to an existing job.
   253  func (j *Job) AddTaskGroup(grp *TaskGroup) *Job {
   254  	j.TaskGroups = append(j.TaskGroups, grp)
   255  	return j
   256  }
   257  
   258  // AddPeriodicConfig adds a periodic config to an existing job.
   259  func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job {
   260  	j.Periodic = cfg
   261  	return j
   262  }
   263  
   264  // RegisterJobRequest is used to serialize a job registration
   265  type RegisterJobRequest struct {
   266  	Job *Job
   267  }
   268  
   269  // registerJobResponse is used to deserialize a job response
   270  type registerJobResponse struct {
   271  	EvalID string
   272  }
   273  
   274  // deregisterJobResponse is used to decode a deregister response
   275  type deregisterJobResponse struct {
   276  	EvalID string
   277  }
   278  
   279  type JobPlanRequest struct {
   280  	Job  *Job
   281  	Diff bool
   282  }
   283  
   284  type JobPlanResponse struct {
   285  	JobModifyIndex uint64
   286  	CreatedEvals   []*Evaluation
   287  	Diff           *JobDiff
   288  	Annotations    *PlanAnnotations
   289  }
   290  
   291  type JobDiff struct {
   292  	Type       string
   293  	ID         string
   294  	Fields     []*FieldDiff
   295  	Objects    []*ObjectDiff
   296  	TaskGroups []*TaskGroupDiff
   297  }
   298  
   299  type TaskGroupDiff struct {
   300  	Type    string
   301  	Name    string
   302  	Fields  []*FieldDiff
   303  	Objects []*ObjectDiff
   304  	Tasks   []*TaskDiff
   305  	Updates map[string]uint64
   306  }
   307  
   308  type TaskDiff struct {
   309  	Type        string
   310  	Name        string
   311  	Fields      []*FieldDiff
   312  	Objects     []*ObjectDiff
   313  	Annotations []string
   314  }
   315  
   316  type FieldDiff struct {
   317  	Type        string
   318  	Name        string
   319  	Old, New    string
   320  	Annotations []string
   321  }
   322  
   323  type ObjectDiff struct {
   324  	Type    string
   325  	Name    string
   326  	Fields  []*FieldDiff
   327  	Objects []*ObjectDiff
   328  }
   329  
   330  type PlanAnnotations struct {
   331  	DesiredTGUpdates map[string]*DesiredUpdates
   332  }
   333  
   334  type DesiredUpdates struct {
   335  	Ignore            uint64
   336  	Place             uint64
   337  	Migrate           uint64
   338  	Stop              uint64
   339  	InPlaceUpdate     uint64
   340  	DestructiveUpdate uint64
   341  }