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