github.com/jrxfive/nomad@v0.6.1-0.20170802162750-1fef470e89bf/api/tasks.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  
     7  	"path/filepath"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/hashicorp/nomad/helper"
    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  // The ServiceCheck data model represents the consul health check that
    83  // Nomad registers for a Task
    84  type ServiceCheck struct {
    85  	Id            string
    86  	Name          string
    87  	Type          string
    88  	Command       string
    89  	Args          []string
    90  	Path          string
    91  	Protocol      string
    92  	PortLabel     string `mapstructure:"port"`
    93  	Interval      time.Duration
    94  	Timeout       time.Duration
    95  	InitialStatus string `mapstructure:"initial_status"`
    96  	TLSSkipVerify bool   `mapstructure:"tls_skip_verify"`
    97  }
    98  
    99  // The Service model represents a Consul service definition
   100  type Service struct {
   101  	Id          string
   102  	Name        string
   103  	Tags        []string
   104  	PortLabel   string `mapstructure:"port"`
   105  	AddressMode string `mapstructure:"address_mode"`
   106  	Checks      []ServiceCheck
   107  }
   108  
   109  func (s *Service) Canonicalize(t *Task, tg *TaskGroup, job *Job) {
   110  	if s.Name == "" {
   111  		s.Name = fmt.Sprintf("%s-%s-%s", *job.Name, *tg.Name, t.Name)
   112  	}
   113  
   114  	// Default to AddressModeAuto
   115  	if s.AddressMode == "" {
   116  		s.AddressMode = "auto"
   117  	}
   118  }
   119  
   120  // EphemeralDisk is an ephemeral disk object
   121  type EphemeralDisk struct {
   122  	Sticky  *bool
   123  	Migrate *bool
   124  	SizeMB  *int `mapstructure:"size"`
   125  }
   126  
   127  func DefaultEphemeralDisk() *EphemeralDisk {
   128  	return &EphemeralDisk{
   129  		Sticky:  helper.BoolToPtr(false),
   130  		Migrate: helper.BoolToPtr(false),
   131  		SizeMB:  helper.IntToPtr(300),
   132  	}
   133  }
   134  
   135  func (e *EphemeralDisk) Canonicalize() {
   136  	if e.Sticky == nil {
   137  		e.Sticky = helper.BoolToPtr(false)
   138  	}
   139  	if e.Migrate == nil {
   140  		e.Migrate = helper.BoolToPtr(false)
   141  	}
   142  	if e.SizeMB == nil {
   143  		e.SizeMB = helper.IntToPtr(300)
   144  	}
   145  }
   146  
   147  // TaskGroup is the unit of scheduling.
   148  type TaskGroup struct {
   149  	Name          *string
   150  	Count         *int
   151  	Constraints   []*Constraint
   152  	Tasks         []*Task
   153  	RestartPolicy *RestartPolicy
   154  	EphemeralDisk *EphemeralDisk
   155  	Update        *UpdateStrategy
   156  	Meta          map[string]string
   157  }
   158  
   159  // NewTaskGroup creates a new TaskGroup.
   160  func NewTaskGroup(name string, count int) *TaskGroup {
   161  	return &TaskGroup{
   162  		Name:  helper.StringToPtr(name),
   163  		Count: helper.IntToPtr(count),
   164  	}
   165  }
   166  
   167  func (g *TaskGroup) Canonicalize(job *Job) {
   168  	if g.Name == nil {
   169  		g.Name = helper.StringToPtr("")
   170  	}
   171  	if g.Count == nil {
   172  		g.Count = helper.IntToPtr(1)
   173  	}
   174  	for _, t := range g.Tasks {
   175  		t.Canonicalize(g, job)
   176  	}
   177  	if g.EphemeralDisk == nil {
   178  		g.EphemeralDisk = DefaultEphemeralDisk()
   179  	} else {
   180  		g.EphemeralDisk.Canonicalize()
   181  	}
   182  
   183  	// Merge the update policy from the job
   184  	if ju, tu := job.Update != nil, g.Update != nil; ju && tu {
   185  		// Merge the jobs and task groups definition of the update strategy
   186  		jc := job.Update.Copy()
   187  		jc.Merge(g.Update)
   188  		g.Update = jc
   189  	} else if ju {
   190  		// Inherit the jobs
   191  		jc := job.Update.Copy()
   192  		g.Update = jc
   193  	}
   194  
   195  	if g.Update != nil {
   196  		g.Update.Canonicalize()
   197  	}
   198  
   199  	var defaultRestartPolicy *RestartPolicy
   200  	switch *job.Type {
   201  	case "service", "system":
   202  		defaultRestartPolicy = &RestartPolicy{
   203  			Delay:    helper.TimeToPtr(15 * time.Second),
   204  			Attempts: helper.IntToPtr(2),
   205  			Interval: helper.TimeToPtr(1 * time.Minute),
   206  			Mode:     helper.StringToPtr("delay"),
   207  		}
   208  	default:
   209  		defaultRestartPolicy = &RestartPolicy{
   210  			Delay:    helper.TimeToPtr(15 * time.Second),
   211  			Attempts: helper.IntToPtr(15),
   212  			Interval: helper.TimeToPtr(7 * 24 * time.Hour),
   213  			Mode:     helper.StringToPtr("delay"),
   214  		}
   215  	}
   216  
   217  	if g.RestartPolicy != nil {
   218  		defaultRestartPolicy.Merge(g.RestartPolicy)
   219  	}
   220  	g.RestartPolicy = defaultRestartPolicy
   221  }
   222  
   223  // Constrain is used to add a constraint to a task group.
   224  func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
   225  	g.Constraints = append(g.Constraints, c)
   226  	return g
   227  }
   228  
   229  // AddMeta is used to add a meta k/v pair to a task group
   230  func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
   231  	if g.Meta == nil {
   232  		g.Meta = make(map[string]string)
   233  	}
   234  	g.Meta[key] = val
   235  	return g
   236  }
   237  
   238  // AddTask is used to add a new task to a task group.
   239  func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
   240  	g.Tasks = append(g.Tasks, t)
   241  	return g
   242  }
   243  
   244  // RequireDisk adds a ephemeral disk to the task group
   245  func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup {
   246  	g.EphemeralDisk = disk
   247  	return g
   248  }
   249  
   250  // LogConfig provides configuration for log rotation
   251  type LogConfig struct {
   252  	MaxFiles      *int `mapstructure:"max_files"`
   253  	MaxFileSizeMB *int `mapstructure:"max_file_size"`
   254  }
   255  
   256  func DefaultLogConfig() *LogConfig {
   257  	return &LogConfig{
   258  		MaxFiles:      helper.IntToPtr(10),
   259  		MaxFileSizeMB: helper.IntToPtr(10),
   260  	}
   261  }
   262  
   263  func (l *LogConfig) Canonicalize() {
   264  	if l.MaxFiles == nil {
   265  		l.MaxFiles = helper.IntToPtr(10)
   266  	}
   267  	if l.MaxFileSizeMB == nil {
   268  		l.MaxFileSizeMB = helper.IntToPtr(10)
   269  	}
   270  }
   271  
   272  // DispatchPayloadConfig configures how a task gets its input from a job dispatch
   273  type DispatchPayloadConfig struct {
   274  	File string
   275  }
   276  
   277  // Task is a single process in a task group.
   278  type Task struct {
   279  	Name            string
   280  	Driver          string
   281  	User            string
   282  	Config          map[string]interface{}
   283  	Constraints     []*Constraint
   284  	Env             map[string]string
   285  	Services        []*Service
   286  	Resources       *Resources
   287  	Meta            map[string]string
   288  	KillTimeout     *time.Duration `mapstructure:"kill_timeout"`
   289  	LogConfig       *LogConfig     `mapstructure:"logs"`
   290  	Artifacts       []*TaskArtifact
   291  	Vault           *Vault
   292  	Templates       []*Template
   293  	DispatchPayload *DispatchPayloadConfig
   294  	Leader          bool
   295  }
   296  
   297  func (t *Task) Canonicalize(tg *TaskGroup, job *Job) {
   298  	min := MinResources()
   299  	min.Merge(t.Resources)
   300  	min.Canonicalize()
   301  	t.Resources = min
   302  
   303  	if t.KillTimeout == nil {
   304  		t.KillTimeout = helper.TimeToPtr(5 * time.Second)
   305  	}
   306  	if t.LogConfig == nil {
   307  		t.LogConfig = DefaultLogConfig()
   308  	} else {
   309  		t.LogConfig.Canonicalize()
   310  	}
   311  	for _, artifact := range t.Artifacts {
   312  		artifact.Canonicalize()
   313  	}
   314  	if t.Vault != nil {
   315  		t.Vault.Canonicalize()
   316  	}
   317  	for _, tmpl := range t.Templates {
   318  		tmpl.Canonicalize()
   319  	}
   320  	for _, s := range t.Services {
   321  		s.Canonicalize(t, tg, job)
   322  	}
   323  }
   324  
   325  // TaskArtifact is used to download artifacts before running a task.
   326  type TaskArtifact struct {
   327  	GetterSource  *string           `mapstructure:"source"`
   328  	GetterOptions map[string]string `mapstructure:"options"`
   329  	GetterMode    *string           `mapstructure:"mode"`
   330  	RelativeDest  *string           `mapstructure:"destination"`
   331  }
   332  
   333  func (a *TaskArtifact) Canonicalize() {
   334  	if a.GetterMode == nil {
   335  		a.GetterMode = helper.StringToPtr("any")
   336  	}
   337  	if a.GetterSource == nil {
   338  		// Shouldn't be possible, but we don't want to panic
   339  		a.GetterSource = helper.StringToPtr("")
   340  	}
   341  	if a.RelativeDest == nil {
   342  		switch *a.GetterMode {
   343  		case "file":
   344  			// File mode should default to local/filename
   345  			dest := *a.GetterSource
   346  			dest = path.Base(dest)
   347  			dest = filepath.Join("local", dest)
   348  			a.RelativeDest = &dest
   349  		default:
   350  			// Default to a directory
   351  			a.RelativeDest = helper.StringToPtr("local/")
   352  		}
   353  	}
   354  }
   355  
   356  type Template struct {
   357  	SourcePath   *string        `mapstructure:"source"`
   358  	DestPath     *string        `mapstructure:"destination"`
   359  	EmbeddedTmpl *string        `mapstructure:"data"`
   360  	ChangeMode   *string        `mapstructure:"change_mode"`
   361  	ChangeSignal *string        `mapstructure:"change_signal"`
   362  	Splay        *time.Duration `mapstructure:"splay"`
   363  	Perms        *string        `mapstructure:"perms"`
   364  	LeftDelim    *string        `mapstructure:"left_delimiter"`
   365  	RightDelim   *string        `mapstructure:"right_delimiter"`
   366  	Envvars      *bool          `mapstructure:"env"`
   367  }
   368  
   369  func (tmpl *Template) Canonicalize() {
   370  	if tmpl.SourcePath == nil {
   371  		tmpl.SourcePath = helper.StringToPtr("")
   372  	}
   373  	if tmpl.DestPath == nil {
   374  		tmpl.DestPath = helper.StringToPtr("")
   375  	}
   376  	if tmpl.EmbeddedTmpl == nil {
   377  		tmpl.EmbeddedTmpl = helper.StringToPtr("")
   378  	}
   379  	if tmpl.ChangeMode == nil {
   380  		tmpl.ChangeMode = helper.StringToPtr("restart")
   381  	}
   382  	if tmpl.ChangeSignal == nil {
   383  		if *tmpl.ChangeMode == "signal" {
   384  			tmpl.ChangeSignal = helper.StringToPtr("SIGHUP")
   385  		} else {
   386  			tmpl.ChangeSignal = helper.StringToPtr("")
   387  		}
   388  	} else {
   389  		sig := *tmpl.ChangeSignal
   390  		tmpl.ChangeSignal = helper.StringToPtr(strings.ToUpper(sig))
   391  	}
   392  	if tmpl.Splay == nil {
   393  		tmpl.Splay = helper.TimeToPtr(5 * time.Second)
   394  	}
   395  	if tmpl.Perms == nil {
   396  		tmpl.Perms = helper.StringToPtr("0644")
   397  	}
   398  	if tmpl.LeftDelim == nil {
   399  		tmpl.LeftDelim = helper.StringToPtr("{{")
   400  	}
   401  	if tmpl.RightDelim == nil {
   402  		tmpl.RightDelim = helper.StringToPtr("}}")
   403  	}
   404  	if tmpl.Envvars == nil {
   405  		tmpl.Envvars = helper.BoolToPtr(false)
   406  	}
   407  }
   408  
   409  type Vault struct {
   410  	Policies     []string
   411  	Env          *bool
   412  	ChangeMode   *string `mapstructure:"change_mode"`
   413  	ChangeSignal *string `mapstructure:"change_signal"`
   414  }
   415  
   416  func (v *Vault) Canonicalize() {
   417  	if v.Env == nil {
   418  		v.Env = helper.BoolToPtr(true)
   419  	}
   420  	if v.ChangeMode == nil {
   421  		v.ChangeMode = helper.StringToPtr("restart")
   422  	}
   423  	if v.ChangeSignal == nil {
   424  		v.ChangeSignal = helper.StringToPtr("SIGHUP")
   425  	}
   426  }
   427  
   428  // NewTask creates and initializes a new Task.
   429  func NewTask(name, driver string) *Task {
   430  	return &Task{
   431  		Name:   name,
   432  		Driver: driver,
   433  	}
   434  }
   435  
   436  // Configure is used to configure a single k/v pair on
   437  // the task.
   438  func (t *Task) SetConfig(key string, val interface{}) *Task {
   439  	if t.Config == nil {
   440  		t.Config = make(map[string]interface{})
   441  	}
   442  	t.Config[key] = val
   443  	return t
   444  }
   445  
   446  // SetMeta is used to add metadata k/v pairs to the task.
   447  func (t *Task) SetMeta(key, val string) *Task {
   448  	if t.Meta == nil {
   449  		t.Meta = make(map[string]string)
   450  	}
   451  	t.Meta[key] = val
   452  	return t
   453  }
   454  
   455  // Require is used to add resource requirements to a task.
   456  func (t *Task) Require(r *Resources) *Task {
   457  	t.Resources = r
   458  	return t
   459  }
   460  
   461  // Constraint adds a new constraints to a single task.
   462  func (t *Task) Constrain(c *Constraint) *Task {
   463  	t.Constraints = append(t.Constraints, c)
   464  	return t
   465  }
   466  
   467  // SetLogConfig sets a log config to a task
   468  func (t *Task) SetLogConfig(l *LogConfig) *Task {
   469  	t.LogConfig = l
   470  	return t
   471  }
   472  
   473  // TaskState tracks the current state of a task and events that caused state
   474  // transitions.
   475  type TaskState struct {
   476  	State       string
   477  	Failed      bool
   478  	Restarts    uint64
   479  	LastRestart time.Time
   480  	StartedAt   time.Time
   481  	FinishedAt  time.Time
   482  	Events      []*TaskEvent
   483  }
   484  
   485  const (
   486  	TaskSetup                  = "Task Setup"
   487  	TaskSetupFailure           = "Setup Failure"
   488  	TaskDriverFailure          = "Driver Failure"
   489  	TaskDriverMessage          = "Driver"
   490  	TaskReceived               = "Received"
   491  	TaskFailedValidation       = "Failed Validation"
   492  	TaskStarted                = "Started"
   493  	TaskTerminated             = "Terminated"
   494  	TaskKilling                = "Killing"
   495  	TaskKilled                 = "Killed"
   496  	TaskRestarting             = "Restarting"
   497  	TaskNotRestarting          = "Not Restarting"
   498  	TaskDownloadingArtifacts   = "Downloading Artifacts"
   499  	TaskArtifactDownloadFailed = "Failed Artifact Download"
   500  	TaskSiblingFailed          = "Sibling Task Failed"
   501  	TaskSignaling              = "Signaling"
   502  	TaskRestartSignal          = "Restart Signaled"
   503  	TaskLeaderDead             = "Leader Task Dead"
   504  	TaskBuildingTaskDir        = "Building Task Directory"
   505  )
   506  
   507  // TaskEvent is an event that effects the state of a task and contains meta-data
   508  // appropriate to the events type.
   509  type TaskEvent struct {
   510  	Type             string
   511  	Time             int64
   512  	FailsTask        bool
   513  	RestartReason    string
   514  	SetupError       string
   515  	DriverError      string
   516  	DriverMessage    string
   517  	ExitCode         int
   518  	Signal           int
   519  	Message          string
   520  	KillReason       string
   521  	KillTimeout      time.Duration
   522  	KillError        string
   523  	StartDelay       int64
   524  	DownloadError    string
   525  	ValidationError  string
   526  	DiskLimit        int64
   527  	DiskSize         int64
   528  	FailedSibling    string
   529  	VaultError       string
   530  	TaskSignalReason string
   531  	TaskSignal       string
   532  }