github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/api/jobs.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "net/url" 6 "sort" 7 "strconv" 8 "time" 9 10 "github.com/gorhill/cronexpr" 11 "github.com/hashicorp/nomad/helper" 12 ) 13 14 const ( 15 // JobTypeService indicates a long-running processes 16 JobTypeService = "service" 17 18 // JobTypeBatch indicates a short-lived process 19 JobTypeBatch = "batch" 20 21 // PeriodicSpecCron is used for a cron spec. 22 PeriodicSpecCron = "cron" 23 24 // DefaultNamespace is the default namespace. 25 DefaultNamespace = "default" 26 ) 27 28 const ( 29 // RegisterEnforceIndexErrPrefix is the prefix to use in errors caused by 30 // enforcing the job modify index during registers. 31 RegisterEnforceIndexErrPrefix = "Enforcing job modify index" 32 ) 33 34 // Jobs is used to access the job-specific endpoints. 35 type Jobs struct { 36 client *Client 37 } 38 39 // Jobs returns a handle on the jobs endpoints. 40 func (c *Client) Jobs() *Jobs { 41 return &Jobs{client: c} 42 } 43 44 func (j *Jobs) Validate(job *Job, q *WriteOptions) (*JobValidateResponse, *WriteMeta, error) { 45 var resp JobValidateResponse 46 req := &JobValidateRequest{Job: job} 47 if q != nil { 48 req.WriteRequest = WriteRequest{Region: q.Region} 49 } 50 wm, err := j.client.write("/v1/validate/job", req, &resp, q) 51 return &resp, wm, err 52 } 53 54 // RegisterOptions is used to pass through job registration parameters 55 type RegisterOptions struct { 56 EnforceIndex bool 57 ModifyIndex uint64 58 PolicyOverride bool 59 } 60 61 // Register is used to register a new job. It returns the ID 62 // of the evaluation, along with any errors encountered. 63 func (j *Jobs) Register(job *Job, q *WriteOptions) (*JobRegisterResponse, *WriteMeta, error) { 64 return j.RegisterOpts(job, nil, q) 65 } 66 67 // EnforceRegister is used to register a job enforcing its job modify index. 68 func (j *Jobs) EnforceRegister(job *Job, modifyIndex uint64, q *WriteOptions) (*JobRegisterResponse, *WriteMeta, error) { 69 opts := RegisterOptions{EnforceIndex: true, ModifyIndex: modifyIndex} 70 return j.RegisterOpts(job, &opts, q) 71 } 72 73 // Register is used to register a new job. It returns the ID 74 // of the evaluation, along with any errors encountered. 75 func (j *Jobs) RegisterOpts(job *Job, opts *RegisterOptions, q *WriteOptions) (*JobRegisterResponse, *WriteMeta, error) { 76 // Format the request 77 req := &RegisterJobRequest{ 78 Job: job, 79 } 80 if opts != nil { 81 if opts.EnforceIndex { 82 req.EnforceIndex = true 83 req.JobModifyIndex = opts.ModifyIndex 84 } 85 if opts.PolicyOverride { 86 req.PolicyOverride = true 87 } 88 } 89 90 var resp JobRegisterResponse 91 wm, err := j.client.write("/v1/jobs", req, &resp, q) 92 if err != nil { 93 return nil, nil, err 94 } 95 return &resp, wm, nil 96 } 97 98 // List is used to list all of the existing jobs. 99 func (j *Jobs) List(q *QueryOptions) ([]*JobListStub, *QueryMeta, error) { 100 var resp []*JobListStub 101 qm, err := j.client.query("/v1/jobs", &resp, q) 102 if err != nil { 103 return nil, qm, err 104 } 105 sort.Sort(JobIDSort(resp)) 106 return resp, qm, nil 107 } 108 109 // PrefixList is used to list all existing jobs that match the prefix. 110 func (j *Jobs) PrefixList(prefix string) ([]*JobListStub, *QueryMeta, error) { 111 return j.List(&QueryOptions{Prefix: prefix}) 112 } 113 114 // Info is used to retrieve information about a particular 115 // job given its unique ID. 116 func (j *Jobs) Info(jobID string, q *QueryOptions) (*Job, *QueryMeta, error) { 117 var resp Job 118 qm, err := j.client.query("/v1/job/"+jobID, &resp, q) 119 if err != nil { 120 return nil, nil, err 121 } 122 return &resp, qm, nil 123 } 124 125 // Versions is used to retrieve all versions of a particular job given its 126 // unique ID. 127 func (j *Jobs) Versions(jobID string, diffs bool, q *QueryOptions) ([]*Job, []*JobDiff, *QueryMeta, error) { 128 var resp JobVersionsResponse 129 qm, err := j.client.query(fmt.Sprintf("/v1/job/%s/versions?diffs=%v", jobID, diffs), &resp, q) 130 if err != nil { 131 return nil, nil, nil, err 132 } 133 return resp.Versions, resp.Diffs, qm, nil 134 } 135 136 // Allocations is used to return the allocs for a given job ID. 137 func (j *Jobs) Allocations(jobID string, allAllocs bool, q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) { 138 var resp []*AllocationListStub 139 u, err := url.Parse("/v1/job/" + jobID + "/allocations") 140 if err != nil { 141 return nil, nil, err 142 } 143 144 v := u.Query() 145 v.Add("all", strconv.FormatBool(allAllocs)) 146 u.RawQuery = v.Encode() 147 148 qm, err := j.client.query(u.String(), &resp, q) 149 if err != nil { 150 return nil, nil, err 151 } 152 sort.Sort(AllocIndexSort(resp)) 153 return resp, qm, nil 154 } 155 156 // Deployments is used to query the deployments associated with the given job 157 // ID. 158 func (j *Jobs) Deployments(jobID string, q *QueryOptions) ([]*Deployment, *QueryMeta, error) { 159 var resp []*Deployment 160 qm, err := j.client.query("/v1/job/"+jobID+"/deployments", &resp, q) 161 if err != nil { 162 return nil, nil, err 163 } 164 sort.Sort(DeploymentIndexSort(resp)) 165 return resp, qm, nil 166 } 167 168 // LatestDeployment is used to query for the latest deployment associated with 169 // the given job ID. 170 func (j *Jobs) LatestDeployment(jobID string, q *QueryOptions) (*Deployment, *QueryMeta, error) { 171 var resp *Deployment 172 qm, err := j.client.query("/v1/job/"+jobID+"/deployment", &resp, q) 173 if err != nil { 174 return nil, nil, err 175 } 176 return resp, qm, nil 177 } 178 179 // Evaluations is used to query the evaluations associated with the given job 180 // ID. 181 func (j *Jobs) Evaluations(jobID string, q *QueryOptions) ([]*Evaluation, *QueryMeta, error) { 182 var resp []*Evaluation 183 qm, err := j.client.query("/v1/job/"+jobID+"/evaluations", &resp, q) 184 if err != nil { 185 return nil, nil, err 186 } 187 sort.Sort(EvalIndexSort(resp)) 188 return resp, qm, nil 189 } 190 191 // Deregister is used to remove an existing job. If purge is set to true, the job 192 // is deregistered and purged from the system versus still being queryable and 193 // eventually GC'ed from the system. Most callers should not specify purge. 194 func (j *Jobs) Deregister(jobID string, purge bool, q *WriteOptions) (string, *WriteMeta, error) { 195 var resp JobDeregisterResponse 196 wm, err := j.client.delete(fmt.Sprintf("/v1/job/%v?purge=%t", jobID, purge), &resp, q) 197 if err != nil { 198 return "", nil, err 199 } 200 return resp.EvalID, wm, nil 201 } 202 203 // ForceEvaluate is used to force-evaluate an existing job. 204 func (j *Jobs) ForceEvaluate(jobID string, q *WriteOptions) (string, *WriteMeta, error) { 205 var resp JobRegisterResponse 206 wm, err := j.client.write("/v1/job/"+jobID+"/evaluate", nil, &resp, q) 207 if err != nil { 208 return "", nil, err 209 } 210 return resp.EvalID, wm, nil 211 } 212 213 // PeriodicForce spawns a new instance of the periodic job and returns the eval ID 214 func (j *Jobs) PeriodicForce(jobID string, q *WriteOptions) (string, *WriteMeta, error) { 215 var resp periodicForceResponse 216 wm, err := j.client.write("/v1/job/"+jobID+"/periodic/force", nil, &resp, q) 217 if err != nil { 218 return "", nil, err 219 } 220 return resp.EvalID, wm, nil 221 } 222 223 // PlanOptions is used to pass through job planning parameters 224 type PlanOptions struct { 225 Diff bool 226 PolicyOverride bool 227 } 228 229 func (j *Jobs) Plan(job *Job, diff bool, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) { 230 opts := PlanOptions{Diff: diff} 231 return j.PlanOpts(job, &opts, q) 232 } 233 234 func (j *Jobs) PlanOpts(job *Job, opts *PlanOptions, q *WriteOptions) (*JobPlanResponse, *WriteMeta, error) { 235 if job == nil { 236 return nil, nil, fmt.Errorf("must pass non-nil job") 237 } 238 239 // Setup the request 240 req := &JobPlanRequest{ 241 Job: job, 242 } 243 if opts != nil { 244 req.Diff = opts.Diff 245 req.PolicyOverride = opts.PolicyOverride 246 } 247 248 var resp JobPlanResponse 249 wm, err := j.client.write("/v1/job/"+*job.ID+"/plan", req, &resp, q) 250 if err != nil { 251 return nil, nil, err 252 } 253 return &resp, wm, nil 254 } 255 256 func (j *Jobs) Summary(jobID string, q *QueryOptions) (*JobSummary, *QueryMeta, error) { 257 var resp JobSummary 258 qm, err := j.client.query("/v1/job/"+jobID+"/summary", &resp, q) 259 if err != nil { 260 return nil, nil, err 261 } 262 return &resp, qm, nil 263 } 264 265 func (j *Jobs) Dispatch(jobID string, meta map[string]string, 266 payload []byte, q *WriteOptions) (*JobDispatchResponse, *WriteMeta, error) { 267 var resp JobDispatchResponse 268 req := &JobDispatchRequest{ 269 JobID: jobID, 270 Meta: meta, 271 Payload: payload, 272 } 273 wm, err := j.client.write("/v1/job/"+jobID+"/dispatch", req, &resp, q) 274 if err != nil { 275 return nil, nil, err 276 } 277 return &resp, wm, nil 278 } 279 280 // Revert is used to revert the given job to the passed version. If 281 // enforceVersion is set, the job is only reverted if the current version is at 282 // the passed version. 283 func (j *Jobs) Revert(jobID string, version uint64, enforcePriorVersion *uint64, 284 q *WriteOptions) (*JobRegisterResponse, *WriteMeta, error) { 285 286 var resp JobRegisterResponse 287 req := &JobRevertRequest{ 288 JobID: jobID, 289 JobVersion: version, 290 EnforcePriorVersion: enforcePriorVersion, 291 } 292 wm, err := j.client.write("/v1/job/"+jobID+"/revert", req, &resp, q) 293 if err != nil { 294 return nil, nil, err 295 } 296 return &resp, wm, nil 297 } 298 299 // Stable is used to mark a job version's stability. 300 func (j *Jobs) Stable(jobID string, version uint64, stable bool, 301 q *WriteOptions) (*JobStabilityResponse, *WriteMeta, error) { 302 303 var resp JobStabilityResponse 304 req := &JobStabilityRequest{ 305 JobID: jobID, 306 JobVersion: version, 307 Stable: stable, 308 } 309 wm, err := j.client.write("/v1/job/"+jobID+"/stable", req, &resp, q) 310 if err != nil { 311 return nil, nil, err 312 } 313 return &resp, wm, nil 314 } 315 316 // periodicForceResponse is used to deserialize a force response 317 type periodicForceResponse struct { 318 EvalID string 319 } 320 321 // UpdateStrategy defines a task groups update strategy. 322 type UpdateStrategy struct { 323 Stagger *time.Duration `mapstructure:"stagger"` 324 MaxParallel *int `mapstructure:"max_parallel"` 325 HealthCheck *string `mapstructure:"health_check"` 326 MinHealthyTime *time.Duration `mapstructure:"min_healthy_time"` 327 HealthyDeadline *time.Duration `mapstructure:"healthy_deadline"` 328 AutoRevert *bool `mapstructure:"auto_revert"` 329 Canary *int `mapstructure:"canary"` 330 } 331 332 // DefaultUpdateStrategy provides a baseline that can be used to upgrade 333 // jobs with the old policy or for populating field defaults. 334 func DefaultUpdateStrategy() *UpdateStrategy { 335 return &UpdateStrategy{ 336 Stagger: helper.TimeToPtr(30 * time.Second), 337 MaxParallel: helper.IntToPtr(1), 338 HealthCheck: helper.StringToPtr("checks"), 339 MinHealthyTime: helper.TimeToPtr(10 * time.Second), 340 HealthyDeadline: helper.TimeToPtr(5 * time.Minute), 341 AutoRevert: helper.BoolToPtr(false), 342 Canary: helper.IntToPtr(0), 343 } 344 } 345 346 func (u *UpdateStrategy) Copy() *UpdateStrategy { 347 if u == nil { 348 return nil 349 } 350 351 copy := new(UpdateStrategy) 352 353 if u.Stagger != nil { 354 copy.Stagger = helper.TimeToPtr(*u.Stagger) 355 } 356 357 if u.MaxParallel != nil { 358 copy.MaxParallel = helper.IntToPtr(*u.MaxParallel) 359 } 360 361 if u.HealthCheck != nil { 362 copy.HealthCheck = helper.StringToPtr(*u.HealthCheck) 363 } 364 365 if u.MinHealthyTime != nil { 366 copy.MinHealthyTime = helper.TimeToPtr(*u.MinHealthyTime) 367 } 368 369 if u.HealthyDeadline != nil { 370 copy.HealthyDeadline = helper.TimeToPtr(*u.HealthyDeadline) 371 } 372 373 if u.AutoRevert != nil { 374 copy.AutoRevert = helper.BoolToPtr(*u.AutoRevert) 375 } 376 377 if u.Canary != nil { 378 copy.Canary = helper.IntToPtr(*u.Canary) 379 } 380 381 return copy 382 } 383 384 func (u *UpdateStrategy) Merge(o *UpdateStrategy) { 385 if o == nil { 386 return 387 } 388 389 if o.Stagger != nil { 390 u.Stagger = helper.TimeToPtr(*o.Stagger) 391 } 392 393 if o.MaxParallel != nil { 394 u.MaxParallel = helper.IntToPtr(*o.MaxParallel) 395 } 396 397 if o.HealthCheck != nil { 398 u.HealthCheck = helper.StringToPtr(*o.HealthCheck) 399 } 400 401 if o.MinHealthyTime != nil { 402 u.MinHealthyTime = helper.TimeToPtr(*o.MinHealthyTime) 403 } 404 405 if o.HealthyDeadline != nil { 406 u.HealthyDeadline = helper.TimeToPtr(*o.HealthyDeadline) 407 } 408 409 if o.AutoRevert != nil { 410 u.AutoRevert = helper.BoolToPtr(*o.AutoRevert) 411 } 412 413 if o.Canary != nil { 414 u.Canary = helper.IntToPtr(*o.Canary) 415 } 416 } 417 418 func (u *UpdateStrategy) Canonicalize() { 419 d := DefaultUpdateStrategy() 420 421 if u.MaxParallel == nil { 422 u.MaxParallel = d.MaxParallel 423 } 424 425 if u.Stagger == nil { 426 u.Stagger = d.Stagger 427 } 428 429 if u.HealthCheck == nil { 430 u.HealthCheck = d.HealthCheck 431 } 432 433 if u.HealthyDeadline == nil { 434 u.HealthyDeadline = d.HealthyDeadline 435 } 436 437 if u.MinHealthyTime == nil { 438 u.MinHealthyTime = d.MinHealthyTime 439 } 440 441 if u.AutoRevert == nil { 442 u.AutoRevert = d.AutoRevert 443 } 444 445 if u.Canary == nil { 446 u.Canary = d.Canary 447 } 448 } 449 450 // Empty returns whether the UpdateStrategy is empty or has user defined values. 451 func (u *UpdateStrategy) Empty() bool { 452 if u == nil { 453 return true 454 } 455 456 if u.Stagger != nil && *u.Stagger != 0 { 457 return false 458 } 459 460 if u.MaxParallel != nil && *u.MaxParallel != 0 { 461 return false 462 } 463 464 if u.HealthCheck != nil && *u.HealthCheck != "" { 465 return false 466 } 467 468 if u.MinHealthyTime != nil && *u.MinHealthyTime != 0 { 469 return false 470 } 471 472 if u.HealthyDeadline != nil && *u.HealthyDeadline != 0 { 473 return false 474 } 475 476 if u.AutoRevert != nil && *u.AutoRevert { 477 return false 478 } 479 480 if u.Canary != nil && *u.Canary != 0 { 481 return false 482 } 483 484 return true 485 } 486 487 // PeriodicConfig is for serializing periodic config for a job. 488 type PeriodicConfig struct { 489 Enabled *bool 490 Spec *string 491 SpecType *string 492 ProhibitOverlap *bool `mapstructure:"prohibit_overlap"` 493 TimeZone *string `mapstructure:"time_zone"` 494 } 495 496 func (p *PeriodicConfig) Canonicalize() { 497 if p.Enabled == nil { 498 p.Enabled = helper.BoolToPtr(true) 499 } 500 if p.Spec == nil { 501 p.Spec = helper.StringToPtr("") 502 } 503 if p.SpecType == nil { 504 p.SpecType = helper.StringToPtr(PeriodicSpecCron) 505 } 506 if p.ProhibitOverlap == nil { 507 p.ProhibitOverlap = helper.BoolToPtr(false) 508 } 509 if p.TimeZone == nil || *p.TimeZone == "" { 510 p.TimeZone = helper.StringToPtr("UTC") 511 } 512 } 513 514 // Next returns the closest time instant matching the spec that is after the 515 // passed time. If no matching instance exists, the zero value of time.Time is 516 // returned. The `time.Location` of the returned value matches that of the 517 // passed time. 518 func (p *PeriodicConfig) Next(fromTime time.Time) time.Time { 519 if *p.SpecType == PeriodicSpecCron { 520 if e, err := cronexpr.Parse(*p.Spec); err == nil { 521 return e.Next(fromTime) 522 } 523 } 524 525 return time.Time{} 526 } 527 528 func (p *PeriodicConfig) GetLocation() (*time.Location, error) { 529 if p.TimeZone == nil || *p.TimeZone == "" { 530 return time.UTC, nil 531 } 532 533 return time.LoadLocation(*p.TimeZone) 534 } 535 536 // ParameterizedJobConfig is used to configure the parameterized job. 537 type ParameterizedJobConfig struct { 538 Payload string 539 MetaRequired []string `mapstructure:"meta_required"` 540 MetaOptional []string `mapstructure:"meta_optional"` 541 } 542 543 // Job is used to serialize a job. 544 type Job struct { 545 Stop *bool 546 Region *string 547 Namespace *string 548 ID *string 549 ParentID *string 550 Name *string 551 Type *string 552 Priority *int 553 AllAtOnce *bool `mapstructure:"all_at_once"` 554 Datacenters []string 555 Constraints []*Constraint 556 TaskGroups []*TaskGroup 557 Update *UpdateStrategy 558 Periodic *PeriodicConfig 559 ParameterizedJob *ParameterizedJobConfig 560 Payload []byte 561 Meta map[string]string 562 VaultToken *string `mapstructure:"vault_token"` 563 Status *string 564 StatusDescription *string 565 Stable *bool 566 Version *uint64 567 SubmitTime *int64 568 CreateIndex *uint64 569 ModifyIndex *uint64 570 JobModifyIndex *uint64 571 } 572 573 // IsPeriodic returns whether a job is periodic. 574 func (j *Job) IsPeriodic() bool { 575 return j.Periodic != nil 576 } 577 578 // IsParameterized returns whether a job is parameterized job. 579 func (j *Job) IsParameterized() bool { 580 return j.ParameterizedJob != nil 581 } 582 583 func (j *Job) Canonicalize() { 584 if j.ID == nil { 585 j.ID = helper.StringToPtr("") 586 } 587 if j.Name == nil { 588 j.Name = helper.StringToPtr(*j.ID) 589 } 590 if j.ParentID == nil { 591 j.ParentID = helper.StringToPtr("") 592 } 593 if j.Namespace == nil { 594 j.Namespace = helper.StringToPtr(DefaultNamespace) 595 } 596 if j.Priority == nil { 597 j.Priority = helper.IntToPtr(50) 598 } 599 if j.Stop == nil { 600 j.Stop = helper.BoolToPtr(false) 601 } 602 if j.Region == nil { 603 j.Region = helper.StringToPtr("global") 604 } 605 if j.Namespace == nil { 606 j.Namespace = helper.StringToPtr("default") 607 } 608 if j.Type == nil { 609 j.Type = helper.StringToPtr("service") 610 } 611 if j.AllAtOnce == nil { 612 j.AllAtOnce = helper.BoolToPtr(false) 613 } 614 if j.VaultToken == nil { 615 j.VaultToken = helper.StringToPtr("") 616 } 617 if j.Status == nil { 618 j.Status = helper.StringToPtr("") 619 } 620 if j.StatusDescription == nil { 621 j.StatusDescription = helper.StringToPtr("") 622 } 623 if j.Stable == nil { 624 j.Stable = helper.BoolToPtr(false) 625 } 626 if j.Version == nil { 627 j.Version = helper.Uint64ToPtr(0) 628 } 629 if j.CreateIndex == nil { 630 j.CreateIndex = helper.Uint64ToPtr(0) 631 } 632 if j.ModifyIndex == nil { 633 j.ModifyIndex = helper.Uint64ToPtr(0) 634 } 635 if j.JobModifyIndex == nil { 636 j.JobModifyIndex = helper.Uint64ToPtr(0) 637 } 638 if j.Periodic != nil { 639 j.Periodic.Canonicalize() 640 } 641 if j.Update != nil { 642 j.Update.Canonicalize() 643 } 644 645 for _, tg := range j.TaskGroups { 646 tg.Canonicalize(j) 647 } 648 } 649 650 // JobSummary summarizes the state of the allocations of a job 651 type JobSummary struct { 652 JobID string 653 Namespace string 654 Summary map[string]TaskGroupSummary 655 Children *JobChildrenSummary 656 657 // Raft Indexes 658 CreateIndex uint64 659 ModifyIndex uint64 660 } 661 662 // JobChildrenSummary contains the summary of children job status 663 type JobChildrenSummary struct { 664 Pending int64 665 Running int64 666 Dead int64 667 } 668 669 func (jc *JobChildrenSummary) Sum() int { 670 if jc == nil { 671 return 0 672 } 673 674 return int(jc.Pending + jc.Running + jc.Dead) 675 } 676 677 // TaskGroup summarizes the state of all the allocations of a particular 678 // TaskGroup 679 type TaskGroupSummary struct { 680 Queued int 681 Complete int 682 Failed int 683 Running int 684 Starting int 685 Lost int 686 } 687 688 // JobListStub is used to return a subset of information about 689 // jobs during list operations. 690 type JobListStub struct { 691 ID string 692 ParentID string 693 Name string 694 Type string 695 Priority int 696 Periodic bool 697 ParameterizedJob bool 698 Stop bool 699 Status string 700 StatusDescription string 701 JobSummary *JobSummary 702 CreateIndex uint64 703 ModifyIndex uint64 704 JobModifyIndex uint64 705 SubmitTime int64 706 } 707 708 // JobIDSort is used to sort jobs by their job ID's. 709 type JobIDSort []*JobListStub 710 711 func (j JobIDSort) Len() int { 712 return len(j) 713 } 714 715 func (j JobIDSort) Less(a, b int) bool { 716 return j[a].ID < j[b].ID 717 } 718 719 func (j JobIDSort) Swap(a, b int) { 720 j[a], j[b] = j[b], j[a] 721 } 722 723 // NewServiceJob creates and returns a new service-style job 724 // for long-lived processes using the provided name, ID, and 725 // relative job priority. 726 func NewServiceJob(id, name, region string, pri int) *Job { 727 return newJob(id, name, region, JobTypeService, pri) 728 } 729 730 // NewBatchJob creates and returns a new batch-style job for 731 // short-lived processes using the provided name and ID along 732 // with the relative job priority. 733 func NewBatchJob(id, name, region string, pri int) *Job { 734 return newJob(id, name, region, JobTypeBatch, pri) 735 } 736 737 // newJob is used to create a new Job struct. 738 func newJob(id, name, region, typ string, pri int) *Job { 739 return &Job{ 740 Region: ®ion, 741 ID: &id, 742 Name: &name, 743 Type: &typ, 744 Priority: &pri, 745 } 746 } 747 748 // SetMeta is used to set arbitrary k/v pairs of metadata on a job. 749 func (j *Job) SetMeta(key, val string) *Job { 750 if j.Meta == nil { 751 j.Meta = make(map[string]string) 752 } 753 j.Meta[key] = val 754 return j 755 } 756 757 // AddDatacenter is used to add a datacenter to a job. 758 func (j *Job) AddDatacenter(dc string) *Job { 759 j.Datacenters = append(j.Datacenters, dc) 760 return j 761 } 762 763 // Constrain is used to add a constraint to a job. 764 func (j *Job) Constrain(c *Constraint) *Job { 765 j.Constraints = append(j.Constraints, c) 766 return j 767 } 768 769 // AddTaskGroup adds a task group to an existing job. 770 func (j *Job) AddTaskGroup(grp *TaskGroup) *Job { 771 j.TaskGroups = append(j.TaskGroups, grp) 772 return j 773 } 774 775 // AddPeriodicConfig adds a periodic config to an existing job. 776 func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job { 777 j.Periodic = cfg 778 return j 779 } 780 781 type WriteRequest struct { 782 // The target region for this write 783 Region string 784 785 // Namespace is the target namespace for this write 786 Namespace string 787 788 // SecretID is the secret ID of an ACL token 789 SecretID string 790 } 791 792 // JobValidateRequest is used to validate a job 793 type JobValidateRequest struct { 794 Job *Job 795 WriteRequest 796 } 797 798 // JobValidateResponse is the response from validate request 799 type JobValidateResponse struct { 800 // DriverConfigValidated indicates whether the agent validated the driver 801 // config 802 DriverConfigValidated bool 803 804 // ValidationErrors is a list of validation errors 805 ValidationErrors []string 806 807 // Error is a string version of any error that may have occurred 808 Error string 809 810 // Warnings contains any warnings about the given job. These may include 811 // deprecation warnings. 812 Warnings string 813 } 814 815 // JobRevertRequest is used to revert a job to a prior version. 816 type JobRevertRequest struct { 817 // JobID is the ID of the job being reverted 818 JobID string 819 820 // JobVersion the version to revert to. 821 JobVersion uint64 822 823 // EnforcePriorVersion if set will enforce that the job is at the given 824 // version before reverting. 825 EnforcePriorVersion *uint64 826 827 WriteRequest 828 } 829 830 // JobUpdateRequest is used to update a job 831 type JobRegisterRequest struct { 832 Job *Job 833 // If EnforceIndex is set then the job will only be registered if the passed 834 // JobModifyIndex matches the current Jobs index. If the index is zero, the 835 // register only occurs if the job is new. 836 EnforceIndex bool 837 JobModifyIndex uint64 838 PolicyOverride bool 839 840 WriteRequest 841 } 842 843 // RegisterJobRequest is used to serialize a job registration 844 type RegisterJobRequest struct { 845 Job *Job 846 EnforceIndex bool `json:",omitempty"` 847 JobModifyIndex uint64 `json:",omitempty"` 848 PolicyOverride bool `json:",omitempty"` 849 } 850 851 // JobRegisterResponse is used to respond to a job registration 852 type JobRegisterResponse struct { 853 EvalID string 854 EvalCreateIndex uint64 855 JobModifyIndex uint64 856 857 // Warnings contains any warnings about the given job. These may include 858 // deprecation warnings. 859 Warnings string 860 861 QueryMeta 862 } 863 864 // JobDeregisterResponse is used to respond to a job deregistration 865 type JobDeregisterResponse struct { 866 EvalID string 867 EvalCreateIndex uint64 868 JobModifyIndex uint64 869 QueryMeta 870 } 871 872 type JobPlanRequest struct { 873 Job *Job 874 Diff bool 875 PolicyOverride bool 876 WriteRequest 877 } 878 879 type JobPlanResponse struct { 880 JobModifyIndex uint64 881 CreatedEvals []*Evaluation 882 Diff *JobDiff 883 Annotations *PlanAnnotations 884 FailedTGAllocs map[string]*AllocationMetric 885 NextPeriodicLaunch time.Time 886 887 // Warnings contains any warnings about the given job. These may include 888 // deprecation warnings. 889 Warnings string 890 } 891 892 type JobDiff struct { 893 Type string 894 ID string 895 Fields []*FieldDiff 896 Objects []*ObjectDiff 897 TaskGroups []*TaskGroupDiff 898 } 899 900 type TaskGroupDiff struct { 901 Type string 902 Name string 903 Fields []*FieldDiff 904 Objects []*ObjectDiff 905 Tasks []*TaskDiff 906 Updates map[string]uint64 907 } 908 909 type TaskDiff struct { 910 Type string 911 Name string 912 Fields []*FieldDiff 913 Objects []*ObjectDiff 914 Annotations []string 915 } 916 917 type FieldDiff struct { 918 Type string 919 Name string 920 Old, New string 921 Annotations []string 922 } 923 924 type ObjectDiff struct { 925 Type string 926 Name string 927 Fields []*FieldDiff 928 Objects []*ObjectDiff 929 } 930 931 type PlanAnnotations struct { 932 DesiredTGUpdates map[string]*DesiredUpdates 933 } 934 935 type DesiredUpdates struct { 936 Ignore uint64 937 Place uint64 938 Migrate uint64 939 Stop uint64 940 InPlaceUpdate uint64 941 DestructiveUpdate uint64 942 Canary uint64 943 } 944 945 type JobDispatchRequest struct { 946 JobID string 947 Payload []byte 948 Meta map[string]string 949 } 950 951 type JobDispatchResponse struct { 952 DispatchedJobID string 953 EvalID string 954 EvalCreateIndex uint64 955 JobCreateIndex uint64 956 WriteMeta 957 } 958 959 // JobVersionsResponse is used for a job get versions request 960 type JobVersionsResponse struct { 961 Versions []*Job 962 Diffs []*JobDiff 963 QueryMeta 964 } 965 966 // JobStabilityRequest is used to marked a job as stable. 967 type JobStabilityRequest struct { 968 // Job to set the stability on 969 JobID string 970 JobVersion uint64 971 972 // Set the stability 973 Stable bool 974 WriteRequest 975 } 976 977 // JobStabilityResponse is the response when marking a job as stable. 978 type JobStabilityResponse struct { 979 JobModifyIndex uint64 980 WriteMeta 981 }