open-nomad/api/tasks.go

533 lines
13 KiB
Go
Raw Normal View History

2015-09-09 20:02:39 +00:00
package api
import (
"fmt"
"path"
"path/filepath"
2017-02-13 23:18:17 +00:00
"strings"
"time"
2017-02-06 19:48:28 +00:00
"github.com/hashicorp/nomad/helper"
)
2016-05-27 22:24:22 +00:00
// MemoryStats holds memory usage related stats
2016-04-29 20:03:02 +00:00
type MemoryStats struct {
RSS uint64
Cache uint64
Swap uint64
MaxUsage uint64
KernelUsage uint64
KernelMaxUsage uint64
2016-06-10 02:45:41 +00:00
Measured []string
2016-04-29 20:03:02 +00:00
}
2016-05-27 22:24:22 +00:00
// CpuStats holds cpu usage related stats
2016-05-21 07:49:17 +00:00
type CpuStats struct {
2016-05-19 21:06:19 +00:00
SystemMode float64
UserMode float64
TotalTicks float64
2016-04-29 20:03:02 +00:00
ThrottledPeriods uint64
ThrottledTime uint64
2016-05-19 21:06:19 +00:00
Percent float64
2016-06-10 02:45:41 +00:00
Measured []string
2016-04-29 20:03:02 +00:00
}
2016-05-27 22:24:22 +00:00
// ResourceUsage holds information related to cpu and memory stats
type ResourceUsage struct {
2016-04-29 20:03:02 +00:00
MemoryStats *MemoryStats
2016-05-21 07:49:17 +00:00
CpuStats *CpuStats
}
2016-05-27 22:24:22 +00:00
// TaskResourceUsage holds aggregated resource usage of all processes in a Task
// and the resource usage of the individual pids
type TaskResourceUsage struct {
ResourceUsage *ResourceUsage
2016-05-27 22:24:22 +00:00
Timestamp int64
Pids map[string]*ResourceUsage
2016-04-29 20:03:02 +00:00
}
// AllocResourceUsage holds the aggregated task resource usage of the
// allocation.
type AllocResourceUsage struct {
ResourceUsage *ResourceUsage
Tasks map[string]*TaskResourceUsage
Timestamp int64
}
// RestartPolicy defines how the Nomad client restarts
// tasks in a taskgroup when they fail
type RestartPolicy struct {
2017-02-13 23:18:17 +00:00
Interval *time.Duration
Attempts *int
Delay *time.Duration
Mode *string
}
func (r *RestartPolicy) Merge(rp *RestartPolicy) {
if rp.Interval != nil {
r.Interval = rp.Interval
}
if rp.Attempts != nil {
r.Attempts = rp.Attempts
}
if rp.Delay != nil {
r.Delay = rp.Delay
}
if rp.Mode != nil {
r.Mode = rp.Mode
}
2015-10-31 04:28:56 +00:00
}
// The ServiceCheck data model represents the consul health check that
// Nomad registers for a Task
type ServiceCheck struct {
2016-08-23 20:49:37 +00:00
Id string
Name string
Type string
Command string
Args []string
Path string
Protocol string
2016-08-23 20:49:37 +00:00
PortLabel string `mapstructure:"port"`
Interval time.Duration
Timeout time.Duration
InitialStatus string `mapstructure:"initial_status"`
TLSSkipVerify bool `mapstructure:"tls_skip_verify"`
}
2016-05-15 16:41:34 +00:00
// The Service model represents a Consul service definition
type Service struct {
Id string
Name string
Tags []string
PortLabel string `mapstructure:"port"`
AddressMode string `mapstructure:"address_mode"`
Checks []ServiceCheck
}
func (s *Service) Canonicalize(t *Task, tg *TaskGroup, job *Job) {
if s.Name == "" {
s.Name = fmt.Sprintf("%s-%s-%s", *job.Name, *tg.Name, t.Name)
}
// Default to AddressModeAuto
if s.AddressMode == "" {
s.AddressMode = "auto"
}
}
// EphemeralDisk is an ephemeral disk object
type EphemeralDisk struct {
2017-02-06 19:48:28 +00:00
Sticky *bool
Migrate *bool
SizeMB *int `mapstructure:"size"`
}
func DefaultEphemeralDisk() *EphemeralDisk {
return &EphemeralDisk{
Sticky: helper.BoolToPtr(false),
Migrate: helper.BoolToPtr(false),
SizeMB: helper.IntToPtr(300),
}
}
func (e *EphemeralDisk) Canonicalize() {
if e.Sticky == nil {
e.Sticky = helper.BoolToPtr(false)
}
if e.Migrate == nil {
e.Migrate = helper.BoolToPtr(false)
}
if e.SizeMB == nil {
e.SizeMB = helper.IntToPtr(300)
}
}
2015-09-09 20:02:39 +00:00
// TaskGroup is the unit of scheduling.
type TaskGroup struct {
2017-02-06 19:48:28 +00:00
Name *string
Count *int
Constraints []*Constraint
Tasks []*Task
RestartPolicy *RestartPolicy
EphemeralDisk *EphemeralDisk
Update *UpdateStrategy
Meta map[string]string
2015-09-09 20:02:39 +00:00
}
// NewTaskGroup creates a new TaskGroup.
2015-09-10 00:59:18 +00:00
func NewTaskGroup(name string, count int) *TaskGroup {
2015-09-09 20:02:39 +00:00
return &TaskGroup{
2017-02-06 19:48:28 +00:00
Name: helper.StringToPtr(name),
Count: helper.IntToPtr(count),
}
}
func (g *TaskGroup) Canonicalize(job *Job) {
2017-02-06 19:48:28 +00:00
if g.Name == nil {
g.Name = helper.StringToPtr("")
}
if g.Count == nil {
g.Count = helper.IntToPtr(1)
}
for _, t := range g.Tasks {
t.Canonicalize(g, job)
2017-02-06 19:48:28 +00:00
}
if g.EphemeralDisk == nil {
g.EphemeralDisk = DefaultEphemeralDisk()
} else {
g.EphemeralDisk.Canonicalize()
}
2017-02-13 23:18:17 +00:00
// Merge the update policy from the job
if ju, tu := job.Update != nil, g.Update != nil; ju && tu {
// Merge the jobs and task groups definition of the update strategy
jc := job.Update.Copy()
jc.Merge(g.Update)
g.Update = jc
} else if ju {
// Inherit the jobs
jc := job.Update.Copy()
g.Update = jc
}
if g.Update != nil {
g.Update.Canonicalize()
}
2017-02-13 23:18:17 +00:00
var defaultRestartPolicy *RestartPolicy
switch *job.Type {
2017-02-13 23:18:17 +00:00
case "service", "system":
defaultRestartPolicy = &RestartPolicy{
Delay: helper.TimeToPtr(15 * time.Second),
Attempts: helper.IntToPtr(2),
Interval: helper.TimeToPtr(1 * time.Minute),
Mode: helper.StringToPtr("delay"),
2017-02-06 19:48:28 +00:00
}
2017-02-13 23:18:17 +00:00
default:
defaultRestartPolicy = &RestartPolicy{
Delay: helper.TimeToPtr(15 * time.Second),
Attempts: helper.IntToPtr(15),
Interval: helper.TimeToPtr(7 * 24 * time.Hour),
Mode: helper.StringToPtr("delay"),
}
}
if g.RestartPolicy != nil {
defaultRestartPolicy.Merge(g.RestartPolicy)
2015-09-09 20:02:39 +00:00
}
2017-02-13 23:18:17 +00:00
g.RestartPolicy = defaultRestartPolicy
2015-09-09 20:02:39 +00:00
}
// Constrain is used to add a constraint to a task group.
func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
g.Constraints = append(g.Constraints, c)
return g
}
// AddMeta is used to add a meta k/v pair to a task group
func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
if g.Meta == nil {
g.Meta = make(map[string]string)
}
g.Meta[key] = val
return g
}
// AddTask is used to add a new task to a task group.
func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
g.Tasks = append(g.Tasks, t)
return g
}
// RequireDisk adds a ephemeral disk to the task group
func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup {
g.EphemeralDisk = disk
2016-08-26 03:10:25 +00:00
return g
}
// LogConfig provides configuration for log rotation
type LogConfig struct {
MaxFiles *int `mapstructure:"max_files"`
MaxFileSizeMB *int `mapstructure:"max_file_size"`
2017-02-06 19:48:28 +00:00
}
func DefaultLogConfig() *LogConfig {
return &LogConfig{
MaxFiles: helper.IntToPtr(10),
MaxFileSizeMB: helper.IntToPtr(10),
}
}
func (l *LogConfig) Canonicalize() {
if l.MaxFiles == nil {
l.MaxFiles = helper.IntToPtr(10)
}
if l.MaxFileSizeMB == nil {
l.MaxFileSizeMB = helper.IntToPtr(10)
}
}
// DispatchPayloadConfig configures how a task gets its input from a job dispatch
type DispatchPayloadConfig struct {
2016-12-14 20:50:08 +00:00
File string
2016-11-23 22:56:50 +00:00
}
2015-09-09 20:02:39 +00:00
// Task is a single process in a task group.
type Task struct {
Name string
Driver string
User string
Config map[string]interface{}
Constraints []*Constraint
Env map[string]string
2017-03-01 23:30:01 +00:00
Services []*Service
Resources *Resources
Meta map[string]string
KillTimeout *time.Duration `mapstructure:"kill_timeout"`
LogConfig *LogConfig `mapstructure:"logs"`
Artifacts []*TaskArtifact
Vault *Vault
Templates []*Template
DispatchPayload *DispatchPayloadConfig
2017-02-21 00:36:41 +00:00
Leader bool
}
func (t *Task) Canonicalize(tg *TaskGroup, job *Job) {
min := MinResources()
min.Merge(t.Resources)
min.Canonicalize()
t.Resources = min
if t.KillTimeout == nil {
t.KillTimeout = helper.TimeToPtr(5 * time.Second)
}
2017-02-06 19:48:28 +00:00
if t.LogConfig == nil {
t.LogConfig = DefaultLogConfig()
} else {
t.LogConfig.Canonicalize()
}
for _, artifact := range t.Artifacts {
artifact.Canonicalize()
}
if t.Vault != nil {
t.Vault.Canonicalize()
}
2017-02-06 19:48:28 +00:00
for _, tmpl := range t.Templates {
tmpl.Canonicalize()
}
2017-03-01 23:30:01 +00:00
for _, s := range t.Services {
s.Canonicalize(t, tg, job)
}
2017-02-06 19:48:28 +00:00
}
2016-03-16 03:21:52 +00:00
// TaskArtifact is used to download artifacts before running a task.
type TaskArtifact struct {
GetterSource *string `mapstructure:"source"`
GetterOptions map[string]string `mapstructure:"options"`
GetterMode *string `mapstructure:"mode"`
RelativeDest *string `mapstructure:"destination"`
2017-02-06 19:48:28 +00:00
}
func (a *TaskArtifact) Canonicalize() {
if a.GetterMode == nil {
a.GetterMode = helper.StringToPtr("any")
}
if a.GetterSource == nil {
// Shouldn't be possible, but we don't want to panic
a.GetterSource = helper.StringToPtr("")
}
2017-02-06 19:48:28 +00:00
if a.RelativeDest == nil {
switch *a.GetterMode {
case "file":
// File mode should default to local/filename
dest := *a.GetterSource
dest = path.Base(dest)
dest = filepath.Join("local", dest)
a.RelativeDest = &dest
default:
// Default to a directory
a.RelativeDest = helper.StringToPtr("local/")
}
2017-02-06 19:48:28 +00:00
}
2015-09-09 20:02:39 +00:00
}
2016-09-23 22:39:52 +00:00
type Template struct {
SourcePath *string `mapstructure:"source"`
DestPath *string `mapstructure:"destination"`
EmbeddedTmpl *string `mapstructure:"data"`
ChangeMode *string `mapstructure:"change_mode"`
ChangeSignal *string `mapstructure:"change_signal"`
Splay *time.Duration `mapstructure:"splay"`
Perms *string `mapstructure:"perms"`
LeftDelim *string `mapstructure:"left_delimiter"`
RightDelim *string `mapstructure:"right_delimiter"`
Envvars *bool `mapstructure:"env"`
2017-02-06 19:48:28 +00:00
}
func (tmpl *Template) Canonicalize() {
if tmpl.SourcePath == nil {
tmpl.SourcePath = helper.StringToPtr("")
2017-02-06 19:48:28 +00:00
}
if tmpl.DestPath == nil {
tmpl.DestPath = helper.StringToPtr("")
2017-02-06 19:48:28 +00:00
}
if tmpl.EmbeddedTmpl == nil {
tmpl.EmbeddedTmpl = helper.StringToPtr("")
}
if tmpl.ChangeMode == nil {
tmpl.ChangeMode = helper.StringToPtr("restart")
2017-02-06 19:48:28 +00:00
}
if tmpl.ChangeSignal == nil {
if *tmpl.ChangeMode == "signal" {
tmpl.ChangeSignal = helper.StringToPtr("SIGHUP")
} else {
tmpl.ChangeSignal = helper.StringToPtr("")
}
} else {
2017-02-13 23:18:17 +00:00
sig := *tmpl.ChangeSignal
tmpl.ChangeSignal = helper.StringToPtr(strings.ToUpper(sig))
}
if tmpl.Splay == nil {
tmpl.Splay = helper.TimeToPtr(5 * time.Second)
}
if tmpl.Perms == nil {
tmpl.Perms = helper.StringToPtr("0644")
}
2017-02-21 00:43:28 +00:00
if tmpl.LeftDelim == nil {
tmpl.LeftDelim = helper.StringToPtr("{{")
}
if tmpl.RightDelim == nil {
tmpl.RightDelim = helper.StringToPtr("}}")
}
if tmpl.Envvars == nil {
tmpl.Envvars = helper.BoolToPtr(false)
}
2016-09-23 22:39:52 +00:00
}
2016-08-17 04:32:25 +00:00
type Vault struct {
Policies []string
2017-02-06 19:48:28 +00:00
Env *bool
ChangeMode *string `mapstructure:"change_mode"`
ChangeSignal *string `mapstructure:"change_signal"`
2017-02-06 19:48:28 +00:00
}
func (v *Vault) Canonicalize() {
if v.Env == nil {
v.Env = helper.BoolToPtr(true)
}
if v.ChangeMode == nil {
v.ChangeMode = helper.StringToPtr("restart")
}
if v.ChangeSignal == nil {
2017-02-13 23:18:17 +00:00
v.ChangeSignal = helper.StringToPtr("SIGHUP")
2017-02-06 19:48:28 +00:00
}
2016-08-17 04:32:25 +00:00
}
2015-09-09 20:02:39 +00:00
// NewTask creates and initializes a new Task.
func NewTask(name, driver string) *Task {
return &Task{
Name: name,
Driver: driver,
}
}
// Configure is used to configure a single k/v pair on
// the task.
2016-08-22 16:35:25 +00:00
func (t *Task) SetConfig(key string, val interface{}) *Task {
2015-09-09 20:02:39 +00:00
if t.Config == nil {
2015-11-14 04:51:30 +00:00
t.Config = make(map[string]interface{})
2015-09-09 20:02:39 +00:00
}
t.Config[key] = val
return t
}
// SetMeta is used to add metadata k/v pairs to the task.
func (t *Task) SetMeta(key, val string) *Task {
if t.Meta == nil {
t.Meta = make(map[string]string)
}
t.Meta[key] = val
return t
}
// Require is used to add resource requirements to a task.
func (t *Task) Require(r *Resources) *Task {
t.Resources = r
return t
}
2015-09-10 00:29:43 +00:00
// Constraint adds a new constraints to a single task.
func (t *Task) Constrain(c *Constraint) *Task {
t.Constraints = append(t.Constraints, c)
return t
}
2015-11-12 23:28:22 +00:00
2016-02-10 21:36:47 +00:00
// SetLogConfig sets a log config to a task
func (t *Task) SetLogConfig(l *LogConfig) *Task {
t.LogConfig = l
return t
}
2015-11-12 23:28:22 +00:00
// TaskState tracks the current state of a task and events that caused state
2016-05-15 16:41:34 +00:00
// transitions.
2015-11-12 23:28:22 +00:00
type TaskState struct {
State string
Failed bool
Restarts uint64
LastRestart time.Time
StartedAt time.Time
FinishedAt time.Time
Events []*TaskEvent
2015-11-12 23:28:22 +00:00
}
const (
2017-02-10 01:40:13 +00:00
TaskSetup = "Task Setup"
2016-10-10 21:49:37 +00:00
TaskSetupFailure = "Setup Failure"
TaskDriverFailure = "Driver Failure"
TaskDriverMessage = "Driver"
TaskReceived = "Received"
TaskFailedValidation = "Failed Validation"
TaskStarted = "Started"
TaskTerminated = "Terminated"
TaskKilling = "Killing"
TaskKilled = "Killed"
TaskRestarting = "Restarting"
TaskNotRestarting = "Not Restarting"
TaskDownloadingArtifacts = "Downloading Artifacts"
TaskArtifactDownloadFailed = "Failed Artifact Download"
2017-02-11 01:55:19 +00:00
TaskSiblingFailed = "Sibling Task Failed"
2016-10-05 20:41:29 +00:00
TaskSignaling = "Signaling"
2016-10-05 22:11:09 +00:00
TaskRestartSignal = "Restart Signaled"
2017-02-11 01:55:19 +00:00
TaskLeaderDead = "Leader Task Dead"
2017-07-07 06:04:42 +00:00
TaskBuildingTaskDir = "Building Task Directory"
2015-11-12 23:28:22 +00:00
)
// TaskEvent is an event that effects the state of a task and contains meta-data
// appropriate to the events type.
type TaskEvent struct {
Type string
Time int64
FailsTask bool
RestartReason string
SetupError string
DriverError string
DriverMessage string
ExitCode int
Signal int
Message string
KillReason string
KillTimeout time.Duration
KillError string
StartDelay int64
DownloadError string
ValidationError string
DiskLimit int64
DiskSize int64
FailedSibling string
VaultError string
TaskSignalReason string
TaskSignal string
2015-11-12 23:28:22 +00:00
}