1package api
2
3import (
4	"strconv"
5)
6
7// Resources encapsulates the required resources of
8// a given task or task group.
9type Resources struct {
10	CPU         *int               `hcl:"cpu,optional"`
11	Cores       *int               `hcl:"cores,optional"`
12	MemoryMB    *int               `mapstructure:"memory" hcl:"memory,optional"`
13	MemoryMaxMB *int               `mapstructure:"memory_max" hcl:"memory_max,optional"`
14	DiskMB      *int               `mapstructure:"disk" hcl:"disk,optional"`
15	Networks    []*NetworkResource `hcl:"network,block"`
16	Devices     []*RequestedDevice `hcl:"device,block"`
17
18	// COMPAT(0.10)
19	// XXX Deprecated. Please do not use. The field will be removed in Nomad
20	// 0.10 and is only being kept to allow any references to be removed before
21	// then.
22	IOPS *int `hcl:"iops,optional"`
23}
24
25// Canonicalize will supply missing values in the cases
26// where they are not provided.
27func (r *Resources) Canonicalize() {
28	defaultResources := DefaultResources()
29	if r.Cores == nil {
30		r.Cores = defaultResources.Cores
31
32		// only set cpu to the default value if it and cores is not defined
33		if r.CPU == nil {
34			r.CPU = defaultResources.CPU
35		}
36	}
37
38	// CPU will be set to the default if cores is nil above.
39	// If cpu is nil here then cores has been set and cpu should be 0
40	if r.CPU == nil {
41		r.CPU = intToPtr(0)
42	}
43
44	if r.MemoryMB == nil {
45		r.MemoryMB = defaultResources.MemoryMB
46	}
47	for _, d := range r.Devices {
48		d.Canonicalize()
49	}
50}
51
52// DefaultResources is a small resources object that contains the
53// default resources requests that we will provide to an object.
54// ---  THIS FUNCTION IS REPLICATED IN nomad/structs/structs.go
55// and should be kept in sync.
56func DefaultResources() *Resources {
57	return &Resources{
58		CPU:      intToPtr(100),
59		Cores:    intToPtr(0),
60		MemoryMB: intToPtr(300),
61	}
62}
63
64// MinResources is a small resources object that contains the
65// absolute minimum resources that we will provide to an object.
66// This should not be confused with the defaults which are
67// provided in DefaultResources() ---  THIS LOGIC IS REPLICATED
68// IN nomad/structs/structs.go and should be kept in sync.
69func MinResources() *Resources {
70	return &Resources{
71		CPU:      intToPtr(1),
72		Cores:    intToPtr(0),
73		MemoryMB: intToPtr(10),
74	}
75}
76
77// Merge merges this resource with another resource.
78func (r *Resources) Merge(other *Resources) {
79	if other == nil {
80		return
81	}
82	if other.CPU != nil {
83		r.CPU = other.CPU
84	}
85	if other.MemoryMB != nil {
86		r.MemoryMB = other.MemoryMB
87	}
88	if other.DiskMB != nil {
89		r.DiskMB = other.DiskMB
90	}
91	if len(other.Networks) != 0 {
92		r.Networks = other.Networks
93	}
94	if len(other.Devices) != 0 {
95		r.Devices = other.Devices
96	}
97}
98
99type Port struct {
100	Label       string `hcl:",label"`
101	Value       int    `mapstructure:"static" hcl:"static,optional"`
102	To          int    `mapstructure:"to" hcl:"to,optional"`
103	HostNetwork string `mapstructure:"host_network" hcl:"host_network,optional"`
104}
105
106type DNSConfig struct {
107	Servers  []string `mapstructure:"servers" hcl:"servers,optional"`
108	Searches []string `mapstructure:"searches" hcl:"searches,optional"`
109	Options  []string `mapstructure:"options" hcl:"options,optional"`
110}
111
112// NetworkResource is used to describe required network
113// resources of a given task.
114type NetworkResource struct {
115	Mode          string     `hcl:"mode,optional"`
116	Device        string     `hcl:"device,optional"`
117	CIDR          string     `hcl:"cidr,optional"`
118	IP            string     `hcl:"ip,optional"`
119	DNS           *DNSConfig `hcl:"dns,block"`
120	ReservedPorts []Port     `hcl:"reserved_ports,block"`
121	DynamicPorts  []Port     `hcl:"port,block"`
122
123	// COMPAT(0.13)
124	// XXX Deprecated. Please do not use. The field will be removed in Nomad
125	// 0.13 and is only being kept to allow any references to be removed before
126	// then.
127	MBits *int `hcl:"mbits,optional"`
128}
129
130// COMPAT(0.13)
131// XXX Deprecated. Please do not use. The method will be removed in Nomad
132// 0.13 and is only being kept to allow any references to be removed before
133// then.
134func (n *NetworkResource) Megabits() int {
135	if n == nil || n.MBits == nil {
136		return 0
137	}
138	return *n.MBits
139}
140
141func (n *NetworkResource) Canonicalize() {
142	// COMPAT(0.13)
143	// Noop to maintain backwards compatibility
144}
145
146func (n *NetworkResource) HasPorts() bool {
147	if n == nil {
148		return false
149	}
150
151	return len(n.ReservedPorts)+len(n.DynamicPorts) > 0
152}
153
154// NodeDeviceResource captures a set of devices sharing a common
155// vendor/type/device_name tuple.
156type NodeDeviceResource struct {
157
158	// Vendor specifies the vendor of device
159	Vendor string
160
161	// Type specifies the type of the device
162	Type string
163
164	// Name specifies the specific model of the device
165	Name string
166
167	// Instances are list of the devices matching the vendor/type/name
168	Instances []*NodeDevice
169
170	Attributes map[string]*Attribute
171}
172
173func (r NodeDeviceResource) ID() string {
174	return r.Vendor + "/" + r.Type + "/" + r.Name
175}
176
177// NodeDevice is an instance of a particular device.
178type NodeDevice struct {
179	// ID is the ID of the device.
180	ID string
181
182	// Healthy captures whether the device is healthy.
183	Healthy bool
184
185	// HealthDescription is used to provide a human readable description of why
186	// the device may be unhealthy.
187	HealthDescription string
188
189	// Locality stores HW locality information for the node to optionally be
190	// used when making placement decisions.
191	Locality *NodeDeviceLocality
192}
193
194// Attribute is used to describe the value of an attribute, optionally
195// specifying units
196type Attribute struct {
197	// Float is the float value for the attribute
198	FloatVal *float64 `json:"Float,omitempty"`
199
200	// Int is the int value for the attribute
201	IntVal *int64 `json:"Int,omitempty"`
202
203	// String is the string value for the attribute
204	StringVal *string `json:"String,omitempty"`
205
206	// Bool is the bool value for the attribute
207	BoolVal *bool `json:"Bool,omitempty"`
208
209	// Unit is the optional unit for the set int or float value
210	Unit string
211}
212
213func (a Attribute) String() string {
214	switch {
215	case a.FloatVal != nil:
216		str := formatFloat(*a.FloatVal, 3)
217		if a.Unit != "" {
218			str += " " + a.Unit
219		}
220		return str
221	case a.IntVal != nil:
222		str := strconv.FormatInt(*a.IntVal, 10)
223		if a.Unit != "" {
224			str += " " + a.Unit
225		}
226		return str
227	case a.StringVal != nil:
228		return *a.StringVal
229	case a.BoolVal != nil:
230		return strconv.FormatBool(*a.BoolVal)
231	default:
232		return "<unknown>"
233	}
234}
235
236// NodeDeviceLocality stores information about the devices hardware locality on
237// the node.
238type NodeDeviceLocality struct {
239	// PciBusID is the PCI Bus ID for the device.
240	PciBusID string
241}
242
243// RequestedDevice is used to request a device for a task.
244type RequestedDevice struct {
245	// Name is the request name. The possible values are as follows:
246	// * <type>: A single value only specifies the type of request.
247	// * <vendor>/<type>: A single slash delimiter assumes the vendor and type of device is specified.
248	// * <vendor>/<type>/<name>: Two slash delimiters assume vendor, type and specific model are specified.
249	//
250	// Examples are as follows:
251	// * "gpu"
252	// * "nvidia/gpu"
253	// * "nvidia/gpu/GTX2080Ti"
254	Name string `hcl:",label"`
255
256	// Count is the number of requested devices
257	Count *uint64 `hcl:"count,optional"`
258
259	// Constraints are a set of constraints to apply when selecting the device
260	// to use.
261	Constraints []*Constraint `hcl:"constraint,block"`
262
263	// Affinities are a set of affinites to apply when selecting the device
264	// to use.
265	Affinities []*Affinity `hcl:"affinity,block"`
266}
267
268func (d *RequestedDevice) Canonicalize() {
269	if d.Count == nil {
270		d.Count = uint64ToPtr(1)
271	}
272
273	for _, a := range d.Affinities {
274		a.Canonicalize()
275	}
276}
277