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