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 }