github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/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 Reschedule *ReschedulePolicy 562 Meta map[string]string 563 VaultToken *string `mapstructure:"vault_token"` 564 Status *string 565 StatusDescription *string 566 Stable *bool 567 Version *uint64 568 SubmitTime *int64 569 CreateIndex *uint64 570 ModifyIndex *uint64 571 JobModifyIndex *uint64 572 } 573 574 // IsPeriodic returns whether a job is periodic. 575 func (j *Job) IsPeriodic() bool { 576 return j.Periodic != nil 577 } 578 579 // IsParameterized returns whether a job is parameterized job. 580 func (j *Job) IsParameterized() bool { 581 return j.ParameterizedJob != nil 582 } 583 584 func (j *Job) Canonicalize() { 585 if j.ID == nil { 586 j.ID = helper.StringToPtr("") 587 } 588 if j.Name == nil { 589 j.Name = helper.StringToPtr(*j.ID) 590 } 591 if j.ParentID == nil { 592 j.ParentID = helper.StringToPtr("") 593 } 594 if j.Namespace == nil { 595 j.Namespace = helper.StringToPtr(DefaultNamespace) 596 } 597 if j.Priority == nil { 598 j.Priority = helper.IntToPtr(50) 599 } 600 if j.Stop == nil { 601 j.Stop = helper.BoolToPtr(false) 602 } 603 if j.Region == nil { 604 j.Region = helper.StringToPtr("global") 605 } 606 if j.Namespace == nil { 607 j.Namespace = helper.StringToPtr("default") 608 } 609 if j.Type == nil { 610 j.Type = helper.StringToPtr("service") 611 } 612 if j.AllAtOnce == nil { 613 j.AllAtOnce = helper.BoolToPtr(false) 614 } 615 if j.VaultToken == nil { 616 j.VaultToken = helper.StringToPtr("") 617 } 618 if j.Status == nil { 619 j.Status = helper.StringToPtr("") 620 } 621 if j.StatusDescription == nil { 622 j.StatusDescription = helper.StringToPtr("") 623 } 624 if j.Stable == nil { 625 j.Stable = helper.BoolToPtr(false) 626 } 627 if j.Version == nil { 628 j.Version = helper.Uint64ToPtr(0) 629 } 630 if j.CreateIndex == nil { 631 j.CreateIndex = helper.Uint64ToPtr(0) 632 } 633 if j.ModifyIndex == nil { 634 j.ModifyIndex = helper.Uint64ToPtr(0) 635 } 636 if j.JobModifyIndex == nil { 637 j.JobModifyIndex = helper.Uint64ToPtr(0) 638 } 639 if j.Periodic != nil { 640 j.Periodic.Canonicalize() 641 } 642 if j.Update != nil { 643 j.Update.Canonicalize() 644 } 645 646 for _, tg := range j.TaskGroups { 647 tg.Canonicalize(j) 648 } 649 } 650 651 // JobSummary summarizes the state of the allocations of a job 652 type JobSummary struct { 653 JobID string 654 Namespace string 655 Summary map[string]TaskGroupSummary 656 Children *JobChildrenSummary 657 658 // Raft Indexes 659 CreateIndex uint64 660 ModifyIndex uint64 661 } 662 663 // JobChildrenSummary contains the summary of children job status 664 type JobChildrenSummary struct { 665 Pending int64 666 Running int64 667 Dead int64 668 } 669 670 func (jc *JobChildrenSummary) Sum() int { 671 if jc == nil { 672 return 0 673 } 674 675 return int(jc.Pending + jc.Running + jc.Dead) 676 } 677 678 // TaskGroup summarizes the state of all the allocations of a particular 679 // TaskGroup 680 type TaskGroupSummary struct { 681 Queued int 682 Complete int 683 Failed int 684 Running int 685 Starting int 686 Lost int 687 } 688 689 // JobListStub is used to return a subset of information about 690 // jobs during list operations. 691 type JobListStub struct { 692 ID string 693 ParentID string 694 Name string 695 Type string 696 Priority int 697 Periodic bool 698 ParameterizedJob bool 699 Stop bool 700 Status string 701 StatusDescription string 702 JobSummary *JobSummary 703 CreateIndex uint64 704 ModifyIndex uint64 705 JobModifyIndex uint64 706 SubmitTime int64 707 } 708 709 // JobIDSort is used to sort jobs by their job ID's. 710 type JobIDSort []*JobListStub 711 712 func (j JobIDSort) Len() int { 713 return len(j) 714 } 715 716 func (j JobIDSort) Less(a, b int) bool { 717 return j[a].ID < j[b].ID 718 } 719 720 func (j JobIDSort) Swap(a, b int) { 721 j[a], j[b] = j[b], j[a] 722 } 723 724 // NewServiceJob creates and returns a new service-style job 725 // for long-lived processes using the provided name, ID, and 726 // relative job priority. 727 func NewServiceJob(id, name, region string, pri int) *Job { 728 return newJob(id, name, region, JobTypeService, pri) 729 } 730 731 // NewBatchJob creates and returns a new batch-style job for 732 // short-lived processes using the provided name and ID along 733 // with the relative job priority. 734 func NewBatchJob(id, name, region string, pri int) *Job { 735 return newJob(id, name, region, JobTypeBatch, pri) 736 } 737 738 // newJob is used to create a new Job struct. 739 func newJob(id, name, region, typ string, pri int) *Job { 740 return &Job{ 741 Region: ®ion, 742 ID: &id, 743 Name: &name, 744 Type: &typ, 745 Priority: &pri, 746 } 747 } 748 749 // SetMeta is used to set arbitrary k/v pairs of metadata on a job. 750 func (j *Job) SetMeta(key, val string) *Job { 751 if j.Meta == nil { 752 j.Meta = make(map[string]string) 753 } 754 j.Meta[key] = val 755 return j 756 } 757 758 // AddDatacenter is used to add a datacenter to a job. 759 func (j *Job) AddDatacenter(dc string) *Job { 760 j.Datacenters = append(j.Datacenters, dc) 761 return j 762 } 763 764 // Constrain is used to add a constraint to a job. 765 func (j *Job) Constrain(c *Constraint) *Job { 766 j.Constraints = append(j.Constraints, c) 767 return j 768 } 769 770 // AddTaskGroup adds a task group to an existing job. 771 func (j *Job) AddTaskGroup(grp *TaskGroup) *Job { 772 j.TaskGroups = append(j.TaskGroups, grp) 773 return j 774 } 775 776 // AddPeriodicConfig adds a periodic config to an existing job. 777 func (j *Job) AddPeriodicConfig(cfg *PeriodicConfig) *Job { 778 j.Periodic = cfg 779 return j 780 } 781 782 type WriteRequest struct { 783 // The target region for this write 784 Region string 785 786 // Namespace is the target namespace for this write 787 Namespace string 788 789 // SecretID is the secret ID of an ACL token 790 SecretID string 791 } 792 793 // JobValidateRequest is used to validate a job 794 type JobValidateRequest struct { 795 Job *Job 796 WriteRequest 797 } 798 799 // JobValidateResponse is the response from validate request 800 type JobValidateResponse struct { 801 // DriverConfigValidated indicates whether the agent validated the driver 802 // config 803 DriverConfigValidated bool 804 805 // ValidationErrors is a list of validation errors 806 ValidationErrors []string 807 808 // Error is a string version of any error that may have occurred 809 Error string 810 811 // Warnings contains any warnings about the given job. These may include 812 // deprecation warnings. 813 Warnings string 814 } 815 816 // JobRevertRequest is used to revert a job to a prior version. 817 type JobRevertRequest struct { 818 // JobID is the ID of the job being reverted 819 JobID string 820 821 // JobVersion the version to revert to. 822 JobVersion uint64 823 824 // EnforcePriorVersion if set will enforce that the job is at the given 825 // version before reverting. 826 EnforcePriorVersion *uint64 827 828 WriteRequest 829 } 830 831 // JobUpdateRequest is used to update a job 832 type JobRegisterRequest struct { 833 Job *Job 834 // If EnforceIndex is set then the job will only be registered if the passed 835 // JobModifyIndex matches the current Jobs index. If the index is zero, the 836 // register only occurs if the job is new. 837 EnforceIndex bool 838 JobModifyIndex uint64 839 PolicyOverride bool 840 841 WriteRequest 842 } 843 844 // RegisterJobRequest is used to serialize a job registration 845 type RegisterJobRequest struct { 846 Job *Job 847 EnforceIndex bool `json:",omitempty"` 848 JobModifyIndex uint64 `json:",omitempty"` 849 PolicyOverride bool `json:",omitempty"` 850 } 851 852 // JobRegisterResponse is used to respond to a job registration 853 type JobRegisterResponse struct { 854 EvalID string 855 EvalCreateIndex uint64 856 JobModifyIndex uint64 857 858 // Warnings contains any warnings about the given job. These may include 859 // deprecation warnings. 860 Warnings string 861 862 QueryMeta 863 } 864 865 // JobDeregisterResponse is used to respond to a job deregistration 866 type JobDeregisterResponse struct { 867 EvalID string 868 EvalCreateIndex uint64 869 JobModifyIndex uint64 870 QueryMeta 871 } 872 873 type JobPlanRequest struct { 874 Job *Job 875 Diff bool 876 PolicyOverride bool 877 WriteRequest 878 } 879 880 type JobPlanResponse struct { 881 JobModifyIndex uint64 882 CreatedEvals []*Evaluation 883 Diff *JobDiff 884 Annotations *PlanAnnotations 885 FailedTGAllocs map[string]*AllocationMetric 886 NextPeriodicLaunch time.Time 887 888 // Warnings contains any warnings about the given job. These may include 889 // deprecation warnings. 890 Warnings string 891 } 892 893 type JobDiff struct { 894 Type string 895 ID string 896 Fields []*FieldDiff 897 Objects []*ObjectDiff 898 TaskGroups []*TaskGroupDiff 899 } 900 901 type TaskGroupDiff struct { 902 Type string 903 Name string 904 Fields []*FieldDiff 905 Objects []*ObjectDiff 906 Tasks []*TaskDiff 907 Updates map[string]uint64 908 } 909 910 type TaskDiff struct { 911 Type string 912 Name string 913 Fields []*FieldDiff 914 Objects []*ObjectDiff 915 Annotations []string 916 } 917 918 type FieldDiff struct { 919 Type string 920 Name string 921 Old, New string 922 Annotations []string 923 } 924 925 type ObjectDiff struct { 926 Type string 927 Name string 928 Fields []*FieldDiff 929 Objects []*ObjectDiff 930 } 931 932 type PlanAnnotations struct { 933 DesiredTGUpdates map[string]*DesiredUpdates 934 } 935 936 type DesiredUpdates struct { 937 Ignore uint64 938 Place uint64 939 Migrate uint64 940 Stop uint64 941 InPlaceUpdate uint64 942 DestructiveUpdate uint64 943 Canary uint64 944 } 945 946 type JobDispatchRequest struct { 947 JobID string 948 Payload []byte 949 Meta map[string]string 950 } 951 952 type JobDispatchResponse struct { 953 DispatchedJobID string 954 EvalID string 955 EvalCreateIndex uint64 956 JobCreateIndex uint64 957 WriteMeta 958 } 959 960 // JobVersionsResponse is used for a job get versions request 961 type JobVersionsResponse struct { 962 Versions []*Job 963 Diffs []*JobDiff 964 QueryMeta 965 } 966 967 // JobStabilityRequest is used to marked a job as stable. 968 type JobStabilityRequest struct { 969 // Job to set the stability on 970 JobID string 971 JobVersion uint64 972 973 // Set the stability 974 Stable bool 975 WriteRequest 976 } 977 978 // JobStabilityResponse is the response when marking a job as stable. 979 type JobStabilityResponse struct { 980 JobModifyIndex uint64 981 WriteMeta 982 }