Skip to content

Commit

Permalink
namespace: add node pool configuration (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
lgfa29 committed Jul 28, 2023
1 parent 2c03214 commit 63e446b
Show file tree
Hide file tree
Showing 9 changed files with 359 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ IMPROVEMENTS:
* **Target Nomad 1.6.0*: updated the nomad client to support Nomad API and jobspec version 1.6.0 ([#345](https://github.com/hashicorp/terraform-provider-nomad/pull/345))
* provider: add `skip_verify` configuration to skip TLS verification ([#319](https://github.com/hashicorp/terraform-provider-nomad/pull/319))
* provider: update Go to 1.20.5 ([#334](https://github.com/hashicorp/terraform-provider-nomad/pull/334))
* data source/nomad_namespace: add `node_pool_config` attribute ([#355](https://github.com/hashicorp/terraform-provider-nomad/pull/355))
* resource/nomad_acl_policy: add support for `job_acl` ([#314](https://github.com/hashicorp/terraform-provider-nomad/pull/314))
* resource/nomad_csi_volume and resource/nomad_csi_volume_registration: add support to import existing volumes. ([#359](https://github.com/hashicorp/terraform-provider-nomad/pull/359)]
* resource/nomad_job: add support to import existing jobs. ([#359](https://github.com/hashicorp/terraform-provider-nomad/pull/359)]
* resource/nomad_namespace: add `node_pool_config` attribute ([#355](https://github.com/hashicorp/terraform-provider-nomad/pull/355))
* resource/nomad_volume and resource/nomad_external_volume: add timeouts for volume creation, registration, deregistration, and deletion ([#346](https://github.com/hashicorp/terraform-provider-nomad/pull/346))

BUG FIXES:
Expand Down
29 changes: 29 additions & 0 deletions nomad/data_source_namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,32 @@ func dataSourceNamespace() *schema.Resource {
Computed: true,
Elem: resourceNamespaceCapabilities(),
},
"node_pool_config": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"default": {
Computed: true,
Type: schema.TypeString,
},
"allowed": {
Computed: true,
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"denied": {
Computed: true,
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
},
}
}
Expand All @@ -63,6 +89,9 @@ func namespaceDataSourceRead(d *schema.ResourceData, meta interface{}) error {
if err = d.Set("capabilities", flattenNamespaceCapabilities(ns.Capabilities)); err != nil {
return fmt.Errorf("Failed to set 'capabilities': %v", err)
}
if err = d.Set("node_pool_config", flattenNamespaceNodePoolConfig(ns.NodePoolConfiguration)); err != nil {
return fmt.Errorf("Failed to set 'node_pool_config': %v", err)
}

d.SetId(client.Address() + "/namespace/" + name)
return nil
Expand Down
64 changes: 63 additions & 1 deletion nomad/data_source_namespace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestDataSourceNamespace(t *testing.T) {

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t); testCheckEnt(t) },
PreCheck: func() { testAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceDefaultNamespaceConfig,
Expand Down Expand Up @@ -49,6 +49,68 @@ func TestDataSourceNamespace(t *testing.T) {
})
}

func TestDataSourceNamespace_nodePoolConfig(t *testing.T) {
name := acctest.RandomWithPrefix("tf-nomad-test")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t); testCheckMinVersion(t, "1.6.0"); testCheckEnt(t) },
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "nomad_namespace" "test" {
name = "%s"
node_pool_config {
default = "dev"
allowed = ["prod", "qa"]
}
}
data "nomad_namespace" "test" {
name = nomad_namespace.test.name
}
`, name),

Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.nomad_namespace.test", "name", name),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.#", "1"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.default", "dev"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.allowed.#", "2"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.allowed.0", "prod"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.allowed.1", "qa"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.denied.#", "0"),
),
},
{
Config: fmt.Sprintf(`
resource "nomad_namespace" "test" {
name = "%s"
node_pool_config {
default = "dev"
denied = ["prod", "qa"]
}
}
data "nomad_namespace" "test" {
name = nomad_namespace.test.name
}
`, name),

Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.nomad_namespace.test", "name", name),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.#", "1"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.default", "dev"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.denied.#", "2"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.denied.0", "prod"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.denied.1", "qa"),
resource.TestCheckResourceAttr("data.nomad_namespace.test", "node_pool_config.0.allowed.#", "0"),
),
},
},
})
}

const testDataSourceDefaultNamespaceConfig = `
data "nomad_namespace" "test" {
name = "default"
Expand Down
4 changes: 2 additions & 2 deletions nomad/data_source_node_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestDataSourceNodePool(t *testing.T) {
name := acctest.RandomWithPrefix("tf-nomad-test")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t); testCheckMinVersion(t, "1.6.0-beta.1") },
PreCheck: func() { testAccPreCheck(t); testCheckMinVersion(t, "1.6.0") },
Steps: []resource.TestStep{
{
Config: testDataSourceNodePoolConfig_builtIn,
Expand Down Expand Up @@ -48,7 +48,7 @@ func TestDataSourceNodePool_schedConfig(t *testing.T) {
name := acctest.RandomWithPrefix("tf-nomad-test")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t); testCheckMinVersion(t, "1.6.0-beta.1"); testCheckEnt(t) },
PreCheck: func() { testAccPreCheck(t); testCheckMinVersion(t, "1.6.0"); testCheckEnt(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceNodePoolConfig_schedConfig(name),
Expand Down
137 changes: 132 additions & 5 deletions nomad/resource_namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ func resourceNamespace() *schema.Resource {
Elem: resourceNamespaceCapabilities(),
MaxItems: 1,
},
"node_pool_config": {
Description: "Node pool configuration",
Optional: true,
Type: schema.TypeList,
Elem: resourceNamespaceNodePoolConfig(),
MaxItems: 1,

// Set as computed because in Nomad Enterprise the default node
// pool is set to `default` if not set.
Computed: true,
},
},
}
}
Expand All @@ -84,6 +95,37 @@ func resourceNamespaceCapabilities() *schema.Resource {
}
}

func resourceNamespaceNodePoolConfig() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"default": {
Description: "The node pool to use when none are specified in the job.",
Optional: true,
Computed: true,
Type: schema.TypeString,
},
"allowed": {
Description: "The list of node pools allowed to be used in this namespace. Cannot be used with denied.",
Optional: true,
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
ConflictsWith: []string{"node_pool_config.0.denied"},
},
"denied": {
Description: "The list of node pools not allowed to be used in this namespace. Cannot be used with allowed.",
Optional: true,
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
},
ConflictsWith: []string{"node_pool_config.0.allowed"},
},
},
}
}

func resourceNamespaceWrite(d *schema.ResourceData, meta interface{}) error {
client := meta.(ProviderConfig).client

Expand All @@ -97,12 +139,18 @@ func resourceNamespaceWrite(d *schema.ResourceData, meta interface{}) error {
return err
}

npConfig, err := expandNamespaceNodePoolConfig(d)
if err != nil {
return err
}

namespace := api.Namespace{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Quota: d.Get("quota").(string),
Meta: m,
Capabilities: capabilities,
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Quota: d.Get("quota").(string),
Meta: m,
Capabilities: capabilities,
NodePoolConfiguration: npConfig,
}

log.Printf("[DEBUG] Upserting namespace %q", namespace.Name)
Expand Down Expand Up @@ -173,6 +221,7 @@ func resourceNamespaceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("quota", namespace.Quota)
d.Set("meta", namespace.Meta)
d.Set("capabilities", flattenNamespaceCapabilities(namespace.Capabilities))
d.Set("node_pool_config", flattenNamespaceNodePoolConfig(namespace.NodePoolConfiguration))

return nil
}
Expand Down Expand Up @@ -262,3 +311,81 @@ func expandNamespaceCapabilities(d *schema.ResourceData) (*api.NamespaceCapabili
}
return &res, nil
}

func expandNamespaceNodePoolConfig(d *schema.ResourceData) (*api.NamespaceNodePoolConfiguration, error) {
npConfigI := d.Get("node_pool_config").([]any)
if len(npConfigI) < 1 {
return nil, nil
}

npConfig, ok := npConfigI[0].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("expected map[string]interface{} for namespace node pool configuration, got %T", npConfigI[0])
}

var res api.NamespaceNodePoolConfiguration

if defaultI, ok := npConfig["default"]; ok {
defaultStr, ok := defaultI.(string)
if !ok {
return nil, fmt.Errorf("expected default to be a string, got %T", defaultI)
}
res.Default = defaultStr

}

if allowedI, ok := npConfig["allowed"]; ok {
allowedSet, ok := allowedI.(*schema.Set)
if !ok {
return nil, fmt.Errorf("expected allowed to be a *schema.Set, got %T", allowedI)
}
if allowedSet.Len() > 0 {
res.Allowed = make([]string, allowedSet.Len())
for i, v := range allowedSet.List() {
res.Allowed[i] = v.(string)
}
}
}

if deniedI, ok := npConfig["denied"]; ok {
deniedSet, ok := deniedI.(*schema.Set)
if !ok {
return nil, fmt.Errorf("expected denied to be a *schema.Set, got %T", deniedI)
}
if deniedSet.Len() > 0 {
res.Denied = make([]string, deniedSet.Len())
for i, v := range deniedSet.List() {
res.Denied[i] = v.(string)
}
}
}

return &res, nil
}
func flattenNamespaceNodePoolConfig(npConfig *api.NamespaceNodePoolConfiguration) []any {
if npConfig == nil {
return nil
}

rawNpConfig := map[string]any{
"default": npConfig.Default,
}

if npConfig.Allowed != nil {
allowed := make([]any, len(npConfig.Allowed))
for i, v := range npConfig.Allowed {
allowed[i] = v
}
rawNpConfig["allowed"] = allowed
}

if npConfig.Denied != nil {
denied := make([]any, len(npConfig.Denied))
for i, v := range npConfig.Denied {
denied[i] = v
}
rawNpConfig["denied"] = denied
}

return []any{rawNpConfig}
}
Loading

0 comments on commit 63e446b

Please sign in to comment.