2015-09-09 20:02:39 +00:00
|
|
|
package api
|
|
|
|
|
2018-12-10 16:51:43 +00:00
|
|
|
import (
|
|
|
|
"strconv"
|
|
|
|
)
|
2017-02-06 19:48:28 +00:00
|
|
|
|
2015-09-09 20:02:39 +00:00
|
|
|
// Resources encapsulates the required resources of
|
|
|
|
// a given task or task group.
|
|
|
|
type Resources struct {
|
2021-03-26 20:07:12 +00:00
|
|
|
CPU *int `hcl:"cpu,optional"`
|
|
|
|
Cores *int `hcl:"cores,optional"`
|
|
|
|
MemoryMB *int `mapstructure:"memory" hcl:"memory,optional"`
|
|
|
|
MemoryMaxMB *int `mapstructure:"memory_max" hcl:"memory_max,optional"`
|
|
|
|
DiskMB *int `mapstructure:"disk" hcl:"disk,optional"`
|
|
|
|
Networks []*NetworkResource `hcl:"network,block"`
|
|
|
|
Devices []*RequestedDevice `hcl:"device,block"`
|
2018-12-06 23:09:26 +00:00
|
|
|
|
|
|
|
// COMPAT(0.10)
|
|
|
|
// XXX Deprecated. Please do not use. The field will be removed in Nomad
|
|
|
|
// 0.10 and is only being kept to allow any references to be removed before
|
|
|
|
// then.
|
2020-10-21 13:58:45 +00:00
|
|
|
IOPS *int `hcl:"iops,optional"`
|
2015-09-09 20:02:39 +00:00
|
|
|
}
|
|
|
|
|
2017-11-13 17:05:30 +00:00
|
|
|
// Canonicalize will supply missing values in the cases
|
|
|
|
// where they are not provided.
|
2017-02-13 23:18:17 +00:00
|
|
|
func (r *Resources) Canonicalize() {
|
2017-11-13 17:05:30 +00:00
|
|
|
defaultResources := DefaultResources()
|
2021-03-19 03:13:30 +00:00
|
|
|
if r.Cores == nil {
|
|
|
|
r.Cores = defaultResources.Cores
|
|
|
|
|
|
|
|
// only set cpu to the default value if it and cores is not defined
|
|
|
|
if r.CPU == nil {
|
|
|
|
r.CPU = defaultResources.CPU
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CPU will be set to the default if cores is nil above.
|
|
|
|
// If cpu is nil here then cores has been set and cpu should be 0
|
2017-02-22 20:30:05 +00:00
|
|
|
if r.CPU == nil {
|
2021-03-19 03:13:30 +00:00
|
|
|
r.CPU = intToPtr(0)
|
2017-02-22 20:30:05 +00:00
|
|
|
}
|
2021-03-19 03:13:30 +00:00
|
|
|
|
2017-02-22 20:30:05 +00:00
|
|
|
if r.MemoryMB == nil {
|
2017-11-13 17:05:30 +00:00
|
|
|
r.MemoryMB = defaultResources.MemoryMB
|
2017-02-22 20:30:05 +00:00
|
|
|
}
|
2018-10-08 23:09:41 +00:00
|
|
|
for _, d := range r.Devices {
|
|
|
|
d.Canonicalize()
|
|
|
|
}
|
2017-02-13 23:18:17 +00:00
|
|
|
}
|
|
|
|
|
2017-11-13 17:05:30 +00:00
|
|
|
// DefaultResources is a small resources object that contains the
|
|
|
|
// default resources requests that we will provide to an object.
|
2017-11-13 17:25:02 +00:00
|
|
|
// --- THIS FUNCTION IS REPLICATED IN nomad/structs/structs.go
|
2017-11-13 17:05:30 +00:00
|
|
|
// and should be kept in sync.
|
|
|
|
func DefaultResources() *Resources {
|
|
|
|
return &Resources{
|
2019-01-18 18:28:35 +00:00
|
|
|
CPU: intToPtr(100),
|
2021-03-19 03:13:30 +00:00
|
|
|
Cores: intToPtr(0),
|
2019-01-18 18:28:35 +00:00
|
|
|
MemoryMB: intToPtr(300),
|
2017-11-13 17:05:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MinResources is a small resources object that contains the
|
|
|
|
// absolute minimum resources that we will provide to an object.
|
2017-11-13 17:25:02 +00:00
|
|
|
// This should not be confused with the defaults which are
|
|
|
|
// provided in DefaultResources() --- THIS LOGIC IS REPLICATED
|
2017-11-13 17:05:30 +00:00
|
|
|
// IN nomad/structs/structs.go and should be kept in sync.
|
2017-02-06 19:48:28 +00:00
|
|
|
func MinResources() *Resources {
|
|
|
|
return &Resources{
|
2020-09-30 19:09:41 +00:00
|
|
|
CPU: intToPtr(1),
|
2021-03-19 03:13:30 +00:00
|
|
|
Cores: intToPtr(0),
|
2019-01-18 18:28:35 +00:00
|
|
|
MemoryMB: intToPtr(10),
|
2017-02-06 19:48:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge merges this resource with another resource.
|
|
|
|
func (r *Resources) Merge(other *Resources) {
|
|
|
|
if other == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if other.CPU != nil {
|
|
|
|
r.CPU = other.CPU
|
|
|
|
}
|
|
|
|
if other.MemoryMB != nil {
|
|
|
|
r.MemoryMB = other.MemoryMB
|
|
|
|
}
|
|
|
|
if other.DiskMB != nil {
|
|
|
|
r.DiskMB = other.DiskMB
|
|
|
|
}
|
|
|
|
if len(other.Networks) != 0 {
|
|
|
|
r.Networks = other.Networks
|
|
|
|
}
|
2018-10-08 22:38:03 +00:00
|
|
|
if len(other.Devices) != 0 {
|
|
|
|
r.Devices = other.Devices
|
|
|
|
}
|
2017-02-06 19:48:28 +00:00
|
|
|
}
|
|
|
|
|
2015-11-14 04:51:30 +00:00
|
|
|
type Port struct {
|
2020-10-21 13:58:45 +00:00
|
|
|
Label string `hcl:",label"`
|
|
|
|
Value int `mapstructure:"static" hcl:"static,optional"`
|
|
|
|
To int `mapstructure:"to" hcl:"to,optional"`
|
|
|
|
HostNetwork string `mapstructure:"host_network" hcl:"host_network,optional"`
|
2015-11-14 04:51:30 +00:00
|
|
|
}
|
|
|
|
|
2020-04-28 03:11:06 +00:00
|
|
|
type DNSConfig struct {
|
2020-10-21 13:58:45 +00:00
|
|
|
Servers []string `mapstructure:"servers" hcl:"servers,optional"`
|
|
|
|
Searches []string `mapstructure:"searches" hcl:"searches,optional"`
|
|
|
|
Options []string `mapstructure:"options" hcl:"options,optional"`
|
2020-04-28 03:11:06 +00:00
|
|
|
}
|
|
|
|
|
2015-09-09 20:02:39 +00:00
|
|
|
// NetworkResource is used to describe required network
|
|
|
|
// resources of a given task.
|
|
|
|
type NetworkResource struct {
|
2020-10-21 13:58:45 +00:00
|
|
|
Mode string `hcl:"mode,optional"`
|
|
|
|
Device string `hcl:"device,optional"`
|
|
|
|
CIDR string `hcl:"cidr,optional"`
|
|
|
|
IP string `hcl:"ip,optional"`
|
|
|
|
DNS *DNSConfig `hcl:"dns,block"`
|
|
|
|
ReservedPorts []Port `hcl:"reserved_ports,block"`
|
|
|
|
DynamicPorts []Port `hcl:"port,block"`
|
2020-09-15 16:38:45 +00:00
|
|
|
|
|
|
|
// COMPAT(0.13)
|
|
|
|
// XXX Deprecated. Please do not use. The field will be removed in Nomad
|
|
|
|
// 0.13 and is only being kept to allow any references to be removed before
|
|
|
|
// then.
|
|
|
|
MBits *int `hcl:"mbits,optional"`
|
2017-02-13 23:18:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 17:35:51 +00:00
|
|
|
// COMPAT(0.13)
|
|
|
|
// XXX Deprecated. Please do not use. The method will be removed in Nomad
|
|
|
|
// 0.13 and is only being kept to allow any references to be removed before
|
|
|
|
// then.
|
|
|
|
func (n *NetworkResource) Megabits() int {
|
|
|
|
if n == nil || n.MBits == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return *n.MBits
|
|
|
|
}
|
|
|
|
|
2017-02-13 23:18:17 +00:00
|
|
|
func (n *NetworkResource) Canonicalize() {
|
2020-09-14 18:55:17 +00:00
|
|
|
// COMPAT(0.13)
|
|
|
|
// Noop to maintain backwards compatibility
|
2015-09-09 20:02:39 +00:00
|
|
|
}
|
2018-10-08 22:38:03 +00:00
|
|
|
|
2019-08-28 03:59:36 +00:00
|
|
|
func (n *NetworkResource) HasPorts() bool {
|
|
|
|
if n == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return len(n.ReservedPorts)+len(n.DynamicPorts) > 0
|
|
|
|
}
|
|
|
|
|
2018-11-13 22:24:15 +00:00
|
|
|
// NodeDeviceResource captures a set of devices sharing a common
|
|
|
|
// vendor/type/device_name tuple.
|
|
|
|
type NodeDeviceResource struct {
|
|
|
|
|
|
|
|
// Vendor specifies the vendor of device
|
|
|
|
Vendor string
|
|
|
|
|
|
|
|
// Type specifies the type of the device
|
|
|
|
Type string
|
|
|
|
|
|
|
|
// Name specifies the specific model of the device
|
|
|
|
Name string
|
|
|
|
|
|
|
|
// Instances are list of the devices matching the vendor/type/name
|
|
|
|
Instances []*NodeDevice
|
|
|
|
|
|
|
|
Attributes map[string]*Attribute
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:51:43 +00:00
|
|
|
func (r NodeDeviceResource) ID() string {
|
|
|
|
return r.Vendor + "/" + r.Type + "/" + r.Name
|
|
|
|
}
|
|
|
|
|
2018-11-13 22:24:15 +00:00
|
|
|
// NodeDevice is an instance of a particular device.
|
|
|
|
type NodeDevice struct {
|
|
|
|
// ID is the ID of the device.
|
|
|
|
ID string
|
|
|
|
|
|
|
|
// Healthy captures whether the device is healthy.
|
|
|
|
Healthy bool
|
|
|
|
|
|
|
|
// HealthDescription is used to provide a human readable description of why
|
|
|
|
// the device may be unhealthy.
|
|
|
|
HealthDescription string
|
|
|
|
|
|
|
|
// Locality stores HW locality information for the node to optionally be
|
|
|
|
// used when making placement decisions.
|
|
|
|
Locality *NodeDeviceLocality
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attribute is used to describe the value of an attribute, optionally
|
|
|
|
// specifying units
|
|
|
|
type Attribute struct {
|
|
|
|
// Float is the float value for the attribute
|
2018-12-10 16:51:43 +00:00
|
|
|
FloatVal *float64 `json:"Float,omitempty"`
|
2018-11-13 22:24:15 +00:00
|
|
|
|
|
|
|
// Int is the int value for the attribute
|
2018-12-10 16:51:43 +00:00
|
|
|
IntVal *int64 `json:"Int,omitempty"`
|
2018-11-13 22:24:15 +00:00
|
|
|
|
|
|
|
// String is the string value for the attribute
|
2018-12-10 16:51:43 +00:00
|
|
|
StringVal *string `json:"String,omitempty"`
|
2018-11-13 22:24:15 +00:00
|
|
|
|
|
|
|
// Bool is the bool value for the attribute
|
2018-12-10 16:51:43 +00:00
|
|
|
BoolVal *bool `json:"Bool,omitempty"`
|
2018-11-13 22:24:15 +00:00
|
|
|
|
|
|
|
// Unit is the optional unit for the set int or float value
|
|
|
|
Unit string
|
|
|
|
}
|
|
|
|
|
2018-12-10 16:51:43 +00:00
|
|
|
func (a Attribute) String() string {
|
|
|
|
switch {
|
|
|
|
case a.FloatVal != nil:
|
2019-01-18 18:36:49 +00:00
|
|
|
str := formatFloat(*a.FloatVal, 3)
|
2018-12-10 16:51:43 +00:00
|
|
|
if a.Unit != "" {
|
|
|
|
str += " " + a.Unit
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
case a.IntVal != nil:
|
|
|
|
str := strconv.FormatInt(*a.IntVal, 10)
|
|
|
|
if a.Unit != "" {
|
|
|
|
str += " " + a.Unit
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
case a.StringVal != nil:
|
|
|
|
return *a.StringVal
|
|
|
|
case a.BoolVal != nil:
|
|
|
|
return strconv.FormatBool(*a.BoolVal)
|
|
|
|
default:
|
|
|
|
return "<unknown>"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 22:24:15 +00:00
|
|
|
// NodeDeviceLocality stores information about the devices hardware locality on
|
|
|
|
// the node.
|
|
|
|
type NodeDeviceLocality struct {
|
|
|
|
// PciBusID is the PCI Bus ID for the device.
|
|
|
|
PciBusID string
|
|
|
|
}
|
|
|
|
|
2018-10-08 22:38:03 +00:00
|
|
|
// RequestedDevice is used to request a device for a task.
|
|
|
|
type RequestedDevice struct {
|
|
|
|
// Name is the request name. The possible values are as follows:
|
|
|
|
// * <type>: A single value only specifies the type of request.
|
|
|
|
// * <vendor>/<type>: A single slash delimiter assumes the vendor and type of device is specified.
|
|
|
|
// * <vendor>/<type>/<name>: Two slash delimiters assume vendor, type and specific model are specified.
|
|
|
|
//
|
|
|
|
// Examples are as follows:
|
|
|
|
// * "gpu"
|
|
|
|
// * "nvidia/gpu"
|
|
|
|
// * "nvidia/gpu/GTX2080Ti"
|
2020-10-21 13:58:45 +00:00
|
|
|
Name string `hcl:",label"`
|
2018-10-08 22:38:03 +00:00
|
|
|
|
|
|
|
// Count is the number of requested devices
|
2020-10-21 13:58:45 +00:00
|
|
|
Count *uint64 `hcl:"count,optional"`
|
2018-10-11 21:05:19 +00:00
|
|
|
|
|
|
|
// Constraints are a set of constraints to apply when selecting the device
|
|
|
|
// to use.
|
2020-10-21 13:58:45 +00:00
|
|
|
Constraints []*Constraint `hcl:"constraint,block"`
|
2018-10-11 21:05:19 +00:00
|
|
|
|
|
|
|
// Affinities are a set of affinites to apply when selecting the device
|
|
|
|
// to use.
|
2020-10-21 13:58:45 +00:00
|
|
|
Affinities []*Affinity `hcl:"affinity,block"`
|
2018-10-08 23:09:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (d *RequestedDevice) Canonicalize() {
|
|
|
|
if d.Count == nil {
|
2019-01-18 18:28:35 +00:00
|
|
|
d.Count = uint64ToPtr(1)
|
2018-10-08 23:09:41 +00:00
|
|
|
}
|
2019-01-30 20:20:38 +00:00
|
|
|
|
|
|
|
for _, a := range d.Affinities {
|
|
|
|
a.Canonicalize()
|
|
|
|
}
|
2018-10-08 22:38:03 +00:00
|
|
|
}
|