github.com/hernad/nomad@v1.6.112/nomad/structs/node_pool.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package structs 5 6 import ( 7 "fmt" 8 "regexp" 9 "sort" 10 11 "github.com/hashicorp/go-multierror" 12 "github.com/hernad/nomad/helper/pointer" 13 "golang.org/x/crypto/blake2b" 14 "golang.org/x/exp/maps" 15 ) 16 17 const ( 18 // NodePoolAll is a built-in node pool that always includes all nodes in 19 // the cluster. 20 NodePoolAll = "all" 21 NodePoolAllDescription = "Node pool with all nodes in the cluster." 22 23 // NodePoolDefault is a built-in node pool for nodes that don't specify a 24 // node pool in their configuration. 25 NodePoolDefault = "default" 26 NodePoolDefaultDescription = "Default node pool." 27 28 // maxNodePoolDescriptionLength is the maximum length allowed for a node 29 // pool description. 30 maxNodePoolDescriptionLength = 256 31 ) 32 33 var ( 34 // validNodePoolName is the rule used to validate a node pool name. 35 validNodePoolName = regexp.MustCompile("^[a-zA-Z0-9-_]{1,128}$") 36 ) 37 38 // ValidadeNodePoolName returns an error if a node pool name is invalid. 39 func ValidateNodePoolName(pool string) error { 40 if !validNodePoolName.MatchString(pool) { 41 return fmt.Errorf("invalid name %q, must match regex %s", pool, validNodePoolName) 42 } 43 return nil 44 } 45 46 // NodePool allows partioning infrastructure 47 type NodePool struct { 48 // Name is the node pool name. It must be unique. 49 Name string 50 51 // Description is the human-friendly description of the node pool. 52 Description string 53 54 // Meta is a set of user-provided metadata for the node pool. 55 Meta map[string]string 56 57 // SchedulerConfiguration is the scheduler configuration specific to the 58 // node pool. 59 SchedulerConfiguration *NodePoolSchedulerConfiguration 60 61 // Hash is the hash of the node pool which is used to efficiently diff when 62 // we replicate pools across regions. 63 Hash []byte 64 65 // Raft indexes. 66 CreateIndex uint64 67 ModifyIndex uint64 68 } 69 70 // GetID implements the IDGetter interface required for pagination. 71 func (n *NodePool) GetID() string { 72 return n.Name 73 } 74 75 // Validate returns an error if the node pool is invalid. 76 func (n *NodePool) Validate() error { 77 var mErr *multierror.Error 78 79 mErr = multierror.Append(mErr, ValidateNodePoolName(n.Name)) 80 81 if len(n.Description) > maxNodePoolDescriptionLength { 82 mErr = multierror.Append(mErr, fmt.Errorf("description longer than %d", maxNodePoolDescriptionLength)) 83 } 84 85 mErr = multierror.Append(mErr, n.SchedulerConfiguration.Validate()) 86 87 return mErr.ErrorOrNil() 88 } 89 90 // Copy returns a deep copy of the node pool. 91 func (n *NodePool) Copy() *NodePool { 92 if n == nil { 93 return nil 94 } 95 96 nc := new(NodePool) 97 *nc = *n 98 nc.Meta = maps.Clone(nc.Meta) 99 nc.SchedulerConfiguration = nc.SchedulerConfiguration.Copy() 100 101 nc.Hash = make([]byte, len(n.Hash)) 102 copy(nc.Hash, n.Hash) 103 104 return nc 105 } 106 107 // IsBuiltIn returns true if the node pool is one of the built-in pools. 108 // 109 // Built-in node pools are created automatically by Nomad and can never be 110 // deleted or modified so they are always present in the cluster.. 111 func (n *NodePool) IsBuiltIn() bool { 112 switch n.Name { 113 case NodePoolAll, NodePoolDefault: 114 return true 115 default: 116 return false 117 } 118 } 119 120 // MemoryOversubscriptionEnabled returns true if memory oversubscription is 121 // enabled in the node pool or in the global cluster configuration. 122 func (n *NodePool) MemoryOversubscriptionEnabled(global *SchedulerConfiguration) bool { 123 124 // Default to the global scheduler config. 125 memOversubEnabled := global != nil && global.MemoryOversubscriptionEnabled 126 127 // But overwrite it if the node pool also has it configured. 128 poolHasMemOversub := n != nil && 129 n.SchedulerConfiguration != nil && 130 n.SchedulerConfiguration.MemoryOversubscriptionEnabled != nil 131 if poolHasMemOversub { 132 memOversubEnabled = *n.SchedulerConfiguration.MemoryOversubscriptionEnabled 133 } 134 135 return memOversubEnabled 136 } 137 138 // SetHash is used to compute and set the hash of node pool 139 func (n *NodePool) SetHash() []byte { 140 // Initialize a 256bit Blake2 hash (32 bytes) 141 hash, err := blake2b.New256(nil) 142 if err != nil { 143 panic(err) 144 } 145 146 // Write all the user set fields 147 _, _ = hash.Write([]byte(n.Name)) 148 _, _ = hash.Write([]byte(n.Description)) 149 if n.SchedulerConfiguration != nil { 150 _, _ = hash.Write([]byte(n.SchedulerConfiguration.SchedulerAlgorithm)) 151 152 memSub := n.SchedulerConfiguration.MemoryOversubscriptionEnabled 153 if memSub != nil { 154 if *memSub { 155 _, _ = hash.Write([]byte("memory_oversubscription_enabled")) 156 } else { 157 _, _ = hash.Write([]byte("memory_oversubscription_disabled")) 158 } 159 } 160 } 161 162 // sort keys to ensure hash stability when meta is stored later 163 var keys []string 164 for k := range n.Meta { 165 keys = append(keys, k) 166 } 167 sort.Strings(keys) 168 169 for _, k := range keys { 170 _, _ = hash.Write([]byte(k)) 171 _, _ = hash.Write([]byte(n.Meta[k])) 172 } 173 174 // Finalize the hash 175 hashVal := hash.Sum(nil) 176 177 // Set and return the hash 178 n.Hash = hashVal 179 return hashVal 180 } 181 182 // NodePoolSchedulerConfiguration is the scheduler confinguration applied to a 183 // node pool. 184 // 185 // When adding new values that should override global scheduler configuration, 186 // verify the scheduler handles the node pool configuration as well. 187 type NodePoolSchedulerConfiguration struct { 188 189 // SchedulerAlgorithm is the scheduling algorithm to use for the pool. 190 // If not defined, the global cluster scheduling algorithm is used. 191 SchedulerAlgorithm SchedulerAlgorithm `hcl:"scheduler_algorithm"` 192 193 // MemoryOversubscriptionEnabled specifies whether memory oversubscription 194 // is enabled. If not defined, the global cluster configuration is used. 195 MemoryOversubscriptionEnabled *bool `hcl:"memory_oversubscription_enabled"` 196 } 197 198 // Copy returns a deep copy of the node pool scheduler configuration. 199 func (n *NodePoolSchedulerConfiguration) Copy() *NodePoolSchedulerConfiguration { 200 if n == nil { 201 return nil 202 } 203 204 nc := new(NodePoolSchedulerConfiguration) 205 *nc = *n 206 207 if n.MemoryOversubscriptionEnabled != nil { 208 nc.MemoryOversubscriptionEnabled = pointer.Of(*n.MemoryOversubscriptionEnabled) 209 } 210 211 return nc 212 } 213 214 // NodePoolListRequest is used to list node pools. 215 type NodePoolListRequest struct { 216 QueryOptions 217 } 218 219 // NodePoolListResponse is the response to node pools list request. 220 type NodePoolListResponse struct { 221 NodePools []*NodePool 222 QueryMeta 223 } 224 225 // NodePoolSpecificRequest is used to make a request for a specific node pool. 226 type NodePoolSpecificRequest struct { 227 Name string 228 QueryOptions 229 } 230 231 // SingleNodePoolResponse is the response to a specific node pool request. 232 type SingleNodePoolResponse struct { 233 NodePool *NodePool 234 QueryMeta 235 } 236 237 // NodePoolUpsertRequest is used to make a request to insert or update a node 238 // pool. 239 type NodePoolUpsertRequest struct { 240 NodePools []*NodePool 241 WriteRequest 242 } 243 244 // NodePoolDeleteRequest is used to make a request to delete a node pool. 245 type NodePoolDeleteRequest struct { 246 Names []string 247 WriteRequest 248 } 249 250 // NodePoolNodesRequest is used to list all nodes that are part of a node pool. 251 type NodePoolNodesRequest struct { 252 Name string 253 Fields *NodeStubFields 254 QueryOptions 255 } 256 257 // NodePoolNodesResponse is used to return a list nodes in the node pool. 258 type NodePoolNodesResponse struct { 259 Nodes []*NodeListStub 260 QueryMeta 261 } 262 263 // NodePoolJobsRequest is used to make a request for the jobs in a specific node pool. 264 type NodePoolJobsRequest struct { 265 Name string 266 Fields *JobStubFields 267 QueryOptions 268 } 269 270 // NodePoolJobsResponse returns a list of jobs in a specific node pool. 271 type NodePoolJobsResponse struct { 272 Jobs []*JobListStub 273 QueryMeta 274 }