1package api 2 3import ( 4 "fmt" 5 "path" 6 "path/filepath" 7 "strings" 8 "time" 9) 10 11const ( 12 // RestartPolicyModeDelay causes an artificial delay till the next interval is 13 // reached when the specified attempts have been reached in the interval. 14 RestartPolicyModeDelay = "delay" 15 16 // RestartPolicyModeFail causes a job to fail if the specified number of 17 // attempts are reached within an interval. 18 RestartPolicyModeFail = "fail" 19) 20 21// MemoryStats holds memory usage related stats 22type MemoryStats struct { 23 RSS uint64 24 Cache uint64 25 Swap uint64 26 Usage uint64 27 MaxUsage uint64 28 KernelUsage uint64 29 KernelMaxUsage uint64 30 Measured []string 31} 32 33// CpuStats holds cpu usage related stats 34type CpuStats struct { 35 SystemMode float64 36 UserMode float64 37 TotalTicks float64 38 ThrottledPeriods uint64 39 ThrottledTime uint64 40 Percent float64 41 Measured []string 42} 43 44// ResourceUsage holds information related to cpu and memory stats 45type ResourceUsage struct { 46 MemoryStats *MemoryStats 47 CpuStats *CpuStats 48 DeviceStats []*DeviceGroupStats 49} 50 51// TaskResourceUsage holds aggregated resource usage of all processes in a Task 52// and the resource usage of the individual pids 53type TaskResourceUsage struct { 54 ResourceUsage *ResourceUsage 55 Timestamp int64 56 Pids map[string]*ResourceUsage 57} 58 59// AllocResourceUsage holds the aggregated task resource usage of the 60// allocation. 61type AllocResourceUsage struct { 62 ResourceUsage *ResourceUsage 63 Tasks map[string]*TaskResourceUsage 64 Timestamp int64 65} 66 67// RestartPolicy defines how the Nomad client restarts 68// tasks in a taskgroup when they fail 69type RestartPolicy struct { 70 Interval *time.Duration 71 Attempts *int 72 Delay *time.Duration 73 Mode *string 74} 75 76func (r *RestartPolicy) Merge(rp *RestartPolicy) { 77 if rp.Interval != nil { 78 r.Interval = rp.Interval 79 } 80 if rp.Attempts != nil { 81 r.Attempts = rp.Attempts 82 } 83 if rp.Delay != nil { 84 r.Delay = rp.Delay 85 } 86 if rp.Mode != nil { 87 r.Mode = rp.Mode 88 } 89} 90 91// Reschedule configures how Tasks are rescheduled when they crash or fail. 92type ReschedulePolicy struct { 93 // Attempts limits the number of rescheduling attempts that can occur in an interval. 94 Attempts *int `mapstructure:"attempts"` 95 96 // Interval is a duration in which we can limit the number of reschedule attempts. 97 Interval *time.Duration `mapstructure:"interval"` 98 99 // Delay is a minimum duration to wait between reschedule attempts. 100 // The delay function determines how much subsequent reschedule attempts are delayed by. 101 Delay *time.Duration `mapstructure:"delay"` 102 103 // DelayFunction determines how the delay progressively changes on subsequent reschedule 104 // attempts. Valid values are "exponential", "constant", and "fibonacci". 105 DelayFunction *string `mapstructure:"delay_function"` 106 107 // MaxDelay is an upper bound on the delay. 108 MaxDelay *time.Duration `mapstructure:"max_delay"` 109 110 // Unlimited allows rescheduling attempts until they succeed 111 Unlimited *bool `mapstructure:"unlimited"` 112} 113 114func (r *ReschedulePolicy) Merge(rp *ReschedulePolicy) { 115 if rp == nil { 116 return 117 } 118 if rp.Interval != nil { 119 r.Interval = rp.Interval 120 } 121 if rp.Attempts != nil { 122 r.Attempts = rp.Attempts 123 } 124 if rp.Delay != nil { 125 r.Delay = rp.Delay 126 } 127 if rp.DelayFunction != nil { 128 r.DelayFunction = rp.DelayFunction 129 } 130 if rp.MaxDelay != nil { 131 r.MaxDelay = rp.MaxDelay 132 } 133 if rp.Unlimited != nil { 134 r.Unlimited = rp.Unlimited 135 } 136} 137 138func (r *ReschedulePolicy) Canonicalize(jobType string) { 139 dp := NewDefaultReschedulePolicy(jobType) 140 if r.Interval == nil { 141 r.Interval = dp.Interval 142 } 143 if r.Attempts == nil { 144 r.Attempts = dp.Attempts 145 } 146 if r.Delay == nil { 147 r.Delay = dp.Delay 148 } 149 if r.DelayFunction == nil { 150 r.DelayFunction = dp.DelayFunction 151 } 152 if r.MaxDelay == nil { 153 r.MaxDelay = dp.MaxDelay 154 } 155 if r.Unlimited == nil { 156 r.Unlimited = dp.Unlimited 157 } 158} 159 160// Affinity is used to serialize task group affinities 161type Affinity struct { 162 LTarget string // Left-hand target 163 RTarget string // Right-hand target 164 Operand string // Constraint operand (<=, <, =, !=, >, >=), set_contains_all, set_contains_any 165 Weight *int8 // Weight applied to nodes that match the affinity. Can be negative 166} 167 168func NewAffinity(LTarget string, Operand string, RTarget string, Weight int8) *Affinity { 169 return &Affinity{ 170 LTarget: LTarget, 171 RTarget: RTarget, 172 Operand: Operand, 173 Weight: int8ToPtr(Weight), 174 } 175} 176 177func (a *Affinity) Canonicalize() { 178 if a.Weight == nil { 179 a.Weight = int8ToPtr(50) 180 } 181} 182 183func NewDefaultReschedulePolicy(jobType string) *ReschedulePolicy { 184 var dp *ReschedulePolicy 185 switch jobType { 186 case "service": 187 // This needs to be in sync with DefaultServiceJobReschedulePolicy 188 // in nomad/structs/structs.go 189 dp = &ReschedulePolicy{ 190 Delay: timeToPtr(30 * time.Second), 191 DelayFunction: stringToPtr("exponential"), 192 MaxDelay: timeToPtr(1 * time.Hour), 193 Unlimited: boolToPtr(true), 194 195 Attempts: intToPtr(0), 196 Interval: timeToPtr(0), 197 } 198 case "batch": 199 // This needs to be in sync with DefaultBatchJobReschedulePolicy 200 // in nomad/structs/structs.go 201 dp = &ReschedulePolicy{ 202 Attempts: intToPtr(1), 203 Interval: timeToPtr(24 * time.Hour), 204 Delay: timeToPtr(5 * time.Second), 205 DelayFunction: stringToPtr("constant"), 206 207 MaxDelay: timeToPtr(0), 208 Unlimited: boolToPtr(false), 209 } 210 211 case "system": 212 dp = &ReschedulePolicy{ 213 Attempts: intToPtr(0), 214 Interval: timeToPtr(0), 215 Delay: timeToPtr(0), 216 DelayFunction: stringToPtr(""), 217 MaxDelay: timeToPtr(0), 218 Unlimited: boolToPtr(false), 219 } 220 } 221 return dp 222} 223 224func (r *ReschedulePolicy) Copy() *ReschedulePolicy { 225 if r == nil { 226 return nil 227 } 228 nrp := new(ReschedulePolicy) 229 *nrp = *r 230 return nrp 231} 232 233func (p *ReschedulePolicy) String() string { 234 if p == nil { 235 return "" 236 } 237 if *p.Unlimited { 238 return fmt.Sprintf("unlimited with %v delay, max_delay = %v", *p.DelayFunction, *p.MaxDelay) 239 } 240 return fmt.Sprintf("%v in %v with %v delay, max_delay = %v", *p.Attempts, *p.Interval, *p.DelayFunction, *p.MaxDelay) 241} 242 243// Spread is used to serialize task group allocation spread preferences 244type Spread struct { 245 Attribute string 246 Weight *int8 247 SpreadTarget []*SpreadTarget 248} 249 250// SpreadTarget is used to serialize target allocation spread percentages 251type SpreadTarget struct { 252 Value string 253 Percent uint8 254} 255 256func NewSpreadTarget(value string, percent uint8) *SpreadTarget { 257 return &SpreadTarget{ 258 Value: value, 259 Percent: percent, 260 } 261} 262 263func NewSpread(attribute string, weight int8, spreadTargets []*SpreadTarget) *Spread { 264 return &Spread{ 265 Attribute: attribute, 266 Weight: int8ToPtr(weight), 267 SpreadTarget: spreadTargets, 268 } 269} 270 271func (s *Spread) Canonicalize() { 272 if s.Weight == nil { 273 s.Weight = int8ToPtr(50) 274 } 275} 276 277// EphemeralDisk is an ephemeral disk object 278type EphemeralDisk struct { 279 Sticky *bool 280 Migrate *bool 281 SizeMB *int `mapstructure:"size"` 282} 283 284func DefaultEphemeralDisk() *EphemeralDisk { 285 return &EphemeralDisk{ 286 Sticky: boolToPtr(false), 287 Migrate: boolToPtr(false), 288 SizeMB: intToPtr(300), 289 } 290} 291 292func (e *EphemeralDisk) Canonicalize() { 293 if e.Sticky == nil { 294 e.Sticky = boolToPtr(false) 295 } 296 if e.Migrate == nil { 297 e.Migrate = boolToPtr(false) 298 } 299 if e.SizeMB == nil { 300 e.SizeMB = intToPtr(300) 301 } 302} 303 304// MigrateStrategy describes how allocations for a task group should be 305// migrated between nodes (eg when draining). 306type MigrateStrategy struct { 307 MaxParallel *int `mapstructure:"max_parallel"` 308 HealthCheck *string `mapstructure:"health_check"` 309 MinHealthyTime *time.Duration `mapstructure:"min_healthy_time"` 310 HealthyDeadline *time.Duration `mapstructure:"healthy_deadline"` 311} 312 313func DefaultMigrateStrategy() *MigrateStrategy { 314 return &MigrateStrategy{ 315 MaxParallel: intToPtr(1), 316 HealthCheck: stringToPtr("checks"), 317 MinHealthyTime: timeToPtr(10 * time.Second), 318 HealthyDeadline: timeToPtr(5 * time.Minute), 319 } 320} 321 322func (m *MigrateStrategy) Canonicalize() { 323 if m == nil { 324 return 325 } 326 defaults := DefaultMigrateStrategy() 327 if m.MaxParallel == nil { 328 m.MaxParallel = defaults.MaxParallel 329 } 330 if m.HealthCheck == nil { 331 m.HealthCheck = defaults.HealthCheck 332 } 333 if m.MinHealthyTime == nil { 334 m.MinHealthyTime = defaults.MinHealthyTime 335 } 336 if m.HealthyDeadline == nil { 337 m.HealthyDeadline = defaults.HealthyDeadline 338 } 339} 340 341func (m *MigrateStrategy) Merge(o *MigrateStrategy) { 342 if o.MaxParallel != nil { 343 m.MaxParallel = o.MaxParallel 344 } 345 if o.HealthCheck != nil { 346 m.HealthCheck = o.HealthCheck 347 } 348 if o.MinHealthyTime != nil { 349 m.MinHealthyTime = o.MinHealthyTime 350 } 351 if o.HealthyDeadline != nil { 352 m.HealthyDeadline = o.HealthyDeadline 353 } 354} 355 356func (m *MigrateStrategy) Copy() *MigrateStrategy { 357 if m == nil { 358 return nil 359 } 360 nm := new(MigrateStrategy) 361 *nm = *m 362 return nm 363} 364 365// VolumeRequest is a representation of a storage volume that a TaskGroup wishes to use. 366type VolumeRequest struct { 367 Name string 368 Type string 369 Source string 370 ReadOnly bool `mapstructure:"read_only"` 371} 372 373const ( 374 VolumeMountPropagationPrivate = "private" 375 VolumeMountPropagationHostToTask = "host-to-task" 376 VolumeMountPropagationBidirectional = "bidirectional" 377) 378 379// VolumeMount represents the relationship between a destination path in a task 380// and the task group volume that should be mounted there. 381type VolumeMount struct { 382 Volume *string 383 Destination *string 384 ReadOnly *bool `mapstructure:"read_only"` 385 PropagationMode *string `mapstructure:"propagation_mode"` 386} 387 388func (vm *VolumeMount) Canonicalize() { 389 if vm.PropagationMode == nil { 390 vm.PropagationMode = stringToPtr(VolumeMountPropagationPrivate) 391 } 392 if vm.ReadOnly == nil { 393 vm.ReadOnly = boolToPtr(false) 394 } 395} 396 397// TaskGroup is the unit of scheduling. 398type TaskGroup struct { 399 Name *string 400 Count *int 401 Constraints []*Constraint 402 Affinities []*Affinity 403 Tasks []*Task 404 Spreads []*Spread 405 Volumes map[string]*VolumeRequest 406 RestartPolicy *RestartPolicy 407 ReschedulePolicy *ReschedulePolicy 408 EphemeralDisk *EphemeralDisk 409 Update *UpdateStrategy 410 Migrate *MigrateStrategy 411 Networks []*NetworkResource 412 Meta map[string]string 413 Services []*Service 414 ShutdownDelay *time.Duration `mapstructure:"shutdown_delay"` 415} 416 417// NewTaskGroup creates a new TaskGroup. 418func NewTaskGroup(name string, count int) *TaskGroup { 419 return &TaskGroup{ 420 Name: stringToPtr(name), 421 Count: intToPtr(count), 422 } 423} 424 425// Canonicalize sets defaults and merges settings that should be inherited from the job 426func (g *TaskGroup) Canonicalize(job *Job) { 427 if g.Name == nil { 428 g.Name = stringToPtr("") 429 } 430 if g.Count == nil { 431 g.Count = intToPtr(1) 432 } 433 for _, t := range g.Tasks { 434 t.Canonicalize(g, job) 435 } 436 if g.EphemeralDisk == nil { 437 g.EphemeralDisk = DefaultEphemeralDisk() 438 } else { 439 g.EphemeralDisk.Canonicalize() 440 } 441 442 // Merge the update policy from the job 443 if ju, tu := job.Update != nil, g.Update != nil; ju && tu { 444 // Merge the jobs and task groups definition of the update strategy 445 jc := job.Update.Copy() 446 jc.Merge(g.Update) 447 g.Update = jc 448 } else if ju && !job.Update.Empty() { 449 // Inherit the jobs as long as it is non-empty. 450 jc := job.Update.Copy() 451 g.Update = jc 452 } 453 454 if g.Update != nil { 455 g.Update.Canonicalize() 456 } 457 458 // Merge the reschedule policy from the job 459 if jr, tr := job.Reschedule != nil, g.ReschedulePolicy != nil; jr && tr { 460 jobReschedule := job.Reschedule.Copy() 461 jobReschedule.Merge(g.ReschedulePolicy) 462 g.ReschedulePolicy = jobReschedule 463 } else if jr { 464 jobReschedule := job.Reschedule.Copy() 465 g.ReschedulePolicy = jobReschedule 466 } 467 // Only use default reschedule policy for non system jobs 468 if g.ReschedulePolicy == nil && *job.Type != "system" { 469 g.ReschedulePolicy = NewDefaultReschedulePolicy(*job.Type) 470 } 471 if g.ReschedulePolicy != nil { 472 g.ReschedulePolicy.Canonicalize(*job.Type) 473 } 474 // Merge the migrate strategy from the job 475 if jm, tm := job.Migrate != nil, g.Migrate != nil; jm && tm { 476 jobMigrate := job.Migrate.Copy() 477 jobMigrate.Merge(g.Migrate) 478 g.Migrate = jobMigrate 479 } else if jm { 480 jobMigrate := job.Migrate.Copy() 481 g.Migrate = jobMigrate 482 } 483 484 // Merge with default reschedule policy 485 if g.Migrate == nil && *job.Type == "service" { 486 g.Migrate = &MigrateStrategy{} 487 } 488 if g.Migrate != nil { 489 g.Migrate.Canonicalize() 490 } 491 492 var defaultRestartPolicy *RestartPolicy 493 switch *job.Type { 494 case "service", "system": 495 // These needs to be in sync with DefaultServiceJobRestartPolicy in 496 // in nomad/structs/structs.go 497 defaultRestartPolicy = &RestartPolicy{ 498 Delay: timeToPtr(15 * time.Second), 499 Attempts: intToPtr(2), 500 Interval: timeToPtr(30 * time.Minute), 501 Mode: stringToPtr(RestartPolicyModeFail), 502 } 503 default: 504 // These needs to be in sync with DefaultBatchJobRestartPolicy in 505 // in nomad/structs/structs.go 506 defaultRestartPolicy = &RestartPolicy{ 507 Delay: timeToPtr(15 * time.Second), 508 Attempts: intToPtr(3), 509 Interval: timeToPtr(24 * time.Hour), 510 Mode: stringToPtr(RestartPolicyModeFail), 511 } 512 } 513 514 if g.RestartPolicy != nil { 515 defaultRestartPolicy.Merge(g.RestartPolicy) 516 } 517 g.RestartPolicy = defaultRestartPolicy 518 519 for _, spread := range g.Spreads { 520 spread.Canonicalize() 521 } 522 for _, a := range g.Affinities { 523 a.Canonicalize() 524 } 525 for _, n := range g.Networks { 526 n.Canonicalize() 527 } 528 for _, s := range g.Services { 529 s.Canonicalize(nil, g, job) 530 } 531} 532 533// Constrain is used to add a constraint to a task group. 534func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup { 535 g.Constraints = append(g.Constraints, c) 536 return g 537} 538 539// AddMeta is used to add a meta k/v pair to a task group 540func (g *TaskGroup) SetMeta(key, val string) *TaskGroup { 541 if g.Meta == nil { 542 g.Meta = make(map[string]string) 543 } 544 g.Meta[key] = val 545 return g 546} 547 548// AddTask is used to add a new task to a task group. 549func (g *TaskGroup) AddTask(t *Task) *TaskGroup { 550 g.Tasks = append(g.Tasks, t) 551 return g 552} 553 554// AddAffinity is used to add a new affinity to a task group. 555func (g *TaskGroup) AddAffinity(a *Affinity) *TaskGroup { 556 g.Affinities = append(g.Affinities, a) 557 return g 558} 559 560// RequireDisk adds a ephemeral disk to the task group 561func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup { 562 g.EphemeralDisk = disk 563 return g 564} 565 566// AddSpread is used to add a new spread preference to a task group. 567func (g *TaskGroup) AddSpread(s *Spread) *TaskGroup { 568 g.Spreads = append(g.Spreads, s) 569 return g 570} 571 572// LogConfig provides configuration for log rotation 573type LogConfig struct { 574 MaxFiles *int `mapstructure:"max_files"` 575 MaxFileSizeMB *int `mapstructure:"max_file_size"` 576} 577 578func DefaultLogConfig() *LogConfig { 579 return &LogConfig{ 580 MaxFiles: intToPtr(10), 581 MaxFileSizeMB: intToPtr(10), 582 } 583} 584 585func (l *LogConfig) Canonicalize() { 586 if l.MaxFiles == nil { 587 l.MaxFiles = intToPtr(10) 588 } 589 if l.MaxFileSizeMB == nil { 590 l.MaxFileSizeMB = intToPtr(10) 591 } 592} 593 594// DispatchPayloadConfig configures how a task gets its input from a job dispatch 595type DispatchPayloadConfig struct { 596 File string 597} 598 599// Task is a single process in a task group. 600type Task struct { 601 Name string 602 Driver string 603 User string 604 Config map[string]interface{} 605 Constraints []*Constraint 606 Affinities []*Affinity 607 Env map[string]string 608 Services []*Service 609 Resources *Resources 610 Meta map[string]string 611 KillTimeout *time.Duration `mapstructure:"kill_timeout"` 612 LogConfig *LogConfig `mapstructure:"logs"` 613 Artifacts []*TaskArtifact 614 Vault *Vault 615 Templates []*Template 616 DispatchPayload *DispatchPayloadConfig 617 VolumeMounts []*VolumeMount 618 Leader bool 619 ShutdownDelay time.Duration `mapstructure:"shutdown_delay"` 620 KillSignal string `mapstructure:"kill_signal"` 621 Kind string 622} 623 624func (t *Task) Canonicalize(tg *TaskGroup, job *Job) { 625 if t.Resources == nil { 626 t.Resources = &Resources{} 627 } 628 t.Resources.Canonicalize() 629 if t.KillTimeout == nil { 630 t.KillTimeout = timeToPtr(5 * time.Second) 631 } 632 if t.LogConfig == nil { 633 t.LogConfig = DefaultLogConfig() 634 } else { 635 t.LogConfig.Canonicalize() 636 } 637 for _, artifact := range t.Artifacts { 638 artifact.Canonicalize() 639 } 640 if t.Vault != nil { 641 t.Vault.Canonicalize() 642 } 643 for _, tmpl := range t.Templates { 644 tmpl.Canonicalize() 645 } 646 for _, s := range t.Services { 647 s.Canonicalize(t, tg, job) 648 } 649 for _, a := range t.Affinities { 650 a.Canonicalize() 651 } 652 for _, vm := range t.VolumeMounts { 653 vm.Canonicalize() 654 } 655} 656 657// TaskArtifact is used to download artifacts before running a task. 658type TaskArtifact struct { 659 GetterSource *string `mapstructure:"source"` 660 GetterOptions map[string]string `mapstructure:"options"` 661 GetterMode *string `mapstructure:"mode"` 662 RelativeDest *string `mapstructure:"destination"` 663} 664 665func (a *TaskArtifact) Canonicalize() { 666 if a.GetterMode == nil { 667 a.GetterMode = stringToPtr("any") 668 } 669 if a.GetterSource == nil { 670 // Shouldn't be possible, but we don't want to panic 671 a.GetterSource = stringToPtr("") 672 } 673 if a.RelativeDest == nil { 674 switch *a.GetterMode { 675 case "file": 676 // File mode should default to local/filename 677 dest := *a.GetterSource 678 dest = path.Base(dest) 679 dest = filepath.Join("local", dest) 680 a.RelativeDest = &dest 681 default: 682 // Default to a directory 683 a.RelativeDest = stringToPtr("local/") 684 } 685 } 686} 687 688type Template struct { 689 SourcePath *string `mapstructure:"source"` 690 DestPath *string `mapstructure:"destination"` 691 EmbeddedTmpl *string `mapstructure:"data"` 692 ChangeMode *string `mapstructure:"change_mode"` 693 ChangeSignal *string `mapstructure:"change_signal"` 694 Splay *time.Duration `mapstructure:"splay"` 695 Perms *string `mapstructure:"perms"` 696 LeftDelim *string `mapstructure:"left_delimiter"` 697 RightDelim *string `mapstructure:"right_delimiter"` 698 Envvars *bool `mapstructure:"env"` 699 VaultGrace *time.Duration `mapstructure:"vault_grace"` 700} 701 702func (tmpl *Template) Canonicalize() { 703 if tmpl.SourcePath == nil { 704 tmpl.SourcePath = stringToPtr("") 705 } 706 if tmpl.DestPath == nil { 707 tmpl.DestPath = stringToPtr("") 708 } 709 if tmpl.EmbeddedTmpl == nil { 710 tmpl.EmbeddedTmpl = stringToPtr("") 711 } 712 if tmpl.ChangeMode == nil { 713 tmpl.ChangeMode = stringToPtr("restart") 714 } 715 if tmpl.ChangeSignal == nil { 716 if *tmpl.ChangeMode == "signal" { 717 tmpl.ChangeSignal = stringToPtr("SIGHUP") 718 } else { 719 tmpl.ChangeSignal = stringToPtr("") 720 } 721 } else { 722 sig := *tmpl.ChangeSignal 723 tmpl.ChangeSignal = stringToPtr(strings.ToUpper(sig)) 724 } 725 if tmpl.Splay == nil { 726 tmpl.Splay = timeToPtr(5 * time.Second) 727 } 728 if tmpl.Perms == nil { 729 tmpl.Perms = stringToPtr("0644") 730 } 731 if tmpl.LeftDelim == nil { 732 tmpl.LeftDelim = stringToPtr("{{") 733 } 734 if tmpl.RightDelim == nil { 735 tmpl.RightDelim = stringToPtr("}}") 736 } 737 if tmpl.Envvars == nil { 738 tmpl.Envvars = boolToPtr(false) 739 } 740 if tmpl.VaultGrace == nil { 741 tmpl.VaultGrace = timeToPtr(15 * time.Second) 742 } 743} 744 745type Vault struct { 746 Policies []string 747 Env *bool 748 ChangeMode *string `mapstructure:"change_mode"` 749 ChangeSignal *string `mapstructure:"change_signal"` 750} 751 752func (v *Vault) Canonicalize() { 753 if v.Env == nil { 754 v.Env = boolToPtr(true) 755 } 756 if v.ChangeMode == nil { 757 v.ChangeMode = stringToPtr("restart") 758 } 759 if v.ChangeSignal == nil { 760 v.ChangeSignal = stringToPtr("SIGHUP") 761 } 762} 763 764// NewTask creates and initializes a new Task. 765func NewTask(name, driver string) *Task { 766 return &Task{ 767 Name: name, 768 Driver: driver, 769 } 770} 771 772// Configure is used to configure a single k/v pair on 773// the task. 774func (t *Task) SetConfig(key string, val interface{}) *Task { 775 if t.Config == nil { 776 t.Config = make(map[string]interface{}) 777 } 778 t.Config[key] = val 779 return t 780} 781 782// SetMeta is used to add metadata k/v pairs to the task. 783func (t *Task) SetMeta(key, val string) *Task { 784 if t.Meta == nil { 785 t.Meta = make(map[string]string) 786 } 787 t.Meta[key] = val 788 return t 789} 790 791// Require is used to add resource requirements to a task. 792func (t *Task) Require(r *Resources) *Task { 793 t.Resources = r 794 return t 795} 796 797// Constraint adds a new constraints to a single task. 798func (t *Task) Constrain(c *Constraint) *Task { 799 t.Constraints = append(t.Constraints, c) 800 return t 801} 802 803// AddAffinity adds a new affinity to a single task. 804func (t *Task) AddAffinity(a *Affinity) *Task { 805 t.Affinities = append(t.Affinities, a) 806 return t 807} 808 809// SetLogConfig sets a log config to a task 810func (t *Task) SetLogConfig(l *LogConfig) *Task { 811 t.LogConfig = l 812 return t 813} 814 815// TaskState tracks the current state of a task and events that caused state 816// transitions. 817type TaskState struct { 818 State string 819 Failed bool 820 Restarts uint64 821 LastRestart time.Time 822 StartedAt time.Time 823 FinishedAt time.Time 824 Events []*TaskEvent 825} 826 827const ( 828 TaskSetup = "Task Setup" 829 TaskSetupFailure = "Setup Failure" 830 TaskDriverFailure = "Driver Failure" 831 TaskDriverMessage = "Driver" 832 TaskReceived = "Received" 833 TaskFailedValidation = "Failed Validation" 834 TaskStarted = "Started" 835 TaskTerminated = "Terminated" 836 TaskKilling = "Killing" 837 TaskKilled = "Killed" 838 TaskRestarting = "Restarting" 839 TaskNotRestarting = "Not Restarting" 840 TaskDownloadingArtifacts = "Downloading Artifacts" 841 TaskArtifactDownloadFailed = "Failed Artifact Download" 842 TaskSiblingFailed = "Sibling Task Failed" 843 TaskSignaling = "Signaling" 844 TaskRestartSignal = "Restart Signaled" 845 TaskLeaderDead = "Leader Task Dead" 846 TaskBuildingTaskDir = "Building Task Directory" 847) 848 849// TaskEvent is an event that effects the state of a task and contains meta-data 850// appropriate to the events type. 851type TaskEvent struct { 852 Type string 853 Time int64 854 DisplayMessage string 855 Details map[string]string 856 // DEPRECATION NOTICE: The following fields are all deprecated. see TaskEvent struct in structs.go for details. 857 FailsTask bool 858 RestartReason string 859 SetupError string 860 DriverError string 861 DriverMessage string 862 ExitCode int 863 Signal int 864 Message string 865 KillReason string 866 KillTimeout time.Duration 867 KillError string 868 StartDelay int64 869 DownloadError string 870 ValidationError string 871 DiskLimit int64 872 DiskSize int64 873 FailedSibling string 874 VaultError string 875 TaskSignalReason string 876 TaskSignal string 877 GenericSource string 878} 879