github.com/taylorchu/nomad@v0.5.3-rc1.0.20170407200202-db11e7dd7b55/api/tasks.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/helper"
     9  )
    10  
    11  // MemoryStats holds memory usage related stats
    12  type MemoryStats struct {
    13  	RSS            uint64
    14  	Cache          uint64
    15  	Swap           uint64
    16  	MaxUsage       uint64
    17  	KernelUsage    uint64
    18  	KernelMaxUsage uint64
    19  	Measured       []string
    20  }
    21  
    22  // CpuStats holds cpu usage related stats
    23  type CpuStats struct {
    24  	SystemMode       float64
    25  	UserMode         float64
    26  	TotalTicks       float64
    27  	ThrottledPeriods uint64
    28  	ThrottledTime    uint64
    29  	Percent          float64
    30  	Measured         []string
    31  }
    32  
    33  // ResourceUsage holds information related to cpu and memory stats
    34  type ResourceUsage struct {
    35  	MemoryStats *MemoryStats
    36  	CpuStats    *CpuStats
    37  }
    38  
    39  // TaskResourceUsage holds aggregated resource usage of all processes in a Task
    40  // and the resource usage of the individual pids
    41  type TaskResourceUsage struct {
    42  	ResourceUsage *ResourceUsage
    43  	Timestamp     int64
    44  	Pids          map[string]*ResourceUsage
    45  }
    46  
    47  // AllocResourceUsage holds the aggregated task resource usage of the
    48  // allocation.
    49  type AllocResourceUsage struct {
    50  	ResourceUsage *ResourceUsage
    51  	Tasks         map[string]*TaskResourceUsage
    52  	Timestamp     int64
    53  }
    54  
    55  // RestartPolicy defines how the Nomad client restarts
    56  // tasks in a taskgroup when they fail
    57  type RestartPolicy struct {
    58  	Interval *time.Duration
    59  	Attempts *int
    60  	Delay    *time.Duration
    61  	Mode     *string
    62  }
    63  
    64  func (r *RestartPolicy) Merge(rp *RestartPolicy) {
    65  	if rp.Interval != nil {
    66  		r.Interval = rp.Interval
    67  	}
    68  	if rp.Attempts != nil {
    69  		r.Attempts = rp.Attempts
    70  	}
    71  	if rp.Delay != nil {
    72  		r.Delay = rp.Delay
    73  	}
    74  	if rp.Mode != nil {
    75  		r.Mode = rp.Mode
    76  	}
    77  }
    78  
    79  // The ServiceCheck data model represents the consul health check that
    80  // Nomad registers for a Task
    81  type ServiceCheck struct {
    82  	Id            string
    83  	Name          string
    84  	Type          string
    85  	Command       string
    86  	Args          []string
    87  	Path          string
    88  	Protocol      string
    89  	PortLabel     string `mapstructure:"port"`
    90  	Interval      time.Duration
    91  	Timeout       time.Duration
    92  	InitialStatus string `mapstructure:"initial_status"`
    93  }
    94  
    95  // The Service model represents a Consul service definition
    96  type Service struct {
    97  	Id        string
    98  	Name      string
    99  	Tags      []string
   100  	PortLabel string `mapstructure:"port"`
   101  	Checks    []ServiceCheck
   102  }
   103  
   104  func (s *Service) Canonicalize(t *Task, tg *TaskGroup, job *Job) {
   105  	if s.Name == "" {
   106  		s.Name = fmt.Sprintf("%s-%s-%s", *job.Name, *tg.Name, t.Name)
   107  	}
   108  }
   109  
   110  // EphemeralDisk is an ephemeral disk object
   111  type EphemeralDisk struct {
   112  	Sticky  *bool
   113  	Migrate *bool
   114  	SizeMB  *int `mapstructure:"size"`
   115  }
   116  
   117  func DefaultEphemeralDisk() *EphemeralDisk {
   118  	return &EphemeralDisk{
   119  		Sticky:  helper.BoolToPtr(false),
   120  		Migrate: helper.BoolToPtr(false),
   121  		SizeMB:  helper.IntToPtr(300),
   122  	}
   123  }
   124  
   125  func (e *EphemeralDisk) Canonicalize() {
   126  	if e.Sticky == nil {
   127  		e.Sticky = helper.BoolToPtr(false)
   128  	}
   129  	if e.Migrate == nil {
   130  		e.Migrate = helper.BoolToPtr(false)
   131  	}
   132  	if e.SizeMB == nil {
   133  		e.SizeMB = helper.IntToPtr(300)
   134  	}
   135  }
   136  
   137  // TaskGroup is the unit of scheduling.
   138  type TaskGroup struct {
   139  	Name          *string
   140  	Count         *int
   141  	Constraints   []*Constraint
   142  	Tasks         []*Task
   143  	RestartPolicy *RestartPolicy
   144  	EphemeralDisk *EphemeralDisk
   145  	Meta          map[string]string
   146  }
   147  
   148  // NewTaskGroup creates a new TaskGroup.
   149  func NewTaskGroup(name string, count int) *TaskGroup {
   150  	return &TaskGroup{
   151  		Name:  helper.StringToPtr(name),
   152  		Count: helper.IntToPtr(count),
   153  	}
   154  }
   155  
   156  func (g *TaskGroup) Canonicalize(job *Job) {
   157  	if g.Name == nil {
   158  		g.Name = helper.StringToPtr("")
   159  	}
   160  	if g.Count == nil {
   161  		g.Count = helper.IntToPtr(1)
   162  	}
   163  	for _, t := range g.Tasks {
   164  		t.Canonicalize(g, job)
   165  	}
   166  	if g.EphemeralDisk == nil {
   167  		g.EphemeralDisk = DefaultEphemeralDisk()
   168  	} else {
   169  		g.EphemeralDisk.Canonicalize()
   170  	}
   171  
   172  	var defaultRestartPolicy *RestartPolicy
   173  	switch *job.Type {
   174  	case "service", "system":
   175  		defaultRestartPolicy = &RestartPolicy{
   176  			Delay:    helper.TimeToPtr(15 * time.Second),
   177  			Attempts: helper.IntToPtr(2),
   178  			Interval: helper.TimeToPtr(1 * time.Minute),
   179  			Mode:     helper.StringToPtr("delay"),
   180  		}
   181  	default:
   182  		defaultRestartPolicy = &RestartPolicy{
   183  			Delay:    helper.TimeToPtr(15 * time.Second),
   184  			Attempts: helper.IntToPtr(15),
   185  			Interval: helper.TimeToPtr(7 * 24 * time.Hour),
   186  			Mode:     helper.StringToPtr("delay"),
   187  		}
   188  	}
   189  
   190  	if g.RestartPolicy != nil {
   191  		defaultRestartPolicy.Merge(g.RestartPolicy)
   192  	}
   193  	g.RestartPolicy = defaultRestartPolicy
   194  }
   195  
   196  // Constrain is used to add a constraint to a task group.
   197  func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
   198  	g.Constraints = append(g.Constraints, c)
   199  	return g
   200  }
   201  
   202  // AddMeta is used to add a meta k/v pair to a task group
   203  func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
   204  	if g.Meta == nil {
   205  		g.Meta = make(map[string]string)
   206  	}
   207  	g.Meta[key] = val
   208  	return g
   209  }
   210  
   211  // AddTask is used to add a new task to a task group.
   212  func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
   213  	g.Tasks = append(g.Tasks, t)
   214  	return g
   215  }
   216  
   217  // RequireDisk adds a ephemeral disk to the task group
   218  func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup {
   219  	g.EphemeralDisk = disk
   220  	return g
   221  }
   222  
   223  // LogConfig provides configuration for log rotation
   224  type LogConfig struct {
   225  	MaxFiles      *int `mapstructure:"max_files"`
   226  	MaxFileSizeMB *int `mapstructure:"max_file_size"`
   227  }
   228  
   229  func DefaultLogConfig() *LogConfig {
   230  	return &LogConfig{
   231  		MaxFiles:      helper.IntToPtr(10),
   232  		MaxFileSizeMB: helper.IntToPtr(10),
   233  	}
   234  }
   235  
   236  func (l *LogConfig) Canonicalize() {
   237  	if l.MaxFiles == nil {
   238  		l.MaxFiles = helper.IntToPtr(10)
   239  	}
   240  	if l.MaxFileSizeMB == nil {
   241  		l.MaxFileSizeMB = helper.IntToPtr(10)
   242  	}
   243  }
   244  
   245  // DispatchPayloadConfig configures how a task gets its input from a job dispatch
   246  type DispatchPayloadConfig struct {
   247  	File string
   248  }
   249  
   250  // Task is a single process in a task group.
   251  type Task struct {
   252  	Name            string
   253  	Driver          string
   254  	User            string
   255  	Config          map[string]interface{}
   256  	Constraints     []*Constraint
   257  	Env             map[string]string
   258  	Services        []*Service
   259  	Resources       *Resources
   260  	Meta            map[string]string
   261  	KillTimeout     *time.Duration `mapstructure:"kill_timeout"`
   262  	LogConfig       *LogConfig     `mapstructure:"logs"`
   263  	Artifacts       []*TaskArtifact
   264  	Vault           *Vault
   265  	Templates       []*Template
   266  	DispatchPayload *DispatchPayloadConfig
   267  	Leader          bool
   268  }
   269  
   270  func (t *Task) Canonicalize(tg *TaskGroup, job *Job) {
   271  	min := MinResources()
   272  	min.Merge(t.Resources)
   273  	min.Canonicalize()
   274  	t.Resources = min
   275  
   276  	if t.KillTimeout == nil {
   277  		t.KillTimeout = helper.TimeToPtr(5 * time.Second)
   278  	}
   279  	if t.LogConfig == nil {
   280  		t.LogConfig = DefaultLogConfig()
   281  	} else {
   282  		t.LogConfig.Canonicalize()
   283  	}
   284  	for _, artifact := range t.Artifacts {
   285  		artifact.Canonicalize()
   286  	}
   287  	if t.Vault != nil {
   288  		t.Vault.Canonicalize()
   289  	}
   290  	for _, tmpl := range t.Templates {
   291  		tmpl.Canonicalize()
   292  	}
   293  	for _, s := range t.Services {
   294  		s.Canonicalize(t, tg, job)
   295  	}
   296  }
   297  
   298  // TaskArtifact is used to download artifacts before running a task.
   299  type TaskArtifact struct {
   300  	GetterSource  *string           `mapstructure:"source"`
   301  	GetterOptions map[string]string `mapstructure:"options"`
   302  	RelativeDest  *string           `mapstructure:"destination"`
   303  }
   304  
   305  func (a *TaskArtifact) Canonicalize() {
   306  	if a.RelativeDest == nil {
   307  		a.RelativeDest = helper.StringToPtr("local/")
   308  	}
   309  }
   310  
   311  type Template struct {
   312  	SourcePath   *string        `mapstructure:"source"`
   313  	DestPath     *string        `mapstructure:"destination"`
   314  	EmbeddedTmpl *string        `mapstructure:"data"`
   315  	ChangeMode   *string        `mapstructure:"change_mode"`
   316  	ChangeSignal *string        `mapstructure:"change_signal"`
   317  	Splay        *time.Duration `mapstructure:"splay"`
   318  	Perms        *string        `mapstructure:"perms"`
   319  	LeftDelim    *string        `mapstructure:"left_delimiter"`
   320  	RightDelim   *string        `mapstructure:"right_delimiter"`
   321  }
   322  
   323  func (tmpl *Template) Canonicalize() {
   324  	if tmpl.SourcePath == nil {
   325  		tmpl.SourcePath = helper.StringToPtr("")
   326  	}
   327  	if tmpl.DestPath == nil {
   328  		tmpl.DestPath = helper.StringToPtr("")
   329  	}
   330  	if tmpl.EmbeddedTmpl == nil {
   331  		tmpl.EmbeddedTmpl = helper.StringToPtr("")
   332  	}
   333  	if tmpl.ChangeMode == nil {
   334  		tmpl.ChangeMode = helper.StringToPtr("restart")
   335  	}
   336  	if tmpl.ChangeSignal == nil {
   337  		if *tmpl.ChangeMode == "signal" {
   338  			tmpl.ChangeSignal = helper.StringToPtr("SIGHUP")
   339  		} else {
   340  			tmpl.ChangeSignal = helper.StringToPtr("")
   341  		}
   342  	} else {
   343  		sig := *tmpl.ChangeSignal
   344  		tmpl.ChangeSignal = helper.StringToPtr(strings.ToUpper(sig))
   345  	}
   346  	if tmpl.Splay == nil {
   347  		tmpl.Splay = helper.TimeToPtr(5 * time.Second)
   348  	}
   349  	if tmpl.Perms == nil {
   350  		tmpl.Perms = helper.StringToPtr("0644")
   351  	}
   352  	if tmpl.LeftDelim == nil {
   353  		tmpl.LeftDelim = helper.StringToPtr("{{")
   354  	}
   355  	if tmpl.RightDelim == nil {
   356  		tmpl.RightDelim = helper.StringToPtr("}}")
   357  	}
   358  }
   359  
   360  type Vault struct {
   361  	Policies     []string
   362  	Env          *bool
   363  	ChangeMode   *string `mapstructure:"change_mode"`
   364  	ChangeSignal *string `mapstructure:"change_signal"`
   365  }
   366  
   367  func (v *Vault) Canonicalize() {
   368  	if v.Env == nil {
   369  		v.Env = helper.BoolToPtr(true)
   370  	}
   371  	if v.ChangeMode == nil {
   372  		v.ChangeMode = helper.StringToPtr("restart")
   373  	}
   374  	if v.ChangeSignal == nil {
   375  		v.ChangeSignal = helper.StringToPtr("SIGHUP")
   376  	}
   377  }
   378  
   379  // NewTask creates and initializes a new Task.
   380  func NewTask(name, driver string) *Task {
   381  	return &Task{
   382  		Name:   name,
   383  		Driver: driver,
   384  	}
   385  }
   386  
   387  // Configure is used to configure a single k/v pair on
   388  // the task.
   389  func (t *Task) SetConfig(key string, val interface{}) *Task {
   390  	if t.Config == nil {
   391  		t.Config = make(map[string]interface{})
   392  	}
   393  	t.Config[key] = val
   394  	return t
   395  }
   396  
   397  // SetMeta is used to add metadata k/v pairs to the task.
   398  func (t *Task) SetMeta(key, val string) *Task {
   399  	if t.Meta == nil {
   400  		t.Meta = make(map[string]string)
   401  	}
   402  	t.Meta[key] = val
   403  	return t
   404  }
   405  
   406  // Require is used to add resource requirements to a task.
   407  func (t *Task) Require(r *Resources) *Task {
   408  	t.Resources = r
   409  	return t
   410  }
   411  
   412  // Constraint adds a new constraints to a single task.
   413  func (t *Task) Constrain(c *Constraint) *Task {
   414  	t.Constraints = append(t.Constraints, c)
   415  	return t
   416  }
   417  
   418  // SetLogConfig sets a log config to a task
   419  func (t *Task) SetLogConfig(l *LogConfig) *Task {
   420  	t.LogConfig = l
   421  	return t
   422  }
   423  
   424  // TaskState tracks the current state of a task and events that caused state
   425  // transitions.
   426  type TaskState struct {
   427  	State      string
   428  	Failed     bool
   429  	StartedAt  time.Time
   430  	FinishedAt time.Time
   431  	Events     []*TaskEvent
   432  }
   433  
   434  const (
   435  	TaskSetup                  = "Task Setup"
   436  	TaskSetupFailure           = "Setup Failure"
   437  	TaskDriverFailure          = "Driver Failure"
   438  	TaskDriverMessage          = "Driver"
   439  	TaskReceived               = "Received"
   440  	TaskFailedValidation       = "Failed Validation"
   441  	TaskStarted                = "Started"
   442  	TaskTerminated             = "Terminated"
   443  	TaskKilling                = "Killing"
   444  	TaskKilled                 = "Killed"
   445  	TaskRestarting             = "Restarting"
   446  	TaskNotRestarting          = "Not Restarting"
   447  	TaskDownloadingArtifacts   = "Downloading Artifacts"
   448  	TaskArtifactDownloadFailed = "Failed Artifact Download"
   449  	TaskSiblingFailed          = "Sibling Task Failed"
   450  	TaskSignaling              = "Signaling"
   451  	TaskRestartSignal          = "Restart Signaled"
   452  	TaskLeaderDead             = "Leader Task Dead"
   453  )
   454  
   455  // TaskEvent is an event that effects the state of a task and contains meta-data
   456  // appropriate to the events type.
   457  type TaskEvent struct {
   458  	Type             string
   459  	Time             int64
   460  	FailsTask        bool
   461  	RestartReason    string
   462  	SetupError       string
   463  	DriverError      string
   464  	DriverMessage    string
   465  	ExitCode         int
   466  	Signal           int
   467  	Message          string
   468  	KillReason       string
   469  	KillTimeout      time.Duration
   470  	KillError        string
   471  	StartDelay       int64
   472  	DownloadError    string
   473  	ValidationError  string
   474  	DiskLimit        int64
   475  	DiskSize         int64
   476  	FailedSibling    string
   477  	VaultError       string
   478  	TaskSignalReason string
   479  	TaskSignal       string
   480  }