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