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  }