From e0cdee5cace0c18b6124c22e5a8ab68817b5eaac Mon Sep 17 00:00:00 2001 From: Jorge Marey Date: Tue, 13 Sep 2022 13:19:52 +0200 Subject: [PATCH 1/5] Add ns meta and capabilities --- nomad/data_source_namespace.go | 18 ++++ nomad/resource_namespace.go | 119 +++++++++++++++++++++++-- website/docs/d/namespace.html.markdown | 8 +- website/docs/r/namespace.html.markdown | 16 ++++ 4 files changed, 154 insertions(+), 7 deletions(-) diff --git a/nomad/data_source_namespace.go b/nomad/data_source_namespace.go index 65469f2a..47b4b9a0 100644 --- a/nomad/data_source_namespace.go +++ b/nomad/data_source_namespace.go @@ -23,6 +23,18 @@ func dataSourceNamespace() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "meta": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "capabilities": { + Type: schema.TypeSet, + Computed: true, + Elem: resourceNamespaceCapabilities(), + }, }, } } @@ -42,6 +54,12 @@ func namespaceDataSourceRead(d *schema.ResourceData, meta interface{}) error { if err = d.Set("quota", ns.Quota); err != nil { return fmt.Errorf("Failed to set 'quota': %v", err) } + if err = d.Set("meta", ns.Meta); err != nil { + return fmt.Errorf("Failed to set 'meta': %v", err) + } + if err = d.Set("capabilities", flattenNamespaceCapabilities(ns.Capabilities)); err != nil { + return fmt.Errorf("Failed to set 'capabilities': %v", err) + } d.SetId(client.Address() + "/namespace/" + name) return nil diff --git a/nomad/resource_namespace.go b/nomad/resource_namespace.go index 00b8c318..7bf09cf6 100644 --- a/nomad/resource_namespace.go +++ b/nomad/resource_namespace.go @@ -41,6 +41,41 @@ func resourceNamespace() *schema.Resource { Optional: true, Type: schema.TypeString, }, + + "meta": { + Description: "Metadata associated with the namespace.", + Optional: true, + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "capabilities": { + Description: "Capabilities of the namespace.", + Optional: true, + Type: schema.TypeSet, + Elem: resourceNamespaceCapabilities(), + }, + }, + } +} + +func resourceNamespaceCapabilities() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled_task_drivers": { + Description: "Enabled task drivers for the namespace.", + Optional: true, + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "disabled_task_drivers": { + Description: "Disabled task drivers for the namespace.", + Optional: true, + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + }, }, } } @@ -48,15 +83,26 @@ func resourceNamespace() *schema.Resource { func resourceNamespaceWrite(d *schema.ResourceData, meta interface{}) error { client := meta.(ProviderConfig).client + m := make(map[string]string) + for name, value := range d.Get("meta").(map[string]interface{}) { + m[name] = value.(string) + } + + capabilities, err := expandNamespaceCapabilities(d) + if err != nil { + return err + } + namespace := api.Namespace{ - Name: d.Get("name").(string), - Description: d.Get("description").(string), - Quota: d.Get("quota").(string), + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Quota: d.Get("quota").(string), + Meta: m, + Capabilities: capabilities, } log.Printf("[DEBUG] Upserting namespace %q", namespace.Name) - _, err := client.Namespaces().Register(&namespace, nil) - if err != nil { + if _, err := client.Namespaces().Register(&namespace, nil); err != nil { return fmt.Errorf("error inserting namespace %q: %s", namespace.Name, err.Error()) } log.Printf("[DEBUG] Created namespace %q", namespace.Name) @@ -121,6 +167,8 @@ func resourceNamespaceRead(d *schema.ResourceData, meta interface{}) error { d.Set("name", namespace.Name) d.Set("description", namespace.Description) d.Set("quota", namespace.Quota) + d.Set("meta", namespace.Meta) + d.Set("capabilities", flattenNamespaceCapabilities(namespace.Capabilities)) return nil } @@ -150,3 +198,64 @@ func resourceNamespaceExists(d *schema.ResourceData, meta interface{}) (bool, er return true, nil } + +func flattenNamespaceCapabilities(capabilities *api.NamespaceCapabilities) *schema.Set { + if capabilities == nil { + return nil + } + rawCapabilities := map[string]interface{}{} + if capabilities.EnabledTaskDrivers != nil { + enabledI := make([]interface{}, len(capabilities.EnabledTaskDrivers)) + for i, v := range capabilities.EnabledTaskDrivers { + enabledI[i] = v + } + rawCapabilities["enabled_task_drivers"] = enabledI + } + if capabilities.DisabledTaskDrivers != nil { + disabledI := make([]interface{}, len(capabilities.DisabledTaskDrivers)) + for i, v := range capabilities.DisabledTaskDrivers { + disabledI[i] = v + } + rawCapabilities["disabled_task_drivers"] = disabledI + } + + result := []interface{}{rawCapabilities} + return schema.NewSet(schema.HashResource(resourceNamespaceCapabilities()), result) +} + +func expandNamespaceCapabilities(d *schema.ResourceData) (*api.NamespaceCapabilities, error) { + capabilitiesI := d.Get("capabilities").(*schema.Set).List() + if len(capabilitiesI) < 1 { + return nil, nil + } + capabilities, ok := capabilitiesI[0].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("expected map[string]interface{} for region capabilities, got %T", capabilitiesI[0]) + } + var res api.NamespaceCapabilities + if enaI, ok := capabilities["enabled_task_drivers"]; ok { + enaS, ok := enaI.([]interface{}) + if !ok { + return nil, fmt.Errorf("expected enabled_task_drivers to be []string, got %T", enaS) + } + res.EnabledTaskDrivers = make([]string, len(enaS)) + for index, value := range enaS { + if val, ok := value.(string); ok { + res.EnabledTaskDrivers[index] = val + } + } + } + if disI, ok := capabilities["disabled_task_drivers"]; ok { + disS, ok := disI.([]interface{}) + if !ok { + return nil, fmt.Errorf("expected disabled_task_drivers to be []string, got %T", disS) + } + res.DisabledTaskDrivers = make([]string, len(disS)) + for index, value := range disS { + if val, ok := value.(string); ok { + res.DisabledTaskDrivers[index] = val + } + } + } + return &res, nil +} diff --git a/website/docs/d/namespace.html.markdown b/website/docs/d/namespace.html.markdown index f3e2a533..bf1f313d 100644 --- a/website/docs/d/namespace.html.markdown +++ b/website/docs/d/namespace.html.markdown @@ -26,5 +26,9 @@ data "nomad_namespace" "namespaces" { The following attributes are exported: -- `description` `(string)` - The description of the namespace. -- `quota` `(string)` - The quota associated with the namespace. +* `description` `(string)` - The description of the namespace. +* `quota` `(string)` - The quota associated with the namespace. +* `meta` `(map[string]string)` - Arbitrary KV metadata associated with the namespace. +* `capabilities` `(block)` - Capabilities of the namespace + * `enabled_task_drivers` `([]string)` - Task drivers enabled for the namespace. + * `disabled_task_drivers` `([]string)` - Task drivers disabled for the namespace. diff --git a/website/docs/r/namespace.html.markdown b/website/docs/r/namespace.html.markdown index 7aa3980b..90310d0a 100644 --- a/website/docs/r/namespace.html.markdown +++ b/website/docs/r/namespace.html.markdown @@ -24,6 +24,10 @@ resource "nomad_namespace" "dev" { name = "dev" description = "Shared development environment." quota = "dev" + meta = { + owner = "John Doe" + foo = "bar" + } } ``` @@ -58,3 +62,15 @@ The following arguments are supported: - `name` `(string: )` - A unique name for the namespace. - `description` `(string: "")` - A description of the namespace. - `quota` `(string: "")` - A resource quota to attach to the namespace. +- `meta` `(map[string]string: )` - Specifies arbitrary KV metadata to associate with the namespace. +- `capabilities` `(block: )` - A block of capabilities for the namespace. Can't + be repeated. See below for the structure of this block. + + +### `capabilities` blocks + +The `capabilities` block describes the capabilities of the namespace. It supports +the following arguments: + +- `enabled_task_drivers` `([]string: )` - Task drivers enabled for the namespace. +- `disabled_task_drivers` `([]string: )` - Task drivers disabled for the namespace. \ No newline at end of file From 0e1bd4ad8e474dad6c05356530ff0b2f480182a1 Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Mon, 19 Sep 2022 18:58:44 -0400 Subject: [PATCH 2/5] set max items to 1 on namespace capabilities --- nomad/resource_namespace.go | 1 + 1 file changed, 1 insertion(+) diff --git a/nomad/resource_namespace.go b/nomad/resource_namespace.go index 7bf09cf6..f90fa464 100644 --- a/nomad/resource_namespace.go +++ b/nomad/resource_namespace.go @@ -56,6 +56,7 @@ func resourceNamespace() *schema.Resource { Optional: true, Type: schema.TypeSet, Elem: resourceNamespaceCapabilities(), + MaxItems: 1, }, }, } From 65cfda3d8ba51ca09f2ca2a12c6c06d187468d51 Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Mon, 19 Sep 2022 19:04:21 -0400 Subject: [PATCH 3/5] add tests for namespace meta and capability --- nomad/data_source_namespace_test.go | 49 +++++++++++++++++++++++++++-- nomad/resource_namespace_test.go | 25 +++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/nomad/data_source_namespace_test.go b/nomad/data_source_namespace_test.go index d784fd35..ed4fda1c 100644 --- a/nomad/data_source_namespace_test.go +++ b/nomad/data_source_namespace_test.go @@ -1,21 +1,25 @@ package nomad import ( + "fmt" "regexp" "testing" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func TestDataSourceNamespace(t *testing.T) { resourceName := "data.nomad_namespace.test" + name := acctest.RandomWithPrefix("tf-nomad-test") resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testAccPreCheck(t); testCheckEnt(t) }, Steps: []resource.TestStep{ { - Config: testDataSourceNamespaceConfig, + Config: testDataSourceDefaultNamespaceConfig, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", "default"), resource.TestCheckResourceAttr(resourceName, "description", "Default shared namespace"), @@ -26,11 +30,30 @@ func TestDataSourceNamespace(t *testing.T) { Config: testDataSourceNamespaceConfig_doesNotExists, ExpectError: regexp.MustCompile("Namespace not found"), }, + { + Config: testDataSourceNamespace_basicConfig(name), + Check: resource.ComposeTestCheckFunc( + func() resource.TestCheckFunc { + return func(s *terraform.State) error { + t.Log(s) + return nil + } + }(), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "description", "A Terraform acctest namespace"), + resource.TestCheckResourceAttr(resourceName, "quota", ""), + resource.TestCheckResourceAttr(resourceName, "meta.key", "value"), + resource.TestCheckResourceAttr(resourceName, "capabilities.#", "1"), + resource.TestCheckResourceAttr(resourceName, "capabilities.795649181.disabled_task_drivers.0", "raw_exec"), + resource.TestCheckResourceAttr(resourceName, "capabilities.795649181.enabled_task_drivers.0", "docker"), + resource.TestCheckResourceAttr(resourceName, "capabilities.795649181.enabled_task_drivers.1", "exec"), + ), + }, }, }) } -const testDataSourceNamespaceConfig = ` +const testDataSourceDefaultNamespaceConfig = ` data "nomad_namespace" "test" { name = "default" } @@ -41,3 +64,25 @@ data "nomad_namespace" "test" { name = "does-not-exists" } ` + +func testDataSourceNamespace_basicConfig(name string) string { + return fmt.Sprintf(` +resource "nomad_namespace" "test" { + name = "%s" + description = "A Terraform acctest namespace" + + meta = { + key = "value", + } + + capabilities { + enabled_task_drivers = ["docker", "exec"] + disabled_task_drivers = ["raw_exec"] + } +} + +data "nomad_namespace" "test" { + name = nomad_namespace.test.name +} +`, name) +} diff --git a/nomad/resource_namespace_test.go b/nomad/resource_namespace_test.go index a9e214bc..cd8d7db7 100644 --- a/nomad/resource_namespace_test.go +++ b/nomad/resource_namespace_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/nomad/api" "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -130,6 +131,15 @@ func testResourceNamespace_initialConfig(name string) string { resource "nomad_namespace" "test" { name = "%s" description = "A Terraform acctest namespace" + + meta = { + key = "value", + } + + capabilities { + enabled_task_drivers = ["docker", "exec"] + disabled_task_drivers = ["raw_exec"] + } } `, name) } @@ -174,6 +184,21 @@ func testResourceNamespace_initialCheck(name string) resource.TestCheckFunc { return fmt.Errorf("expected description to be %q, is %q in API", description, namespace.Description) } + expectedMeta := map[string]string{ + "key": "value", + } + if diff := cmp.Diff(namespace.Meta, expectedMeta); diff != "" { + return fmt.Errorf("namespace meta mismatch (-want +got):\n%s", diff) + } + + expectedCapabilities := &api.NamespaceCapabilities{ + EnabledTaskDrivers: []string{"docker", "exec"}, + DisabledTaskDrivers: []string{"raw_exec"}, + } + if diff := cmp.Diff(namespace.Capabilities, expectedCapabilities); diff != "" { + return fmt.Errorf("namespace capabilities mismatch (-want +got):\n%s", diff) + } + return nil } } From e18a2443fcc59df50ad2712dcd2ebaaa13b104e8 Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Mon, 19 Sep 2022 19:07:55 -0400 Subject: [PATCH 4/5] changelog: add entry for #287 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87a48ecf..d2d42427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -## 1.4.18 (Unreleased) +## 1.4.19 (Unreleased) + +IMPROVEMENTS: +* resources/nomad_namespace: add support for `meta` and `capabilities` ([#287](https://github.com/hashicorp/terraform-provider-nomad/pull/287)) +* data source/nomad_namespace: add support for `meta` and `capabilities` ([#287](https://github.com/hashicorp/terraform-provider-nomad/pull/287)) + +## 1.4.18 (August 31, 2022) * **Target Nomad 1.3.4**: updated the nomad client to support Nomad API and jobspec version 1.3.4 ([#282](https://github.com/hashicorp/terraform-provider-nomad/pull/282)) From 6c415a9612780d0a28a066d0105030890dfe65d6 Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Mon, 19 Sep 2022 19:13:40 -0400 Subject: [PATCH 5/5] remove test debug --- nomad/data_source_namespace_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nomad/data_source_namespace_test.go b/nomad/data_source_namespace_test.go index ed4fda1c..8bd2872b 100644 --- a/nomad/data_source_namespace_test.go +++ b/nomad/data_source_namespace_test.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func TestDataSourceNamespace(t *testing.T) { @@ -33,12 +32,6 @@ func TestDataSourceNamespace(t *testing.T) { { Config: testDataSourceNamespace_basicConfig(name), Check: resource.ComposeTestCheckFunc( - func() resource.TestCheckFunc { - return func(s *terraform.State) error { - t.Log(s) - return nil - } - }(), resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "description", "A Terraform acctest namespace"), resource.TestCheckResourceAttr(resourceName, "quota", ""),