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 }