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