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