diff --git a/api/node_pools.go b/api/node_pools.go
index f2fa67b49..d3f18bd87 100644
--- a/api/node_pools.go
+++ b/api/node_pools.go
@@ -118,7 +118,7 @@ type NodePool struct {
Name string `hcl:"name,label"`
Description string `hcl:"description,optional"`
Meta map[string]string `hcl:"meta,block"`
- SchedulerConfiguration *NodePoolSchedulerConfiguration `hcl:"scheduler_configuration,block"`
+ SchedulerConfiguration *NodePoolSchedulerConfiguration `hcl:"scheduler_config,block"`
CreateIndex uint64
ModifyIndex uint64
}
@@ -126,5 +126,6 @@ type NodePool struct {
// NodePoolSchedulerConfiguration is used to serialize the scheduler
// configuration of a node pool.
type NodePoolSchedulerConfiguration struct {
- SchedulerAlgorithm SchedulerAlgorithm `hcl:"scheduler_algorithm,optional"`
+ SchedulerAlgorithm SchedulerAlgorithm `hcl:"scheduler_algorithm,optional"`
+ MemoryOversubscriptionEnabled *bool `hcl:"memory_oversubscription_enabled,optional"`
}
diff --git a/command/agent/node_pool_endpoint_test.go b/command/agent/node_pool_endpoint_test.go
index 1e744fcb6..74e2770ff 100644
--- a/command/agent/node_pool_endpoint_test.go
+++ b/command/agent/node_pool_endpoint_test.go
@@ -172,9 +172,6 @@ func TestHTTP_NodePool_Update(t *testing.T) {
updated.Meta = map[string]string{
"updated": "true",
}
- updated.SchedulerConfiguration = &structs.NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: structs.SchedulerAlgorithmBinpack,
- }
buf := encodeReq(updated)
req, err := http.NewRequest("PUT", fmt.Sprintf("/v1/node/pool/%s", updated.Name), buf)
@@ -219,9 +216,6 @@ func TestHTTP_NodePool_Update(t *testing.T) {
updated.Meta = map[string]string{
"updated": "true",
}
- updated.SchedulerConfiguration = &structs.NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: structs.SchedulerAlgorithmBinpack,
- }
buf := encodeReq(updated)
req, err := http.NewRequest("PUT", "/v1/node/pool/", buf)
@@ -264,9 +258,6 @@ func TestHTTP_NodePool_Update(t *testing.T) {
updated.Meta = map[string]string{
"updated": "true",
}
- updated.SchedulerConfiguration = &structs.NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: structs.SchedulerAlgorithmBinpack,
- }
// Make request with the wrong path.
buf := encodeReq(updated)
diff --git a/command/asset/pool.nomad.hcl b/command/asset/pool.nomad.hcl
index e4c3ca228..b9a111359 100644
--- a/command/asset/pool.nomad.hcl
+++ b/command/asset/pool.nomad.hcl
@@ -17,9 +17,13 @@ node_pool "example" {
# * scheduler_algorithm is the scheduling algorithm to use for the pool.
# If not defined, the global cluster scheduling algorithm is used.
#
+ # * memory_oversubscription_enabled specifies whether memory oversubscription
+ # is enabled. If not defined, the global cluster configuration is used.
+ #
# Available only in Nomad Enterprise.
- # scheduler_configuration {
- # scheduler_algorithm = "spread"
+ # scheduler_config {
+ # scheduler_algorithm = "spread"
+ # memory_oversubscription_enabled = true
# }
}
diff --git a/command/asset/pool.nomad.json b/command/asset/pool.nomad.json
index 02622902a..16d205f26 100644
--- a/command/asset/pool.nomad.json
+++ b/command/asset/pool.nomad.json
@@ -6,6 +6,7 @@
"owner": "sre"
},
"SchedulerConfiguration": {
- "SchedulerAlgorithm": "spread"
+ "SchedulerAlgorithm": "spread",
+ "MemoryOversubscriptionEnabled": true
}
}
diff --git a/command/node_pool_info.go b/command/node_pool_info.go
index 34766e8e2..4a93e4471 100644
--- a/command/node_pool_info.go
+++ b/command/node_pool_info.go
@@ -130,11 +130,16 @@ func (c *NodePoolInfoCommand) Run(args []string) int {
}
c.Ui.Output(c.Colorize().Color("\n[bold]Scheduler Configuration[reset]"))
- if pool.SchedulerConfiguration != nil {
- schedConfig := []string{
- fmt.Sprintf("Scheduler Algorithm|%s", pool.SchedulerConfiguration.SchedulerAlgorithm),
+ if schedConfig := pool.SchedulerConfiguration; schedConfig != nil {
+ schedConfigOut := []string{
+ fmt.Sprintf("Scheduler Algorithm|%s", schedConfig.SchedulerAlgorithm),
}
- c.Ui.Output(formatKV(schedConfig))
+ if schedConfig.MemoryOversubscriptionEnabled != nil {
+ schedConfigOut = append(schedConfigOut,
+ fmt.Sprintf("Memory Oversubscription Enabled|%v", *schedConfig.MemoryOversubscriptionEnabled),
+ )
+ }
+ c.Ui.Output(formatKV(schedConfigOut))
} else {
c.Ui.Output("No scheduler configuration")
}
diff --git a/command/node_pool_info_test.go b/command/node_pool_info_test.go
index b8607ab9d..ef002f312 100644
--- a/command/node_pool_info_test.go
+++ b/command/node_pool_info_test.go
@@ -35,9 +35,6 @@ func TestNodePoolInfoCommand_Run(t *testing.T) {
Meta: map[string]string{
"env": "test",
},
- SchedulerConfiguration: &api.NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: api.SchedulerAlgorithmSpread,
- },
}
_, err := client.NodePools().Register(dev1, nil)
must.NoError(t, err)
@@ -50,7 +47,7 @@ Metadata
env = test
Scheduler Configuration
-Scheduler Algorithm = spread`
+No scheduler configuration`
dev1JsonOutput := `
{
@@ -59,9 +56,7 @@ Scheduler Algorithm = spread`
"env": "test"
},
"Name": "dev-1",
- "SchedulerConfiguration": {
- "SchedulerAlgorithm": "spread"
- }
+ "SchedulerConfiguration": null
}`
// These two node pools are used to test exact prefix match.
diff --git a/nomad/mock/mock.go b/nomad/mock/mock.go
index 45154e4c6..728a931aa 100644
--- a/nomad/mock/mock.go
+++ b/nomad/mock/mock.go
@@ -257,9 +257,6 @@ func NodePool() *structs.NodePool {
Name: fmt.Sprintf("pool-%s", uuid.Short()),
Description: "test node pool",
Meta: map[string]string{"team": "test"},
- SchedulerConfiguration: &structs.NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: structs.SchedulerAlgorithmSpread,
- },
}
pool.SetHash()
return pool
diff --git a/nomad/structs/node_pool.go b/nomad/structs/node_pool.go
index 39fc72046..e706b4ff2 100644
--- a/nomad/structs/node_pool.go
+++ b/nomad/structs/node_pool.go
@@ -9,6 +9,7 @@ import (
"sort"
"github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/nomad/helper/pointer"
"golang.org/x/crypto/blake2b"
"golang.org/x/exp/maps"
)
@@ -129,6 +130,15 @@ func (n *NodePool) SetHash() []byte {
_, _ = hash.Write([]byte(n.Description))
if n.SchedulerConfiguration != nil {
_, _ = hash.Write([]byte(n.SchedulerConfiguration.SchedulerAlgorithm))
+
+ memSub := n.SchedulerConfiguration.MemoryOversubscriptionEnabled
+ if memSub != nil {
+ if *memSub {
+ _, _ = hash.Write([]byte("memory_oversubscription_enabled"))
+ } else {
+ _, _ = hash.Write([]byte("memory_oversubscription_disabled"))
+ }
+ }
}
// sort keys to ensure hash stability when meta is stored later
@@ -158,6 +168,10 @@ type NodePoolSchedulerConfiguration struct {
// SchedulerAlgorithm is the scheduling algorithm to use for the pool.
// If not defined, the global cluster scheduling algorithm is used.
SchedulerAlgorithm SchedulerAlgorithm `hcl:"scheduler_algorithm"`
+
+ // MemoryOversubscriptionEnabled specifies whether memory oversubscription
+ // is enabled. If not defined, the global cluster configuration is used.
+ MemoryOversubscriptionEnabled *bool `hcl:"memory_oversubscription_enabled"`
}
// Copy returns a deep copy of the node pool scheduler configuration.
@@ -169,27 +183,13 @@ func (n *NodePoolSchedulerConfiguration) Copy() *NodePoolSchedulerConfiguration
nc := new(NodePoolSchedulerConfiguration)
*nc = *n
+ if n.MemoryOversubscriptionEnabled != nil {
+ nc.MemoryOversubscriptionEnabled = pointer.Of(*n.MemoryOversubscriptionEnabled)
+ }
+
return nc
}
-// Validate returns an error if the node pool scheduler confinguration is
-// invalid.
-func (n *NodePoolSchedulerConfiguration) Validate() error {
- if n == nil {
- return nil
- }
-
- var mErr *multierror.Error
-
- switch n.SchedulerAlgorithm {
- case "", SchedulerAlgorithmBinpack, SchedulerAlgorithmSpread:
- default:
- mErr = multierror.Append(mErr, fmt.Errorf("invalid scheduler algorithm %q", n.SchedulerAlgorithm))
- }
-
- return mErr.ErrorOrNil()
-}
-
// NodePoolListRequest is used to list node pools.
type NodePoolListRequest struct {
QueryOptions
diff --git a/nomad/structs/node_pool_oss.go b/nomad/structs/node_pool_oss.go
new file mode 100644
index 000000000..769c7aa49
--- /dev/null
+++ b/nomad/structs/node_pool_oss.go
@@ -0,0 +1,18 @@
+// copyright (c) hashicorp, inc.
+// spdx-license-identifier: mpl-2.0
+
+//go:build !ent
+// +build !ent
+
+package structs
+
+import "errors"
+
+// Validate returns an error if the node pool scheduler confinguration is
+// invalid.
+func (n *NodePoolSchedulerConfiguration) Validate() error {
+ if n != nil {
+ return errors.New("Node Pools Governance is unlicensed.")
+ }
+ return nil
+}
diff --git a/nomad/structs/node_pool_oss_test.go b/nomad/structs/node_pool_oss_test.go
new file mode 100644
index 000000000..8180411ba
--- /dev/null
+++ b/nomad/structs/node_pool_oss_test.go
@@ -0,0 +1,47 @@
+// copyright (c) hashicorp, inc.
+// spdx-license-identifier: mpl-2.0
+
+//go:build !ent
+// +build !ent
+
+package structs
+
+import (
+ "testing"
+
+ "github.com/hashicorp/nomad/ci"
+ "github.com/shoenig/test/must"
+)
+
+func TestNodePool_Validate_OSS(t *testing.T) {
+ ci.Parallel(t)
+
+ testCases := []struct {
+ name string
+ pool *NodePool
+ expectedErr string
+ }{
+ {
+ name: "invalid scheduling algorithm",
+ pool: &NodePool{
+ Name: "valid",
+ SchedulerConfiguration: &NodePoolSchedulerConfiguration{
+ SchedulerAlgorithm: SchedulerAlgorithmBinpack,
+ },
+ },
+ expectedErr: "unlicensed",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ err := tc.pool.Validate()
+
+ if tc.expectedErr != "" {
+ must.ErrorContains(t, err, tc.expectedErr)
+ } else {
+ must.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/nomad/structs/node_pool_test.go b/nomad/structs/node_pool_test.go
index 54c2b1e1d..f261c49c6 100644
--- a/nomad/structs/node_pool_test.go
+++ b/nomad/structs/node_pool_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"github.com/hashicorp/nomad/ci"
+ "github.com/hashicorp/nomad/helper/pointer"
"github.com/shoenig/test/must"
)
@@ -19,7 +20,8 @@ func TestNodePool_Copy(t *testing.T) {
Description: "original node pool",
Meta: map[string]string{"original": "true"},
SchedulerConfiguration: &NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: SchedulerAlgorithmSpread,
+ SchedulerAlgorithm: SchedulerAlgorithmSpread,
+ MemoryOversubscriptionEnabled: pointer.Of(false),
},
}
poolCopy := pool.Copy()
@@ -28,6 +30,7 @@ func TestNodePool_Copy(t *testing.T) {
poolCopy.Meta["original"] = "false"
poolCopy.Meta["new_key"] = "true"
poolCopy.SchedulerConfiguration.SchedulerAlgorithm = SchedulerAlgorithmBinpack
+ poolCopy.SchedulerConfiguration.MemoryOversubscriptionEnabled = pointer.Of(true)
must.NotEq(t, pool, poolCopy)
must.NotEq(t, pool.Meta, poolCopy.Meta)
@@ -71,16 +74,6 @@ func TestNodePool_Validate(t *testing.T) {
},
expectedErr: "description longer",
},
- {
- name: "invalid scheduling algorithm",
- pool: &NodePool{
- Name: "valid",
- SchedulerConfiguration: &NodePoolSchedulerConfiguration{
- SchedulerAlgorithm: "invalid",
- },
- },
- expectedErr: "invalid scheduler algorithm",
- },
}
for _, tc := range testCases {
diff --git a/website/content/docs/commands/node-pool/apply.mdx b/website/content/docs/commands/node-pool/apply.mdx
index 7c462f7ff..c185e960a 100644
--- a/website/content/docs/commands/node-pool/apply.mdx
+++ b/website/content/docs/commands/node-pool/apply.mdx
@@ -45,7 +45,7 @@ node_pool "prod" {
}
# Available only in Nomad Enterprise.
- scheduler_configuration {
+ scheduler_config {
scheduler_algorithm = "spread"
}
}
diff --git a/website/content/docs/other-specifications/node-pool.mdx b/website/content/docs/other-specifications/node-pool.mdx
index 75833cbff..ebc4b78c2 100644
--- a/website/content/docs/other-specifications/node-pool.mdx
+++ b/website/content/docs/other-specifications/node-pool.mdx
@@ -37,7 +37,7 @@ node_pool "example" {
#
# Available only in Nomad Enterprise.
- # scheduler_configuration {
+ # scheduler_config {
# scheduler_algorithm = "spread"
# }
}
@@ -59,18 +59,21 @@ Successfully applied node pool "example"!
pool, defined as key-value pairs. The scheduler does not use node pool metadat
as part of scheduling.
-- `scheduler_configuration` ([SchedulerConfig][sched-config]:
- nil) - Sets scheduler configuration options specific to the node
- pool. If not defined, the global cluster scheduling algorithm is
- used. Available only in Nomad Enterprise.
+- `scheduler_config` ([SchedulerConfig][sched-config]: nil) -
+ Sets scheduler configuration options specific to the node pool. If not
+ defined, the global scheduler configurations are used.
-### Scheduler Configuration Parameters
+### `scheduler_config` Parameters
- `scheduler_algorithm` `(string: )` - The [scheduler algorithm][]
used for this node pool. Must be one of `binpack` or `spread`.
+- `memory_oversubscription_enabled` `(bool: )` - The [memory
+ oversubscription][] setting to use for this node pool.
+
[pool-apply]: /nomad/docs/commands/node-pool/apply
[jobspecs]: /nomad/docs/job-specification
[pool-init]: /nomad/docs/commands/node-pool/init
-[sched-config]: #scheduler-configuration-parameters
+[sched-config]: #scheduler_config-parameters
[scheduler algorithm]: /nomad/api-docs/operator/scheduler#scheduleralgorithm-1
+[memory oversubscription]: /nomad/api-docs/operator/scheduler#memoryoversubscriptionenabled-1