open-nomad/api/jobs.go

404 lines
9.7 KiB
Go
Raw Normal View History

2015-09-08 23:24:26 +00:00
package api
2015-09-17 19:40:51 +00:00
import (
2016-05-12 01:51:48 +00:00
"fmt"
2015-09-17 19:40:51 +00:00
"sort"
2015-10-20 23:42:53 +00:00
"time"
2015-09-17 19:40:51 +00:00
)
2015-09-10 00:29:43 +00:00
const (
// JobTypeService indicates a long-running processes
JobTypeService = "service"
// JobTypeBatch indicates a short-lived process
JobTypeBatch = "batch"
)
2016-06-08 23:48:02 +00:00
const (
// RegisterEnforceIndexErrPrefix is the prefix to use in errors caused by
// enforcing the job modify index during registers.
RegisterEnforceIndexErrPrefix = "Enforcing job modify index"
)
2015-09-08 23:24:26 +00:00
// Jobs is used to access the job-specific endpoints.
type Jobs struct {
client *Client
}
// Jobs returns a handle on the jobs endpoints.
func (c *Client) Jobs() *Jobs {
return &Jobs{client: c}
}
// 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) {
2016-06-08 23:48:02 +00:00
var resp registerJobResponse
req := &RegisterJobRequest{Job: job}
wm, err := j.client.write("/v1/jobs", req, &resp, q)
if err != nil {
return "", nil, err
}
return resp.EvalID, wm, nil
}
// EnforceRegister is used to register a job enforcing its job modify index.
func (j *Jobs) EnforceRegister(job *Job, modifyIndex uint64, q *WriteOptions) (string, *WriteMeta, error) {
2015-09-08 23:24:26 +00:00
var resp registerJobResponse
2016-06-08 23:48:02 +00:00
req := &RegisterJobRequest{
Job: job,
EnforceIndex: true,
JobModifyIndex: modifyIndex,
}
2015-09-08 23:24:26 +00:00
wm, err := j.client.write("/v1/jobs", req, &resp, q)
if err != nil {
return "", nil, err
}
return resp.EvalID, wm, nil
}
// List is used to list all of the existing jobs.
2015-09-14 02:55:47 +00:00
func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) {
var resp []*JobListStub
2015-09-09 20:18:50 +00:00
qm, err := j.client.query("/v1/jobs", &resp, q)
2015-09-08 23:24:26 +00:00
if err != nil {
2015-09-08 23:45:16 +00:00
return nil, qm, err
2015-09-08 23:24:26 +00:00
}
2015-09-17 19:40:51 +00:00
sort.Sort(JobIDSort(resp))
2015-09-08 23:45:16 +00:00
return resp, qm, nil
2015-09-08 23:24:26 +00:00
}
// PrefixList is used to list all existing jobs that match the prefix.
func (j *Jobs) PrefixList(prefix string) ([]*JobListStub, *QueryMeta, error) {
return j.List(&QueryOptions{Prefix: prefix})
}
2015-09-09 00:49:31 +00:00
// Info is used to retrieve information about a particular
2015-09-09 00:20:52 +00:00
// job given its unique ID.
2015-09-09 20:18:50 +00:00
func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) {
2015-09-09 00:20:52 +00:00
var resp Job
2015-09-09 20:18:50 +00:00
qm, err := j.client.query("/v1/job/"+jobID, &resp, q)
2015-09-09 00:20:52 +00:00
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}
2015-09-09 00:49:31 +00:00
// Allocations is used to return the allocs for a given job ID.
2015-09-14 02:55:47 +00:00
func (j *Jobs) Allocations(jobID string, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
var resp []*AllocationListStub
2015-09-09 20:18:50 +00:00
qm, err := j.client.query("/v1/job/"+jobID+"/allocations", &resp, q)
2015-09-09 00:49:31 +00:00
if err != nil {
return nil, nil, err
}
2015-09-17 19:40:51 +00:00
sort.Sort(AllocIndexSort(resp))
2015-09-09 00:49:31 +00:00
return resp, qm, nil
}
2015-09-09 01:42:34 +00:00
// Evaluations is used to query the evaluations associated with
// the given job ID.
2015-09-09 20:18:50 +00:00
func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *QueryMeta, error) {
2015-09-09 01:42:34 +00:00
var resp []*Evaluation
2015-09-09 20:18:50 +00:00
qm, err := j.client.query("/v1/job/"+jobID+"/evaluations", &resp, q)
2015-09-09 01:42:34 +00:00
if err != nil {
return nil, nil, err
}
2015-09-17 19:40:51 +00:00
sort.Sort(EvalIndexSort(resp))
2015-09-09 01:42:34 +00:00
return resp, qm, nil
}
// Deregister is used to remove an existing job.
func (j *Jobs) Deregister(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
2015-09-17 00:12:48 +00:00
var resp deregisterJobResponse
wm, err := j.client.delete("/v1/job/"+jobID, &resp, q)
2015-09-09 01:42:34 +00:00
if err != nil {
2015-09-17 00:12:48 +00:00
return "", nil, err
2015-09-09 01:42:34 +00:00
}
2015-09-17 00:12:48 +00:00
return resp.EvalID, wm, nil
2015-09-09 01:42:34 +00:00
}
2015-09-10 01:39:24 +00:00
// ForceEvaluate is used to force-evaluate an existing job.
func (j *Jobs) ForceEvaluate(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
var resp registerJobResponse
wm, err := j.client.write("/v1/job/"+jobID+"/evaluate", nil, &resp, q)
if err != nil {
return "", nil, err
}
return resp.EvalID, wm, nil
}
2016-01-19 19:09:36 +00:00
// PeriodicForce spawns a new instance of the periodic job and returns the eval ID
func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta, error) {
var resp periodicForceResponse
wm, err := j.client.write("/v1/job/"+jobID+"/periodic/force", nil, &resp, q)
if err != nil {
return "", nil, err
}
return resp.EvalID, wm, nil
}
2016-05-12 01:51:48 +00:00
func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) {
if job == nil {
return nil, nil, fmt.Errorf("must pass non-nil job")
}
var resp JobPlanResponse
req := &JobPlanRequest{
Job: job,
Diff: diff,
}
wm, err := j.client.write("/v1/job/"+job.ID+"/plan", req, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}
func (j *Jobs) Summary(jobID string, q *QueryOptions) (*JobSummary, *QueryMeta, error) {
var resp JobSummary
qm, err := j.client.query("/v1/job/"+jobID+"/summary", &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}
2016-01-19 19:09:36 +00:00
// periodicForceResponse is used to deserialize a force response
type periodicForceResponse struct {
EvalID string
}
// UpdateStrategy is for serializing update strategy for a job.
type UpdateStrategy struct {
Stagger time.Duration
MaxParallel int
}
// PeriodicConfig is for serializing periodic config for a job.
type PeriodicConfig struct {
Enabled bool
Spec string
SpecType string
ProhibitOverlap bool
}
2015-09-08 23:24:26 +00:00
// Job is used to serialize a job.
type Job struct {
2015-09-16 18:19:38 +00:00
Region string
2015-09-08 23:24:26 +00:00
ID string
Name string
Type string
Priority int
AllAtOnce bool
Datacenters []string
2015-09-09 02:27:04 +00:00
Constraints []*Constraint
2015-09-10 00:29:43 +00:00
TaskGroups []*TaskGroup
Update *UpdateStrategy
Periodic *PeriodicConfig
2015-09-08 23:24:26 +00:00
Meta map[string]string
2016-08-17 04:32:25 +00:00
VaultToken string
2015-09-08 23:24:26 +00:00
Status string
StatusDescription string
2015-09-14 02:55:47 +00:00
CreateIndex uint64
ModifyIndex uint64
2016-06-08 23:48:02 +00:00
JobModifyIndex uint64
2015-09-14 02:55:47 +00:00
}
// JobSummary summarizes the state of the allocations of a job
type JobSummary struct {
JobID string
Summary map[string]TaskGroupSummary
// Raft Indexes
CreateIndex uint64
ModifyIndex uint64
}
// TaskGroup summarizes the state of all the allocations of a particular
// TaskGroup
type TaskGroupSummary struct {
Queued int
Complete int
Failed int
Running int
Starting int
Lost int
}
2015-09-14 02:55:47 +00:00
// JobListStub is used to return a subset of information about
// jobs during list operations.
type JobListStub struct {
ID string
ParentID string
2015-09-14 02:55:47 +00:00
Name string
Type string
Priority int
Status string
StatusDescription string
JobSummary *JobSummary
2015-09-14 02:55:47 +00:00
CreateIndex uint64
ModifyIndex uint64
2016-06-08 23:48:02 +00:00
JobModifyIndex uint64
2015-09-08 23:24:26 +00:00
}
2015-09-17 19:40:51 +00:00
// JobIDSort is used to sort jobs by their job ID's.
type JobIDSort []*JobListStub
func (j JobIDSort) Len() int {
return len(j)
}
func (j JobIDSort) Less(a, b int) bool {
return j[a].ID < j[b].ID
}
func (j JobIDSort) Swap(a, b int) {
j[a], j[b] = j[b], j[a]
}
2015-09-10 00:29:43 +00:00
// NewServiceJob creates and returns a new service-style job
// for long-lived processes using the provided name, ID, and
// relative job priority.
2015-09-16 18:42:08 +00:00
func NewServiceJob(id, name, region string, pri int) *Job {
return newJob(id, name, region, JobTypeService, pri)
2015-09-10 00:29:43 +00:00
}
// NewBatchJob creates and returns a new batch-style job for
// short-lived processes using the provided name and ID along
// with the relative job priority.
2015-09-16 18:42:08 +00:00
func NewBatchJob(id, name, region string, pri int) *Job {
return newJob(id, name, region, JobTypeBatch, pri)
2015-09-10 00:29:43 +00:00
}
// newJob is used to create a new Job struct.
2015-09-16 18:42:08 +00:00
func newJob(id, name, region, typ string, pri int) *Job {
2015-09-10 00:29:43 +00:00
return &Job{
2015-09-16 18:42:08 +00:00
Region: region,
ID: id,
Name: name,
Type: typ,
2015-09-10 00:29:43 +00:00
Priority: pri,
}
}
// SetMeta is used to set arbitrary k/v pairs of metadata on a job.
func (j *Job) SetMeta(key, val string) *Job {
if j.Meta == nil {
j.Meta = make(map[string]string)
}
j.Meta[key] = val
return j
}
// AddDatacenter is used to add a datacenter to a job.
func (j *Job) AddDatacenter(dc string) *Job {
j.Datacenters = append(j.Datacenters, dc)
return j
}
// Constrain is used to add a constraint to a job.
func (j *Job) Constrain(c *Constraint) *Job {
j.Constraints = append(j.Constraints, c)
return j
}
// AddTaskGroup adds a task group to an existing job.
func (j *Job) AddTaskGroup(grp *TaskGroup) *Job {
j.TaskGroups = append(j.TaskGroups, grp)
return j
}
2016-01-13 18:19:53 +00:00
// AddPeriodicConfig adds a periodic config to an existing job.
func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job {
j.Periodic = cfg
return j
}
2016-03-29 22:02:14 +00:00
// RegisterJobRequest is used to serialize a job registration
type RegisterJobRequest struct {
2016-06-08 23:48:02 +00:00
Job *Job
2016-07-28 21:48:25 +00:00
EnforceIndex bool `json:",omitempty"`
JobModifyIndex uint64 `json:",omitempty"`
2015-09-08 23:24:26 +00:00
}
// registerJobResponse is used to deserialize a job response
type registerJobResponse struct {
EvalID string
}
2015-09-17 00:12:48 +00:00
// deregisterJobResponse is used to decode a deregister response
type deregisterJobResponse struct {
EvalID string
}
2016-05-12 01:51:48 +00:00
type JobPlanRequest struct {
Job *Job
Diff bool
}
type JobPlanResponse struct {
JobModifyIndex uint64
CreatedEvals []*Evaluation
Diff *JobDiff
Annotations *PlanAnnotations
FailedTGAllocs map[string]*AllocationMetric
NextPeriodicLaunch time.Time
2016-05-12 01:51:48 +00:00
}
type JobDiff struct {
Type string
ID string
Fields []*FieldDiff
Objects []*ObjectDiff
TaskGroups []*TaskGroupDiff
}
type TaskGroupDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
Tasks []*TaskDiff
Updates map[string]uint64
}
type TaskDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
Annotations []string
}
type FieldDiff struct {
Type string
Name string
Old, New string
Annotations []string
}
type ObjectDiff struct {
Type string
Name string
Fields []*FieldDiff
Objects []*ObjectDiff
}
type PlanAnnotations struct {
DesiredTGUpdates map[string]*DesiredUpdates
}
type DesiredUpdates struct {
Ignore uint64
Place uint64
Migrate uint64
Stop uint64
InPlaceUpdate uint64
DestructiveUpdate uint64
}