1package api
2
3import (
4	"fmt"
5	"path"
6	"path/filepath"
7	"strings"
8	"time"
9)
10
11const (
12	// RestartPolicyModeDelay causes an artificial delay till the next interval is
13	// reached when the specified attempts have been reached in the interval.
14	RestartPolicyModeDelay = "delay"
15
16	// RestartPolicyModeFail causes a job to fail if the specified number of
17	// attempts are reached within an interval.
18	RestartPolicyModeFail = "fail"
19)
20
21// MemoryStats holds memory usage related stats
22type MemoryStats struct {
23	RSS            uint64
24	Cache          uint64
25	Swap           uint64
26	Usage          uint64
27	MaxUsage       uint64
28	KernelUsage    uint64
29	KernelMaxUsage uint64
30	Measured       []string
31}
32
33// CpuStats holds cpu usage related stats
34type CpuStats struct {
35	SystemMode       float64
36	UserMode         float64
37	TotalTicks       float64
38	ThrottledPeriods uint64
39	ThrottledTime    uint64
40	Percent          float64
41	Measured         []string
42}
43
44// ResourceUsage holds information related to cpu and memory stats
45type ResourceUsage struct {
46	MemoryStats *MemoryStats
47	CpuStats    *CpuStats
48	DeviceStats []*DeviceGroupStats
49}
50
51// TaskResourceUsage holds aggregated resource usage of all processes in a Task
52// and the resource usage of the individual pids
53type TaskResourceUsage struct {
54	ResourceUsage *ResourceUsage
55	Timestamp     int64
56	Pids          map[string]*ResourceUsage
57}
58
59// AllocResourceUsage holds the aggregated task resource usage of the
60// allocation.
61type AllocResourceUsage struct {
62	ResourceUsage *ResourceUsage
63	Tasks         map[string]*TaskResourceUsage
64	Timestamp     int64
65}
66
67// RestartPolicy defines how the Nomad client restarts
68// tasks in a taskgroup when they fail
69type RestartPolicy struct {
70	Interval *time.Duration
71	Attempts *int
72	Delay    *time.Duration
73	Mode     *string
74}
75
76func (r *RestartPolicy) Merge(rp *RestartPolicy) {
77	if rp.Interval != nil {
78		r.Interval = rp.Interval
79	}
80	if rp.Attempts != nil {
81		r.Attempts = rp.Attempts
82	}
83	if rp.Delay != nil {
84		r.Delay = rp.Delay
85	}
86	if rp.Mode != nil {
87		r.Mode = rp.Mode
88	}
89}
90
91// Reschedule configures how Tasks are rescheduled  when they crash or fail.
92type ReschedulePolicy struct {
93	// Attempts limits the number of rescheduling attempts that can occur in an interval.
94	Attempts *int `mapstructure:"attempts"`
95
96	// Interval is a duration in which we can limit the number of reschedule attempts.
97	Interval *time.Duration `mapstructure:"interval"`
98
99	// Delay is a minimum duration to wait between reschedule attempts.
100	// The delay function determines how much subsequent reschedule attempts are delayed by.
101	Delay *time.Duration `mapstructure:"delay"`
102
103	// DelayFunction determines how the delay progressively changes on subsequent reschedule
104	// attempts. Valid values are "exponential", "constant", and "fibonacci".
105	DelayFunction *string `mapstructure:"delay_function"`
106
107	// MaxDelay is an upper bound on the delay.
108	MaxDelay *time.Duration `mapstructure:"max_delay"`
109
110	// Unlimited allows rescheduling attempts until they succeed
111	Unlimited *bool `mapstructure:"unlimited"`
112}
113
114func (r *ReschedulePolicy) Merge(rp *ReschedulePolicy) {
115	if rp == nil {
116		return
117	}
118	if rp.Interval != nil {
119		r.Interval = rp.Interval
120	}
121	if rp.Attempts != nil {
122		r.Attempts = rp.Attempts
123	}
124	if rp.Delay != nil {
125		r.Delay = rp.Delay
126	}
127	if rp.DelayFunction != nil {
128		r.DelayFunction = rp.DelayFunction
129	}
130	if rp.MaxDelay != nil {
131		r.MaxDelay = rp.MaxDelay
132	}
133	if rp.Unlimited != nil {
134		r.Unlimited = rp.Unlimited
135	}
136}
137
138func (r *ReschedulePolicy) Canonicalize(jobType string) {
139	dp := NewDefaultReschedulePolicy(jobType)
140	if r.Interval == nil {
141		r.Interval = dp.Interval
142	}
143	if r.Attempts == nil {
144		r.Attempts = dp.Attempts
145	}
146	if r.Delay == nil {
147		r.Delay = dp.Delay
148	}
149	if r.DelayFunction == nil {
150		r.DelayFunction = dp.DelayFunction
151	}
152	if r.MaxDelay == nil {
153		r.MaxDelay = dp.MaxDelay
154	}
155	if r.Unlimited == nil {
156		r.Unlimited = dp.Unlimited
157	}
158}
159
160// Affinity is used to serialize task group affinities
161type Affinity struct {
162	LTarget string // Left-hand target
163	RTarget string // Right-hand target
164	Operand string // Constraint operand (<=, <, =, !=, >, >=), set_contains_all, set_contains_any
165	Weight  *int8  // Weight applied to nodes that match the affinity. Can be negative
166}
167
168func NewAffinity(LTarget string, Operand string, RTarget string, Weight int8) *Affinity {
169	return &Affinity{
170		LTarget: LTarget,
171		RTarget: RTarget,
172		Operand: Operand,
173		Weight:  int8ToPtr(Weight),
174	}
175}
176
177func (a *Affinity) Canonicalize() {
178	if a.Weight == nil {
179		a.Weight = int8ToPtr(50)
180	}
181}
182
183func NewDefaultReschedulePolicy(jobType string) *ReschedulePolicy {
184	var dp *ReschedulePolicy
185	switch jobType {
186	case "service":
187		// This needs to be in sync with DefaultServiceJobReschedulePolicy
188		// in nomad/structs/structs.go
189		dp = &ReschedulePolicy{
190			Delay:         timeToPtr(30 * time.Second),
191			DelayFunction: stringToPtr("exponential"),
192			MaxDelay:      timeToPtr(1 * time.Hour),
193			Unlimited:     boolToPtr(true),
194
195			Attempts: intToPtr(0),
196			Interval: timeToPtr(0),
197		}
198	case "batch":
199		// This needs to be in sync with DefaultBatchJobReschedulePolicy
200		// in nomad/structs/structs.go
201		dp = &ReschedulePolicy{
202			Attempts:      intToPtr(1),
203			Interval:      timeToPtr(24 * time.Hour),
204			Delay:         timeToPtr(5 * time.Second),
205			DelayFunction: stringToPtr("constant"),
206
207			MaxDelay:  timeToPtr(0),
208			Unlimited: boolToPtr(false),
209		}
210
211	case "system":
212		dp = &ReschedulePolicy{
213			Attempts:      intToPtr(0),
214			Interval:      timeToPtr(0),
215			Delay:         timeToPtr(0),
216			DelayFunction: stringToPtr(""),
217			MaxDelay:      timeToPtr(0),
218			Unlimited:     boolToPtr(false),
219		}
220	}
221	return dp
222}
223
224func (r *ReschedulePolicy) Copy() *ReschedulePolicy {
225	if r == nil {
226		return nil
227	}
228	nrp := new(ReschedulePolicy)
229	*nrp = *r
230	return nrp
231}
232
233func (p *ReschedulePolicy) String() string {
234	if p == nil {
235		return ""
236	}
237	if *p.Unlimited {
238		return fmt.Sprintf("unlimited with %v delay, max_delay = %v", *p.DelayFunction, *p.MaxDelay)
239	}
240	return fmt.Sprintf("%v in %v with %v delay, max_delay = %v", *p.Attempts, *p.Interval, *p.DelayFunction, *p.MaxDelay)
241}
242
243// Spread is used to serialize task group allocation spread preferences
244type Spread struct {
245	Attribute    string
246	Weight       *int8
247	SpreadTarget []*SpreadTarget
248}
249
250// SpreadTarget is used to serialize target allocation spread percentages
251type SpreadTarget struct {
252	Value   string
253	Percent uint8
254}
255
256func NewSpreadTarget(value string, percent uint8) *SpreadTarget {
257	return &SpreadTarget{
258		Value:   value,
259		Percent: percent,
260	}
261}
262
263func NewSpread(attribute string, weight int8, spreadTargets []*SpreadTarget) *Spread {
264	return &Spread{
265		Attribute:    attribute,
266		Weight:       int8ToPtr(weight),
267		SpreadTarget: spreadTargets,
268	}
269}
270
271func (s *Spread) Canonicalize() {
272	if s.Weight == nil {
273		s.Weight = int8ToPtr(50)
274	}
275}
276
277// EphemeralDisk is an ephemeral disk object
278type EphemeralDisk struct {
279	Sticky  *bool
280	Migrate *bool
281	SizeMB  *int `mapstructure:"size"`
282}
283
284func DefaultEphemeralDisk() *EphemeralDisk {
285	return &EphemeralDisk{
286		Sticky:  boolToPtr(false),
287		Migrate: boolToPtr(false),
288		SizeMB:  intToPtr(300),
289	}
290}
291
292func (e *EphemeralDisk) Canonicalize() {
293	if e.Sticky == nil {
294		e.Sticky = boolToPtr(false)
295	}
296	if e.Migrate == nil {
297		e.Migrate = boolToPtr(false)
298	}
299	if e.SizeMB == nil {
300		e.SizeMB = intToPtr(300)
301	}
302}
303
304// MigrateStrategy describes how allocations for a task group should be
305// migrated between nodes (eg when draining).
306type MigrateStrategy struct {
307	MaxParallel     *int           `mapstructure:"max_parallel"`
308	HealthCheck     *string        `mapstructure:"health_check"`
309	MinHealthyTime  *time.Duration `mapstructure:"min_healthy_time"`
310	HealthyDeadline *time.Duration `mapstructure:"healthy_deadline"`
311}
312
313func DefaultMigrateStrategy() *MigrateStrategy {
314	return &MigrateStrategy{
315		MaxParallel:     intToPtr(1),
316		HealthCheck:     stringToPtr("checks"),
317		MinHealthyTime:  timeToPtr(10 * time.Second),
318		HealthyDeadline: timeToPtr(5 * time.Minute),
319	}
320}
321
322func (m *MigrateStrategy) Canonicalize() {
323	if m == nil {
324		return
325	}
326	defaults := DefaultMigrateStrategy()
327	if m.MaxParallel == nil {
328		m.MaxParallel = defaults.MaxParallel
329	}
330	if m.HealthCheck == nil {
331		m.HealthCheck = defaults.HealthCheck
332	}
333	if m.MinHealthyTime == nil {
334		m.MinHealthyTime = defaults.MinHealthyTime
335	}
336	if m.HealthyDeadline == nil {
337		m.HealthyDeadline = defaults.HealthyDeadline
338	}
339}
340
341func (m *MigrateStrategy) Merge(o *MigrateStrategy) {
342	if o.MaxParallel != nil {
343		m.MaxParallel = o.MaxParallel
344	}
345	if o.HealthCheck != nil {
346		m.HealthCheck = o.HealthCheck
347	}
348	if o.MinHealthyTime != nil {
349		m.MinHealthyTime = o.MinHealthyTime
350	}
351	if o.HealthyDeadline != nil {
352		m.HealthyDeadline = o.HealthyDeadline
353	}
354}
355
356func (m *MigrateStrategy) Copy() *MigrateStrategy {
357	if m == nil {
358		return nil
359	}
360	nm := new(MigrateStrategy)
361	*nm = *m
362	return nm
363}
364
365// VolumeRequest is a representation of a storage volume that a TaskGroup wishes to use.
366type VolumeRequest struct {
367	Name     string
368	Type     string
369	Source   string
370	ReadOnly bool `mapstructure:"read_only"`
371}
372
373const (
374	VolumeMountPropagationPrivate       = "private"
375	VolumeMountPropagationHostToTask    = "host-to-task"
376	VolumeMountPropagationBidirectional = "bidirectional"
377)
378
379// VolumeMount represents the relationship between a destination path in a task
380// and the task group volume that should be mounted there.
381type VolumeMount struct {
382	Volume          *string
383	Destination     *string
384	ReadOnly        *bool   `mapstructure:"read_only"`
385	PropagationMode *string `mapstructure:"propagation_mode"`
386}
387
388func (vm *VolumeMount) Canonicalize() {
389	if vm.PropagationMode == nil {
390		vm.PropagationMode = stringToPtr(VolumeMountPropagationPrivate)
391	}
392	if vm.ReadOnly == nil {
393		vm.ReadOnly = boolToPtr(false)
394	}
395}
396
397// TaskGroup is the unit of scheduling.
398type TaskGroup struct {
399	Name             *string
400	Count            *int
401	Constraints      []*Constraint
402	Affinities       []*Affinity
403	Tasks            []*Task
404	Spreads          []*Spread
405	Volumes          map[string]*VolumeRequest
406	RestartPolicy    *RestartPolicy
407	ReschedulePolicy *ReschedulePolicy
408	EphemeralDisk    *EphemeralDisk
409	Update           *UpdateStrategy
410	Migrate          *MigrateStrategy
411	Networks         []*NetworkResource
412	Meta             map[string]string
413	Services         []*Service
414	ShutdownDelay    *time.Duration `mapstructure:"shutdown_delay"`
415}
416
417// NewTaskGroup creates a new TaskGroup.
418func NewTaskGroup(name string, count int) *TaskGroup {
419	return &TaskGroup{
420		Name:  stringToPtr(name),
421		Count: intToPtr(count),
422	}
423}
424
425// Canonicalize sets defaults and merges settings that should be inherited from the job
426func (g *TaskGroup) Canonicalize(job *Job) {
427	if g.Name == nil {
428		g.Name = stringToPtr("")
429	}
430	if g.Count == nil {
431		g.Count = intToPtr(1)
432	}
433	for _, t := range g.Tasks {
434		t.Canonicalize(g, job)
435	}
436	if g.EphemeralDisk == nil {
437		g.EphemeralDisk = DefaultEphemeralDisk()
438	} else {
439		g.EphemeralDisk.Canonicalize()
440	}
441
442	// Merge the update policy from the job
443	if ju, tu := job.Update != nil, g.Update != nil; ju && tu {
444		// Merge the jobs and task groups definition of the update strategy
445		jc := job.Update.Copy()
446		jc.Merge(g.Update)
447		g.Update = jc
448	} else if ju && !job.Update.Empty() {
449		// Inherit the jobs as long as it is non-empty.
450		jc := job.Update.Copy()
451		g.Update = jc
452	}
453
454	if g.Update != nil {
455		g.Update.Canonicalize()
456	}
457
458	// Merge the reschedule policy from the job
459	if jr, tr := job.Reschedule != nil, g.ReschedulePolicy != nil; jr && tr {
460		jobReschedule := job.Reschedule.Copy()
461		jobReschedule.Merge(g.ReschedulePolicy)
462		g.ReschedulePolicy = jobReschedule
463	} else if jr {
464		jobReschedule := job.Reschedule.Copy()
465		g.ReschedulePolicy = jobReschedule
466	}
467	// Only use default reschedule policy for non system jobs
468	if g.ReschedulePolicy == nil && *job.Type != "system" {
469		g.ReschedulePolicy = NewDefaultReschedulePolicy(*job.Type)
470	}
471	if g.ReschedulePolicy != nil {
472		g.ReschedulePolicy.Canonicalize(*job.Type)
473	}
474	// Merge the migrate strategy from the job
475	if jm, tm := job.Migrate != nil, g.Migrate != nil; jm && tm {
476		jobMigrate := job.Migrate.Copy()
477		jobMigrate.Merge(g.Migrate)
478		g.Migrate = jobMigrate
479	} else if jm {
480		jobMigrate := job.Migrate.Copy()
481		g.Migrate = jobMigrate
482	}
483
484	// Merge with default reschedule policy
485	if g.Migrate == nil && *job.Type == "service" {
486		g.Migrate = &MigrateStrategy{}
487	}
488	if g.Migrate != nil {
489		g.Migrate.Canonicalize()
490	}
491
492	var defaultRestartPolicy *RestartPolicy
493	switch *job.Type {
494	case "service", "system":
495		// These needs to be in sync with DefaultServiceJobRestartPolicy in
496		// in nomad/structs/structs.go
497		defaultRestartPolicy = &RestartPolicy{
498			Delay:    timeToPtr(15 * time.Second),
499			Attempts: intToPtr(2),
500			Interval: timeToPtr(30 * time.Minute),
501			Mode:     stringToPtr(RestartPolicyModeFail),
502		}
503	default:
504		// These needs to be in sync with DefaultBatchJobRestartPolicy in
505		// in nomad/structs/structs.go
506		defaultRestartPolicy = &RestartPolicy{
507			Delay:    timeToPtr(15 * time.Second),
508			Attempts: intToPtr(3),
509			Interval: timeToPtr(24 * time.Hour),
510			Mode:     stringToPtr(RestartPolicyModeFail),
511		}
512	}
513
514	if g.RestartPolicy != nil {
515		defaultRestartPolicy.Merge(g.RestartPolicy)
516	}
517	g.RestartPolicy = defaultRestartPolicy
518
519	for _, spread := range g.Spreads {
520		spread.Canonicalize()
521	}
522	for _, a := range g.Affinities {
523		a.Canonicalize()
524	}
525	for _, n := range g.Networks {
526		n.Canonicalize()
527	}
528	for _, s := range g.Services {
529		s.Canonicalize(nil, g, job)
530	}
531}
532
533// Constrain is used to add a constraint to a task group.
534func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
535	g.Constraints = append(g.Constraints, c)
536	return g
537}
538
539// AddMeta is used to add a meta k/v pair to a task group
540func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
541	if g.Meta == nil {
542		g.Meta = make(map[string]string)
543	}
544	g.Meta[key] = val
545	return g
546}
547
548// AddTask is used to add a new task to a task group.
549func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
550	g.Tasks = append(g.Tasks, t)
551	return g
552}
553
554// AddAffinity is used to add a new affinity to a task group.
555func (g *TaskGroup) AddAffinity(a *Affinity) *TaskGroup {
556	g.Affinities = append(g.Affinities, a)
557	return g
558}
559
560// RequireDisk adds a ephemeral disk to the task group
561func (g *TaskGroup) RequireDisk(disk *EphemeralDisk) *TaskGroup {
562	g.EphemeralDisk = disk
563	return g
564}
565
566// AddSpread is used to add a new spread preference to a task group.
567func (g *TaskGroup) AddSpread(s *Spread) *TaskGroup {
568	g.Spreads = append(g.Spreads, s)
569	return g
570}
571
572// LogConfig provides configuration for log rotation
573type LogConfig struct {
574	MaxFiles      *int `mapstructure:"max_files"`
575	MaxFileSizeMB *int `mapstructure:"max_file_size"`
576}
577
578func DefaultLogConfig() *LogConfig {
579	return &LogConfig{
580		MaxFiles:      intToPtr(10),
581		MaxFileSizeMB: intToPtr(10),
582	}
583}
584
585func (l *LogConfig) Canonicalize() {
586	if l.MaxFiles == nil {
587		l.MaxFiles = intToPtr(10)
588	}
589	if l.MaxFileSizeMB == nil {
590		l.MaxFileSizeMB = intToPtr(10)
591	}
592}
593
594// DispatchPayloadConfig configures how a task gets its input from a job dispatch
595type DispatchPayloadConfig struct {
596	File string
597}
598
599// Task is a single process in a task group.
600type Task struct {
601	Name            string
602	Driver          string
603	User            string
604	Config          map[string]interface{}
605	Constraints     []*Constraint
606	Affinities      []*Affinity
607	Env             map[string]string
608	Services        []*Service
609	Resources       *Resources
610	Meta            map[string]string
611	KillTimeout     *time.Duration `mapstructure:"kill_timeout"`
612	LogConfig       *LogConfig     `mapstructure:"logs"`
613	Artifacts       []*TaskArtifact
614	Vault           *Vault
615	Templates       []*Template
616	DispatchPayload *DispatchPayloadConfig
617	VolumeMounts    []*VolumeMount
618	Leader          bool
619	ShutdownDelay   time.Duration `mapstructure:"shutdown_delay"`
620	KillSignal      string        `mapstructure:"kill_signal"`
621	Kind            string
622}
623
624func (t *Task) Canonicalize(tg *TaskGroup, job *Job) {
625	if t.Resources == nil {
626		t.Resources = &Resources{}
627	}
628	t.Resources.Canonicalize()
629	if t.KillTimeout == nil {
630		t.KillTimeout = timeToPtr(5 * time.Second)
631	}
632	if t.LogConfig == nil {
633		t.LogConfig = DefaultLogConfig()
634	} else {
635		t.LogConfig.Canonicalize()
636	}
637	for _, artifact := range t.Artifacts {
638		artifact.Canonicalize()
639	}
640	if t.Vault != nil {
641		t.Vault.Canonicalize()
642	}
643	for _, tmpl := range t.Templates {
644		tmpl.Canonicalize()
645	}
646	for _, s := range t.Services {
647		s.Canonicalize(t, tg, job)
648	}
649	for _, a := range t.Affinities {
650		a.Canonicalize()
651	}
652	for _, vm := range t.VolumeMounts {
653		vm.Canonicalize()
654	}
655}
656
657// TaskArtifact is used to download artifacts before running a task.
658type TaskArtifact struct {
659	GetterSource  *string           `mapstructure:"source"`
660	GetterOptions map[string]string `mapstructure:"options"`
661	GetterMode    *string           `mapstructure:"mode"`
662	RelativeDest  *string           `mapstructure:"destination"`
663}
664
665func (a *TaskArtifact) Canonicalize() {
666	if a.GetterMode == nil {
667		a.GetterMode = stringToPtr("any")
668	}
669	if a.GetterSource == nil {
670		// Shouldn't be possible, but we don't want to panic
671		a.GetterSource = stringToPtr("")
672	}
673	if a.RelativeDest == nil {
674		switch *a.GetterMode {
675		case "file":
676			// File mode should default to local/filename
677			dest := *a.GetterSource
678			dest = path.Base(dest)
679			dest = filepath.Join("local", dest)
680			a.RelativeDest = &dest
681		default:
682			// Default to a directory
683			a.RelativeDest = stringToPtr("local/")
684		}
685	}
686}
687
688type Template struct {
689	SourcePath   *string        `mapstructure:"source"`
690	DestPath     *string        `mapstructure:"destination"`
691	EmbeddedTmpl *string        `mapstructure:"data"`
692	ChangeMode   *string        `mapstructure:"change_mode"`
693	ChangeSignal *string        `mapstructure:"change_signal"`
694	Splay        *time.Duration `mapstructure:"splay"`
695	Perms        *string        `mapstructure:"perms"`
696	LeftDelim    *string        `mapstructure:"left_delimiter"`
697	RightDelim   *string        `mapstructure:"right_delimiter"`
698	Envvars      *bool          `mapstructure:"env"`
699	VaultGrace   *time.Duration `mapstructure:"vault_grace"`
700}
701
702func (tmpl *Template) Canonicalize() {
703	if tmpl.SourcePath == nil {
704		tmpl.SourcePath = stringToPtr("")
705	}
706	if tmpl.DestPath == nil {
707		tmpl.DestPath = stringToPtr("")
708	}
709	if tmpl.EmbeddedTmpl == nil {
710		tmpl.EmbeddedTmpl = stringToPtr("")
711	}
712	if tmpl.ChangeMode == nil {
713		tmpl.ChangeMode = stringToPtr("restart")
714	}
715	if tmpl.ChangeSignal == nil {
716		if *tmpl.ChangeMode == "signal" {
717			tmpl.ChangeSignal = stringToPtr("SIGHUP")
718		} else {
719			tmpl.ChangeSignal = stringToPtr("")
720		}
721	} else {
722		sig := *tmpl.ChangeSignal
723		tmpl.ChangeSignal = stringToPtr(strings.ToUpper(sig))
724	}
725	if tmpl.Splay == nil {
726		tmpl.Splay = timeToPtr(5 * time.Second)
727	}
728	if tmpl.Perms == nil {
729		tmpl.Perms = stringToPtr("0644")
730	}
731	if tmpl.LeftDelim == nil {
732		tmpl.LeftDelim = stringToPtr("{{")
733	}
734	if tmpl.RightDelim == nil {
735		tmpl.RightDelim = stringToPtr("}}")
736	}
737	if tmpl.Envvars == nil {
738		tmpl.Envvars = boolToPtr(false)
739	}
740	if tmpl.VaultGrace == nil {
741		tmpl.VaultGrace = timeToPtr(15 * time.Second)
742	}
743}
744
745type Vault struct {
746	Policies     []string
747	Env          *bool
748	ChangeMode   *string `mapstructure:"change_mode"`
749	ChangeSignal *string `mapstructure:"change_signal"`
750}
751
752func (v *Vault) Canonicalize() {
753	if v.Env == nil {
754		v.Env = boolToPtr(true)
755	}
756	if v.ChangeMode == nil {
757		v.ChangeMode = stringToPtr("restart")
758	}
759	if v.ChangeSignal == nil {
760		v.ChangeSignal = stringToPtr("SIGHUP")
761	}
762}
763
764// NewTask creates and initializes a new Task.
765func NewTask(name, driver string) *Task {
766	return &Task{
767		Name:   name,
768		Driver: driver,
769	}
770}
771
772// Configure is used to configure a single k/v pair on
773// the task.
774func (t *Task) SetConfig(key string, val interface{}) *Task {
775	if t.Config == nil {
776		t.Config = make(map[string]interface{})
777	}
778	t.Config[key] = val
779	return t
780}
781
782// SetMeta is used to add metadata k/v pairs to the task.
783func (t *Task) SetMeta(key, val string) *Task {
784	if t.Meta == nil {
785		t.Meta = make(map[string]string)
786	}
787	t.Meta[key] = val
788	return t
789}
790
791// Require is used to add resource requirements to a task.
792func (t *Task) Require(r *Resources) *Task {
793	t.Resources = r
794	return t
795}
796
797// Constraint adds a new constraints to a single task.
798func (t *Task) Constrain(c *Constraint) *Task {
799	t.Constraints = append(t.Constraints, c)
800	return t
801}
802
803// AddAffinity adds a new affinity to a single task.
804func (t *Task) AddAffinity(a *Affinity) *Task {
805	t.Affinities = append(t.Affinities, a)
806	return t
807}
808
809// SetLogConfig sets a log config to a task
810func (t *Task) SetLogConfig(l *LogConfig) *Task {
811	t.LogConfig = l
812	return t
813}
814
815// TaskState tracks the current state of a task and events that caused state
816// transitions.
817type TaskState struct {
818	State       string
819	Failed      bool
820	Restarts    uint64
821	LastRestart time.Time
822	StartedAt   time.Time
823	FinishedAt  time.Time
824	Events      []*TaskEvent
825}
826
827const (
828	TaskSetup                  = "Task Setup"
829	TaskSetupFailure           = "Setup Failure"
830	TaskDriverFailure          = "Driver Failure"
831	TaskDriverMessage          = "Driver"
832	TaskReceived               = "Received"
833	TaskFailedValidation       = "Failed Validation"
834	TaskStarted                = "Started"
835	TaskTerminated             = "Terminated"
836	TaskKilling                = "Killing"
837	TaskKilled                 = "Killed"
838	TaskRestarting             = "Restarting"
839	TaskNotRestarting          = "Not Restarting"
840	TaskDownloadingArtifacts   = "Downloading Artifacts"
841	TaskArtifactDownloadFailed = "Failed Artifact Download"
842	TaskSiblingFailed          = "Sibling Task Failed"
843	TaskSignaling              = "Signaling"
844	TaskRestartSignal          = "Restart Signaled"
845	TaskLeaderDead             = "Leader Task Dead"
846	TaskBuildingTaskDir        = "Building Task Directory"
847)
848
849// TaskEvent is an event that effects the state of a task and contains meta-data
850// appropriate to the events type.
851type TaskEvent struct {
852	Type           string
853	Time           int64
854	DisplayMessage string
855	Details        map[string]string
856	// DEPRECATION NOTICE: The following fields are all deprecated. see TaskEvent struct in structs.go for details.
857	FailsTask        bool
858	RestartReason    string
859	SetupError       string
860	DriverError      string
861	DriverMessage    string
862	ExitCode         int
863	Signal           int
864	Message          string
865	KillReason       string
866	KillTimeout      time.Duration
867	KillError        string
868	StartDelay       int64
869	DownloadError    string
870	ValidationError  string
871	DiskLimit        int64
872	DiskSize         int64
873	FailedSibling    string
874	VaultError       string
875	TaskSignalReason string
876	TaskSignal       string
877	GenericSource    string
878}
879