github.com/anuvu/nomad@v0.8.7-atom1/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 func NewDefaultReschedulePolicy(jobType string) *ReschedulePolicy { 152 var dp *ReschedulePolicy 153 switch jobType { 154 case "service": 155 dp = &ReschedulePolicy{ 156 Attempts: helper.IntToPtr(structs.DefaultServiceJobReschedulePolicy.Attempts), 157 Interval: helper.TimeToPtr(structs.DefaultServiceJobReschedulePolicy.Interval), 158 Delay: helper.TimeToPtr(structs.DefaultServiceJobReschedulePolicy.Delay), 159 DelayFunction: helper.StringToPtr(structs.DefaultServiceJobReschedulePolicy.DelayFunction), 160 MaxDelay: helper.TimeToPtr(structs.DefaultServiceJobReschedulePolicy.MaxDelay), 161 Unlimited: helper.BoolToPtr(structs.DefaultServiceJobReschedulePolicy.Unlimited), 162 } 163 case "batch": 164 dp = &ReschedulePolicy{ 165 Attempts: helper.IntToPtr(structs.DefaultBatchJobReschedulePolicy.Attempts), 166 Interval: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Interval), 167 Delay: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.Delay), 168 DelayFunction: helper.StringToPtr(structs.DefaultBatchJobReschedulePolicy.DelayFunction), 169 MaxDelay: helper.TimeToPtr(structs.DefaultBatchJobReschedulePolicy.MaxDelay), 170 Unlimited: helper.BoolToPtr(structs.DefaultBatchJobReschedulePolicy.Unlimited), 171 } 172 173 case "system": 174 dp = &ReschedulePolicy{ 175 Attempts: helper.IntToPtr(0), 176 Interval: helper.TimeToPtr(0), 177 Delay: helper.TimeToPtr(0), 178 DelayFunction: helper.StringToPtr(""), 179 MaxDelay: helper.TimeToPtr(0), 180 Unlimited: helper.BoolToPtr(false), 181 } 182 } 183 return dp 184 } 185 186 func (r *ReschedulePolicy) Copy() *ReschedulePolicy { 187 if r == nil { 188 return nil 189 } 190 nrp := new(ReschedulePolicy) 191 *nrp = *r 192 return nrp 193 } 194 195 func (p *ReschedulePolicy) String() string { 196 if p == nil { 197 return "" 198 } 199 if *p.Unlimited { 200 return fmt.Sprintf("unlimited with %v delay, max_delay = %v", *p.DelayFunction, *p.MaxDelay) 201 } 202 return fmt.Sprintf("%v in %v with %v delay, max_delay = %v", *p.Attempts, *p.Interval, *p.DelayFunction, *p.MaxDelay) 203 } 204 205 // CheckRestart describes if and when a task should be restarted based on 206 // failing health checks. 207 type CheckRestart struct { 208 Limit int `mapstructure:"limit"` 209 Grace *time.Duration `mapstructure:"grace"` 210 IgnoreWarnings bool `mapstructure:"ignore_warnings"` 211 } 212 213 // Canonicalize CheckRestart fields if not nil. 214 func (c *CheckRestart) Canonicalize() { 215 if c == nil { 216 return 217 } 218 219 if c.Grace == nil { 220 c.Grace = helper.TimeToPtr(1 * time.Second) 221 } 222 } 223 224 // Copy returns a copy of CheckRestart or nil if unset. 225 func (c *CheckRestart) Copy() *CheckRestart { 226 if c == nil { 227 return nil 228 } 229 230 nc := new(CheckRestart) 231 nc.Limit = c.Limit 232 if c.Grace != nil { 233 g := *c.Grace 234 nc.Grace = &g 235 } 236 nc.IgnoreWarnings = c.IgnoreWarnings 237 return nc 238 } 239 240 // Merge values from other CheckRestart over default values on this 241 // CheckRestart and return merged copy. 242 func (c *CheckRestart) Merge(o *CheckRestart) *CheckRestart { 243 if c == nil { 244 // Just return other 245 return o 246 } 247 248 nc := c.Copy() 249 250 if o == nil { 251 // Nothing to merge 252 return nc 253 } 254 255 if o.Limit > 0 { 256 nc.Limit = o.Limit 257 } 258 259 if o.Grace != nil { 260 nc.Grace = o.Grace 261 } 262 263 if o.IgnoreWarnings { 264 nc.IgnoreWarnings = o.IgnoreWarnings 265 } 266 267 return nc 268 } 269 270 // The ServiceCheck data model represents the consul health check that 271 // Nomad registers for a Task 272 type ServiceCheck struct { 273 Id string 274 Name string 275 Type string 276 Command string 277 Args []string 278 Path string 279 Protocol string 280 PortLabel string `mapstructure:"port"` 281 AddressMode string `mapstructure:"address_mode"` 282 Interval time.Duration 283 Timeout time.Duration 284 InitialStatus string `mapstructure:"initial_status"` 285 TLSSkipVerify bool `mapstructure:"tls_skip_verify"` 286 Header map[string][]string 287 Method string 288 CheckRestart *CheckRestart `mapstructure:"check_restart"` 289 GRPCService string `mapstructure:"grpc_service"` 290 GRPCUseTLS bool `mapstructure:"grpc_use_tls"` 291 } 292 293 // The Service model represents a Consul service definition 294 type Service struct { 295 Id string 296 Name string 297 Tags []string 298 CanaryTags []string `mapstructure:"canary_tags"` 299 PortLabel string `mapstructure:"port"` 300 AddressMode string `mapstructure:"address_mode"` 301 Checks []ServiceCheck 302 CheckRestart *CheckRestart `mapstructure:"check_restart"` 303 } 304 305 func (s *Service) Canonicalize(t *Task, tg *TaskGroup, job *Job) { 306 if s.Name == "" { 307 s.Name = fmt.Sprintf("%s-%s-%s", *job.Name, *tg.Name, t.Name) 308 } 309 310 // Default to AddressModeAuto 311 if s.AddressMode == "" { 312 s.AddressMode = "auto" 313 } 314 315 // Canonicalize CheckRestart on Checks and merge Service.CheckRestart 316 // into each check. 317 for i, check := range s.Checks { 318 s.Checks[i].CheckRestart = s.CheckRestart.Merge(check.CheckRestart) 319 s.Checks[i].CheckRestart.Canonicalize() 320 } 321 } 322 323 // EphemeralDisk is an ephemeral disk object 324 type EphemeralDisk struct { 325 Sticky *bool 326 Migrate *bool 327 SizeMB *int `mapstructure:"size"` 328 } 329 330 func DefaultEphemeralDisk() *EphemeralDisk { 331 return &EphemeralDisk{ 332 Sticky: helper.BoolToPtr(false), 333 Migrate: helper.BoolToPtr(false), 334 SizeMB: helper.IntToPtr(300), 335 } 336 } 337 338 func (e *EphemeralDisk) Canonicalize() { 339 if e.Sticky == nil { 340 e.Sticky = helper.BoolToPtr(false) 341 } 342 if e.Migrate == nil { 343 e.Migrate = helper.BoolToPtr(false) 344 } 345 if e.SizeMB == nil { 346 e.SizeMB = helper.IntToPtr(300) 347 } 348 } 349 350 // MigrateStrategy describes how allocations for a task group should be 351 // migrated between nodes (eg when draining). 352 type MigrateStrategy struct { 353 MaxParallel *int `mapstructure:"max_parallel"` 354 HealthCheck *string `mapstructure:"health_check"` 355 MinHealthyTime *time.Duration `mapstructure:"min_healthy_time"` 356 HealthyDeadline *time.Duration `mapstructure:"healthy_deadline"` 357 } 358 359 func DefaultMigrateStrategy() *MigrateStrategy { 360 return &MigrateStrategy{ 361 MaxParallel: helper.IntToPtr(1), 362 HealthCheck: helper.StringToPtr("checks"), 363 MinHealthyTime: helper.TimeToPtr(10 * time.Second), 364 HealthyDeadline: helper.TimeToPtr(5 * time.Minute), 365 } 366 } 367 368 func (m *MigrateStrategy) Canonicalize() { 369 if m == nil { 370 return 371 } 372 defaults := DefaultMigrateStrategy() 373 if m.MaxParallel == nil { 374 m.MaxParallel = defaults.MaxParallel 375 } 376 if m.HealthCheck == nil { 377 m.HealthCheck = defaults.HealthCheck 378 } 379 if m.MinHealthyTime == nil { 380 m.MinHealthyTime = defaults.MinHealthyTime 381 } 382 if m.HealthyDeadline == nil { 383 m.HealthyDeadline = defaults.HealthyDeadline 384 } 385 } 386 387 func (m *MigrateStrategy) Merge(o *MigrateStrategy) { 388 if o.MaxParallel != nil { 389 m.MaxParallel = o.MaxParallel 390 } 391 if o.HealthCheck != nil { 392 m.HealthCheck = o.HealthCheck 393 } 394 if o.MinHealthyTime != nil { 395 m.MinHealthyTime = o.MinHealthyTime 396 } 397 if o.HealthyDeadline != nil { 398 m.HealthyDeadline = o.HealthyDeadline 399 } 400 } 401 402 func (m *MigrateStrategy) Copy() *MigrateStrategy { 403 if m == nil { 404 return nil 405 } 406 nm := new(MigrateStrategy) 407 *nm = *m 408 return nm 409 } 410 411 // TaskGroup is the unit of scheduling. 412 type TaskGroup struct { 413 Name *string 414 Count *int 415 Constraints []*Constraint 416 Tasks []*Task 417 RestartPolicy *RestartPolicy 418 ReschedulePolicy *ReschedulePolicy 419 EphemeralDisk *EphemeralDisk 420 Update *UpdateStrategy 421 Migrate *MigrateStrategy 422 Meta map[string]string 423 } 424 425 // NewTaskGroup creates a new TaskGroup. 426 func NewTaskGroup(name string, count int) *TaskGroup { 427 return &TaskGroup{ 428 Name: helper.StringToPtr(name), 429 Count: helper.IntToPtr(count), 430 } 431 } 432 433 func (g *TaskGroup) Canonicalize(job *Job) { 434 if g.Name == nil { 435 g.Name = helper.StringToPtr("") 436 } 437 if g.Count == nil { 438 g.Count = helper.IntToPtr(1) 439 } 440 for _, t := range g.Tasks { 441 t.Canonicalize(g, job) 442 } 443 if g.EphemeralDisk == nil { 444 g.EphemeralDisk = DefaultEphemeralDisk() 445 } else { 446 g.EphemeralDisk.Canonicalize() 447 } 448 449 // Merge the update policy from the job 450 if ju, tu := job.Update != nil, g.Update != nil; ju && tu { 451 // Merge the jobs and task groups definition of the update strategy 452 jc := job.Update.Copy() 453 jc.Merge(g.Update) 454 g.Update = jc 455 } else if ju && !job.Update.Empty() { 456 // Inherit the jobs as long as it is non-empty. 457 jc := job.Update.Copy() 458 g.Update = jc 459 } 460 461 if g.Update != nil { 462 g.Update.Canonicalize() 463 } 464 465 // Merge the reschedule policy from the job 466 if jr, tr := job.Reschedule != nil, g.ReschedulePolicy != nil; jr && tr { 467 jobReschedule := job.Reschedule.Copy() 468 jobReschedule.Merge(g.ReschedulePolicy) 469 g.ReschedulePolicy = jobReschedule 470 } else if jr { 471 jobReschedule := job.Reschedule.Copy() 472 g.ReschedulePolicy = jobReschedule 473 } 474 // Only use default reschedule policy for non system jobs 475 if g.ReschedulePolicy == nil && *job.Type != "system" { 476 g.ReschedulePolicy = NewDefaultReschedulePolicy(*job.Type) 477 } 478 if g.ReschedulePolicy != nil { 479 g.ReschedulePolicy.Canonicalize(*job.Type) 480 } 481 // Merge the migrate strategy from the job 482 if jm, tm := job.Migrate != nil, g.Migrate != nil; jm && tm { 483 jobMigrate := job.Migrate.Copy() 484 jobMigrate.Merge(g.Migrate) 485 g.Migrate = jobMigrate 486 } else if jm { 487 jobMigrate := job.Migrate.Copy() 488 g.Migrate = jobMigrate 489 } 490 491 // Merge with default reschedule policy 492 if *job.Type == "service" { 493 defaultMigrateStrategy := &MigrateStrategy{} 494 defaultMigrateStrategy.Canonicalize() 495 if g.Migrate != nil { 496 defaultMigrateStrategy.Merge(g.Migrate) 497 } 498 g.Migrate = defaultMigrateStrategy 499 } 500 501 var defaultRestartPolicy *RestartPolicy 502 switch *job.Type { 503 case "service", "system": 504 defaultRestartPolicy = &RestartPolicy{ 505 Delay: helper.TimeToPtr(structs.DefaultServiceJobRestartPolicy.Delay), 506 Attempts: helper.IntToPtr(structs.DefaultServiceJobRestartPolicy.Attempts), 507 Interval: helper.TimeToPtr(structs.DefaultServiceJobRestartPolicy.Interval), 508 Mode: helper.StringToPtr(structs.DefaultServiceJobRestartPolicy.Mode), 509 } 510 default: 511 defaultRestartPolicy = &RestartPolicy{ 512 Delay: helper.TimeToPtr(structs.DefaultBatchJobRestartPolicy.Delay), 513 Attempts: helper.IntToPtr(structs.DefaultBatchJobRestartPolicy.Attempts), 514 Interval: helper.TimeToPtr(structs.DefaultBatchJobRestartPolicy.Interval), 515 Mode: helper.StringToPtr(structs.DefaultBatchJobRestartPolicy.Mode), 516 } 517 } 518 519 if g.RestartPolicy != nil { 520 defaultRestartPolicy.Merge(g.RestartPolicy) 521 } 522 g.RestartPolicy = defaultRestartPolicy 523 } 524 525 // Constrain is used to add a constraint to a task group. 526 func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup { 527 g.Constraints = append(g.Constraints, c) 528 return g 529 } 530 531 // AddMeta is used to add a meta k/v pair to a task group 532 func (g *TaskGroup) SetMeta(key, val string) *TaskGroup { 533 if g.Meta == nil { 534 g.Meta = make(map[string]string) 535 } 536 g.Meta[key] = val 537 return g 538 } 539 540 // AddTask is used to add a new task to a task group. 541 func (g *TaskGroup) AddTask(t *Task) *TaskGroup { 542 g.Tasks = append(g.Tasks, t) 543 return g 544 } 545 546 // RequireDisk adds a ephemeral disk to the task group 547 func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup { 548 g.EphemeralDisk = disk 549 return g 550 } 551 552 // LogConfig provides configuration for log rotation 553 type LogConfig struct { 554 MaxFiles *int `mapstructure:"max_files"` 555 MaxFileSizeMB *int `mapstructure:"max_file_size"` 556 } 557 558 func DefaultLogConfig() *LogConfig { 559 return &LogConfig{ 560 MaxFiles: helper.IntToPtr(10), 561 MaxFileSizeMB: helper.IntToPtr(10), 562 } 563 } 564 565 func (l *LogConfig) Canonicalize() { 566 if l.MaxFiles == nil { 567 l.MaxFiles = helper.IntToPtr(10) 568 } 569 if l.MaxFileSizeMB == nil { 570 l.MaxFileSizeMB = helper.IntToPtr(10) 571 } 572 } 573 574 // DispatchPayloadConfig configures how a task gets its input from a job dispatch 575 type DispatchPayloadConfig struct { 576 File string 577 } 578 579 // Task is a single process in a task group. 580 type Task struct { 581 Name string 582 Driver string 583 User string 584 Config map[string]interface{} 585 Constraints []*Constraint 586 Env map[string]string 587 Services []*Service 588 Resources *Resources 589 Meta map[string]string 590 KillTimeout *time.Duration `mapstructure:"kill_timeout"` 591 LogConfig *LogConfig `mapstructure:"logs"` 592 Artifacts []*TaskArtifact 593 Vault *Vault 594 Templates []*Template 595 DispatchPayload *DispatchPayloadConfig 596 Leader bool 597 ShutdownDelay time.Duration `mapstructure:"shutdown_delay"` 598 KillSignal string `mapstructure:"kill_signal"` 599 } 600 601 func (t *Task) Canonicalize(tg *TaskGroup, job *Job) { 602 if t.Resources == nil { 603 t.Resources = &Resources{} 604 } 605 t.Resources.Canonicalize() 606 if t.KillTimeout == nil { 607 t.KillTimeout = helper.TimeToPtr(5 * time.Second) 608 } 609 if t.LogConfig == nil { 610 t.LogConfig = DefaultLogConfig() 611 } else { 612 t.LogConfig.Canonicalize() 613 } 614 for _, artifact := range t.Artifacts { 615 artifact.Canonicalize() 616 } 617 if t.Vault != nil { 618 t.Vault.Canonicalize() 619 } 620 for _, tmpl := range t.Templates { 621 tmpl.Canonicalize() 622 } 623 for _, s := range t.Services { 624 s.Canonicalize(t, tg, job) 625 } 626 } 627 628 // TaskArtifact is used to download artifacts before running a task. 629 type TaskArtifact struct { 630 GetterSource *string `mapstructure:"source"` 631 GetterOptions map[string]string `mapstructure:"options"` 632 GetterMode *string `mapstructure:"mode"` 633 RelativeDest *string `mapstructure:"destination"` 634 } 635 636 func (a *TaskArtifact) Canonicalize() { 637 if a.GetterMode == nil { 638 a.GetterMode = helper.StringToPtr("any") 639 } 640 if a.GetterSource == nil { 641 // Shouldn't be possible, but we don't want to panic 642 a.GetterSource = helper.StringToPtr("") 643 } 644 if a.RelativeDest == nil { 645 switch *a.GetterMode { 646 case "file": 647 // File mode should default to local/filename 648 dest := *a.GetterSource 649 dest = path.Base(dest) 650 dest = filepath.Join("local", dest) 651 a.RelativeDest = &dest 652 default: 653 // Default to a directory 654 a.RelativeDest = helper.StringToPtr("local/") 655 } 656 } 657 } 658 659 type Template struct { 660 SourcePath *string `mapstructure:"source"` 661 DestPath *string `mapstructure:"destination"` 662 EmbeddedTmpl *string `mapstructure:"data"` 663 ChangeMode *string `mapstructure:"change_mode"` 664 ChangeSignal *string `mapstructure:"change_signal"` 665 Splay *time.Duration `mapstructure:"splay"` 666 Perms *string `mapstructure:"perms"` 667 LeftDelim *string `mapstructure:"left_delimiter"` 668 RightDelim *string `mapstructure:"right_delimiter"` 669 Envvars *bool `mapstructure:"env"` 670 VaultGrace *time.Duration `mapstructure:"vault_grace"` 671 } 672 673 func (tmpl *Template) Canonicalize() { 674 if tmpl.SourcePath == nil { 675 tmpl.SourcePath = helper.StringToPtr("") 676 } 677 if tmpl.DestPath == nil { 678 tmpl.DestPath = helper.StringToPtr("") 679 } 680 if tmpl.EmbeddedTmpl == nil { 681 tmpl.EmbeddedTmpl = helper.StringToPtr("") 682 } 683 if tmpl.ChangeMode == nil { 684 tmpl.ChangeMode = helper.StringToPtr("restart") 685 } 686 if tmpl.ChangeSignal == nil { 687 if *tmpl.ChangeMode == "signal" { 688 tmpl.ChangeSignal = helper.StringToPtr("SIGHUP") 689 } else { 690 tmpl.ChangeSignal = helper.StringToPtr("") 691 } 692 } else { 693 sig := *tmpl.ChangeSignal 694 tmpl.ChangeSignal = helper.StringToPtr(strings.ToUpper(sig)) 695 } 696 if tmpl.Splay == nil { 697 tmpl.Splay = helper.TimeToPtr(5 * time.Second) 698 } 699 if tmpl.Perms == nil { 700 tmpl.Perms = helper.StringToPtr("0644") 701 } 702 if tmpl.LeftDelim == nil { 703 tmpl.LeftDelim = helper.StringToPtr("{{") 704 } 705 if tmpl.RightDelim == nil { 706 tmpl.RightDelim = helper.StringToPtr("}}") 707 } 708 if tmpl.Envvars == nil { 709 tmpl.Envvars = helper.BoolToPtr(false) 710 } 711 if tmpl.VaultGrace == nil { 712 tmpl.VaultGrace = helper.TimeToPtr(15 * time.Second) 713 } 714 } 715 716 type Vault struct { 717 Policies []string 718 Env *bool 719 ChangeMode *string `mapstructure:"change_mode"` 720 ChangeSignal *string `mapstructure:"change_signal"` 721 } 722 723 func (v *Vault) Canonicalize() { 724 if v.Env == nil { 725 v.Env = helper.BoolToPtr(true) 726 } 727 if v.ChangeMode == nil { 728 v.ChangeMode = helper.StringToPtr("restart") 729 } 730 if v.ChangeSignal == nil { 731 v.ChangeSignal = helper.StringToPtr("SIGHUP") 732 } 733 } 734 735 // NewTask creates and initializes a new Task. 736 func NewTask(name, driver string) *Task { 737 return &Task{ 738 Name: name, 739 Driver: driver, 740 } 741 } 742 743 // Configure is used to configure a single k/v pair on 744 // the task. 745 func (t *Task) SetConfig(key string, val interface{}) *Task { 746 if t.Config == nil { 747 t.Config = make(map[string]interface{}) 748 } 749 t.Config[key] = val 750 return t 751 } 752 753 // SetMeta is used to add metadata k/v pairs to the task. 754 func (t *Task) SetMeta(key, val string) *Task { 755 if t.Meta == nil { 756 t.Meta = make(map[string]string) 757 } 758 t.Meta[key] = val 759 return t 760 } 761 762 // Require is used to add resource requirements to a task. 763 func (t *Task) Require(r *Resources) *Task { 764 t.Resources = r 765 return t 766 } 767 768 // Constraint adds a new constraints to a single task. 769 func (t *Task) Constrain(c *Constraint) *Task { 770 t.Constraints = append(t.Constraints, c) 771 return t 772 } 773 774 // SetLogConfig sets a log config to a task 775 func (t *Task) SetLogConfig(l *LogConfig) *Task { 776 t.LogConfig = l 777 return t 778 } 779 780 // TaskState tracks the current state of a task and events that caused state 781 // transitions. 782 type TaskState struct { 783 State string 784 Failed bool 785 Restarts uint64 786 LastRestart time.Time 787 StartedAt time.Time 788 FinishedAt time.Time 789 Events []*TaskEvent 790 } 791 792 const ( 793 TaskSetup = "Task Setup" 794 TaskSetupFailure = "Setup Failure" 795 TaskDriverFailure = "Driver Failure" 796 TaskDriverMessage = "Driver" 797 TaskReceived = "Received" 798 TaskFailedValidation = "Failed Validation" 799 TaskStarted = "Started" 800 TaskTerminated = "Terminated" 801 TaskKilling = "Killing" 802 TaskKilled = "Killed" 803 TaskRestarting = "Restarting" 804 TaskNotRestarting = "Not Restarting" 805 TaskDownloadingArtifacts = "Downloading Artifacts" 806 TaskArtifactDownloadFailed = "Failed Artifact Download" 807 TaskSiblingFailed = "Sibling Task Failed" 808 TaskSignaling = "Signaling" 809 TaskRestartSignal = "Restart Signaled" 810 TaskLeaderDead = "Leader Task Dead" 811 TaskBuildingTaskDir = "Building Task Directory" 812 ) 813 814 // TaskEvent is an event that effects the state of a task and contains meta-data 815 // appropriate to the events type. 816 type TaskEvent struct { 817 Type string 818 Time int64 819 DisplayMessage string 820 Details map[string]string 821 // DEPRECATION NOTICE: The following fields are all deprecated. see TaskEvent struct in structs.go for details. 822 FailsTask bool 823 RestartReason string 824 SetupError string 825 DriverError string 826 DriverMessage string 827 ExitCode int 828 Signal int 829 Message string 830 KillReason string 831 KillTimeout time.Duration 832 KillError string 833 StartDelay int64 834 DownloadError string 835 ValidationError string 836 DiskLimit int64 837 DiskSize int64 838 FailedSibling string 839 VaultError string 840 TaskSignalReason string 841 TaskSignal string 842 GenericSource string 843 }