From 53d576b6078bad013008bc4cf25bc37a7ce66df9 Mon Sep 17 00:00:00 2001 From: Neil Garratt Date: Mon, 25 Apr 2022 18:19:08 -0400 Subject: [PATCH 1/7] Add infoblox_zone_delegated resource --- docs/index.md | 1 + docs/resources/infoblox_zone_delegated.md | 39 +++ .../v0.14/Resources/ZoneDelegated/infoblox.tf | 17 ++ .../v0.14/Resources/ZoneDelegated/versions.tf | 8 + infoblox/provider.go | 1 + infoblox/resource_infoblox_zone_delegated.go | 229 ++++++++++++++++++ .../resource_infoblox_zone_delegated_test.go | 92 +++++++ 7 files changed, 387 insertions(+) create mode 100644 docs/resources/infoblox_zone_delegated.md create mode 100644 examples/v0.14/Resources/ZoneDelegated/infoblox.tf create mode 100644 examples/v0.14/Resources/ZoneDelegated/versions.tf create mode 100644 infoblox/resource_infoblox_zone_delegated.go create mode 100644 infoblox/resource_infoblox_zone_delegated_test.go diff --git a/docs/index.md b/docs/index.md index d889cdd7e..0422cf30a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,7 @@ There are resources for the following objects, supported by the plugin: - PTR-record - CNAME-record - Host record +- Zone delegated Network container and network resources have two versions: IPv4 and IPv6. In addition, there are two operations which are implemented as resources: diff --git a/docs/resources/infoblox_zone_delegated.md b/docs/resources/infoblox_zone_delegated.md new file mode 100644 index 000000000..718c15e6d --- /dev/null +++ b/docs/resources/infoblox_zone_delegated.md @@ -0,0 +1,39 @@ +# Resource Zone Delegated + +A Zone Delegated resource creates NS records for a subdomain, pointing to one or more external authoritative name servers. The `infoblox_zone_delegated` resource allow managing such delegations. The parent zone must already exist + +The following list describes the parameters you can define in the `infoblox_zone_delegated` resource block: + +## Argument Reference +* `fqdn`: (Required) The subdomain name to be delegated +* `delegate_to`: (Required) Nested block(s)s for the delegated name servers + * `address`: (Required) The IP address of the name server + * `name`: (Required) The FQDN of the name server +* `ext_attrs`: (Optional) A set of NIOS extensible attributes that are attached to the record, using jsonencode. Currently only "Tenant ID" is supported + +## Example Usage + +```hcl +resource "infoblox_zone_delegated" "subdomain" { + + fqdn = "subdomain.test.com" + + delegate_to { + address = "205.251.197.208" + name = "ns-1488.awsdns-58.org" + } + + delegate_to { + address = "205.251.199.242" + name = "ns-2034.awsdns-62.co.uk" + } + +} +``` + +## Import +Zone Delegated resources can be imported by using either the object reference or the subdomain fqdn, for example: +```shell script +# terraform import infoblox_zone_delegated.subdomain zone_delegated/ZG5zLnpvbmUkLl9kZWZhdWx0LmNvbS5jb2xsZWdlY2hvaWNldHJhbnNpdGlvbi5nc2xi:subdomain.test.com/default +# terraform import infoblox_zone_delegated.subdomain subdomain.test.com +``` diff --git a/examples/v0.14/Resources/ZoneDelegated/infoblox.tf b/examples/v0.14/Resources/ZoneDelegated/infoblox.tf new file mode 100644 index 000000000..2137549e2 --- /dev/null +++ b/examples/v0.14/Resources/ZoneDelegated/infoblox.tf @@ -0,0 +1,17 @@ +# Zone Delegated + +resource "infoblox_zone_delegated" "subdomain" { + + fqdn = "subdomain.example.com" + + delegate_to { + address = "205.251.197.208" + name = "ns-1488.awsdns-58.org" + } + + delegate_to { + address = "205.251.199.242" + name = "ns-2034.awsdns-62.co.uk" + } + +} diff --git a/examples/v0.14/Resources/ZoneDelegated/versions.tf b/examples/v0.14/Resources/ZoneDelegated/versions.tf new file mode 100644 index 000000000..0ac2a2b98 --- /dev/null +++ b/examples/v0.14/Resources/ZoneDelegated/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + infoblox = { + source = "infobloxopen/infoblox" + version = ">= 2.1" + } + } +} diff --git a/infoblox/provider.go b/infoblox/provider.go index 82de9f62b..419d0c111 100644 --- a/infoblox/provider.go +++ b/infoblox/provider.go @@ -123,6 +123,7 @@ func Provider() *schema.Provider { "infoblox_aaaa_record": resourceAAAARecord(), "infoblox_cname_record": resourceCNAMERecord(), "infoblox_ptr_record": resourcePTRRecord(), + "infoblox_zone_delegated": resourceZoneDelegated(), }, DataSourcesMap: map[string]*schema.Resource{ "infoblox_ipv4_network": dataSourceIPv4Network(), diff --git a/infoblox/resource_infoblox_zone_delegated.go b/infoblox/resource_infoblox_zone_delegated.go new file mode 100644 index 000000000..31d8c17d1 --- /dev/null +++ b/infoblox/resource_infoblox_zone_delegated.go @@ -0,0 +1,229 @@ +package infoblox + +import ( + "encoding/json" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + ibclient "github.com/infobloxopen/infoblox-go-client/v2" +) + +func resourceZoneDelegated() *schema.Resource { + return &schema.Resource{ + Create: resourceZoneDelegatedCreate, + Read: resourceZoneDelegatedRead, + Update: resourceZoneDelegatedUpdate, + Delete: resourceZoneDelegatedDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "fqdn": { + Type: schema.TypeString, + Required: true, + Description: "The FQDN of the delegated zone.", + }, + "delegate_to": resourceNameServer(), + "ext_attrs": { + Type: schema.TypeString, + Default: "", + Optional: true, + Description: "Extensible attributes, as a map in JSON format", + }, + }, + } +} + +func resourceNameServer() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Required: true, + Description: "IP of Name Server", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "FQDN of Name Server", + }, + }, + }, + } +} + +func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] %s: Beginning to create Zone Delegated", resourceZoneDelegatedIDString(d)) + + extAttrJSON := d.Get("ext_attrs").(string) + extAttrs := make(map[string]interface{}) + if extAttrJSON != "" { + if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { + return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + } + } + + delegatedFQDN := d.Get("fqdn").(string) + + var nameServers []ibclient.NameServer + delegations := d.Get("delegate_to").(*schema.Set).List() + for _, delegation := range delegations { + var ns ibclient.NameServer + var delegationMap = delegation.(map[string]interface{}) + ns.Address = delegationMap["address"].(string) + ns.Name = delegationMap["name"].(string) + nameServers = append(nameServers, ns) + } + + var tenantID string + if tempVal, ok := extAttrs["Tenant ID"]; ok { + tenantID = tempVal.(string) + } + + connector := m.(*ibclient.Connector) + + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + zoneDelegated, err := objMgr.CreateZoneDelegated( + delegatedFQDN, + nameServers) + if err != nil { + return fmt.Errorf("Error creating Zone Delegated: %s", err) + } + + d.SetId(zoneDelegated.Ref) + + log.Printf("[DEBUG] %s: Creation of Zone Delegated complete", resourceZoneDelegatedIDString(d)) + return nil +} + +func resourceZoneDelegatedRead(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] %s: Begining to Get Zone Delegated", resourceZoneDelegatedIDString(d)) + + extAttrJSON := d.Get("ext_attrs").(string) + extAttrs := make(map[string]interface{}) + if extAttrJSON != "" { + if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { + return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + } + } + + var tenantID string + if tempVal, ok := extAttrs["Tenant ID"]; ok { + tenantID = tempVal.(string) + } + + connector := m.(*ibclient.Connector) + + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + // first attempt to read by ref, otherwise assume import and support fqdn + zoneDelegatedObj, err := objMgr.GetZoneDelegatedByRef(d.Id()) + if err != nil { + zoneDelegatedObj, err = objMgr.GetZoneDelegated(d.Id()) + if err != nil { + return fmt.Errorf("Getting Zone Delegated failed: %s", err) + } + } + + var delegations []map[string]interface{} + for _, delegation := range zoneDelegatedObj.DelegateTo { + ns := make(map[string]interface{}) + ns["address"] = delegation.Address + ns["name"] = delegation.Name + delegations = append(delegations, ns) + } + + d.Set("fqdn", zoneDelegatedObj.Fqdn) + d.Set("delegate_to", delegations) + + d.SetId(zoneDelegatedObj.Ref) + + log.Printf("[DEBUG] %s: Completed reading Zone Delegated ", resourceZoneDelegatedIDString(d)) + return nil +} + +func resourceZoneDelegatedUpdate(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] %s: Beginning to update Zone Delegated", resourceZoneDelegatedIDString(d)) + + extAttrJSON := d.Get("ext_attrs").(string) + extAttrs := make(map[string]interface{}) + if extAttrJSON != "" { + if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { + return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + } + } + + var nameServers []ibclient.NameServer + delegations := d.Get("delegate_to").(*schema.Set).List() + for _, delegation := range delegations { + var ns ibclient.NameServer + var delegationMap = delegation.(map[string]interface{}) + ns.Address = delegationMap["address"].(string) + ns.Name = delegationMap["name"].(string) + nameServers = append(nameServers, ns) + } + + var tenantID string + if tempVal, ok := extAttrs["Tenant ID"]; ok { + tenantID = tempVal.(string) + } + + connector := m.(*ibclient.Connector) + + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + zoneDelegatedUpdated, err := objMgr.UpdateZoneDelegated(d.Id(), nameServers) + if err != nil { + return fmt.Errorf("Updating of Zone Delegated failed : %s", err.Error()) + } + + d.SetId(zoneDelegatedUpdated.Ref) + return nil +} + +func resourceZoneDelegatedDelete(d *schema.ResourceData, m interface{}) error { + log.Printf("[DEBUG] %s: Beginning Deletion of Zone Delegated", resourceZoneDelegatedIDString(d)) + + extAttrJSON := d.Get("ext_attrs").(string) + extAttrs := make(map[string]interface{}) + if extAttrJSON != "" { + if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { + return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + } + } + + var tenantID string + if tempVal, ok := extAttrs["Tenant ID"]; ok { + tenantID = tempVal.(string) + } + + connector := m.(*ibclient.Connector) + + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + _, err := objMgr.DeleteZoneDelegated(d.Id()) + if err != nil { + return fmt.Errorf("Deletion of Zone Delegated failed : %s", err) + } + d.SetId("") + + log.Printf("[DEBUG] %s: Deletion of Zone Delegated complete", resourceZoneDelegatedIDString(d)) + return nil +} + +type resourceZoneDelegatedIDStringInterface interface { + Id() string +} + +func resourceZoneDelegatedIDString(d resourceZoneDelegatedIDStringInterface) string { + id := d.Id() + if id == "" { + id = "" + } + return fmt.Sprintf("infoblox_zone_delegated (ID = %s)", id) +} diff --git a/infoblox/resource_infoblox_zone_delegated_test.go b/infoblox/resource_infoblox_zone_delegated_test.go new file mode 100644 index 000000000..faddc307f --- /dev/null +++ b/infoblox/resource_infoblox_zone_delegated_test.go @@ -0,0 +1,92 @@ +package infoblox + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + ibclient "github.com/infobloxopen/infoblox-go-client/v2" +) + +func testAccCheckZoneDelegatedDestroy(s *terraform.State) error { + meta := testAccProvider.Meta() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "infoblox_zone_delegated" { + return fmt.Errorf("Resource type %s is invalid after destroy", rs.Type) + } + connector := meta.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") + rec, _ := objMgr.GetZoneDelegatedByRef(rs.Primary.ID) + if rec != nil { + return fmt.Errorf("Zone Delegation record found after destroy") + } + } + return nil +} + +func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibclient.RecordNS) resource.TestCheckFunc { + return func(s *terraform.State) error { + res, found := s.RootModule().Resources[resPath] + if !found { + return fmt.Errorf("Not found: %s", resPath) + } + if res.Primary.ID == "" { + return fmt.Errorf("ID is not set") + } + meta := testAccProvider.Meta() + connector := meta.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") + + rec, _ := objMgr.GetZoneDelegatedByRef(res.Primary.ID) + if rec == nil { + return fmt.Errorf("record not found") + } + + if rec.Fqdn != expectedRec.Name { + return fmt.Errorf( + "'fqdn' does not match: got '%s', expected '%s'", + rec.Fqdn, expectedRec.Name) + } + if rec.DelegateTo[0].Address != expectedRec.Addresses[0].Address { + return fmt.Errorf( + "'delegate_to['address']' does not match: got '%s', expected '%s'", + rec.DelegateTo[0].Address, expectedRec.Addresses[0].Address) + } + if rec.DelegateTo[0].Name != expectedRec.Nameserver { + return fmt.Errorf( + "'delegate_to['name']' does not match: got '%s', expected '%s'", + rec.DelegateTo[0].Name, expectedRec.Nameserver) + } + return nil + } +} + +func TestAccResourceZoneDelegated(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckZoneDelegatedDestroy, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` + resource "infoblox_zone_delegated" "foo"{ + fqdn="subdomain.test.com" + delegate_to { + address = "1.2.3.4" + name = "dns.test.com" + } + }`), + Check: resource.ComposeTestCheckFunc( + testAccZoneDelegatedCompare(t, "infoblox_zone_delegated.foo", &ibclient.RecordNS{ + Name: "subdomain.test.com", + Addresses: []ibclient.ZoneNameServer{ibclient.ZoneNameServer{Address: "1.2.3.4"}}, + Nameserver: "dns.test.com", + }), + ), + }, + }, + }) +} From 2a83934a9752d47218147cffbe37b2e867a145ef Mon Sep 17 00:00:00 2001 From: Neil Garratt Date: Tue, 26 Apr 2022 11:34:26 -0400 Subject: [PATCH 2/7] change address in infoblox_zone_delegated to computed attribute, to simplfy integrations with other providers that only list NS FQDNs --- docs/resources/infoblox_zone_delegated.md | 7 +-- .../v0.14/Resources/ZoneDelegated/infoblox.tf | 2 - infoblox/resource_infoblox_zone_delegated.go | 51 +++++++++++++------ .../resource_infoblox_zone_delegated_test.go | 15 ++++-- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/docs/resources/infoblox_zone_delegated.md b/docs/resources/infoblox_zone_delegated.md index 718c15e6d..e48379665 100644 --- a/docs/resources/infoblox_zone_delegated.md +++ b/docs/resources/infoblox_zone_delegated.md @@ -7,10 +7,13 @@ The following list describes the parameters you can define in the `infoblox_zone ## Argument Reference * `fqdn`: (Required) The subdomain name to be delegated * `delegate_to`: (Required) Nested block(s)s for the delegated name servers - * `address`: (Required) The IP address of the name server * `name`: (Required) The FQDN of the name server * `ext_attrs`: (Optional) A set of NIOS extensible attributes that are attached to the record, using jsonencode. Currently only "Tenant ID" is supported +## Attribute Reference +* `delegate_to`: + * `address`: The computed IP address for each delegated name server + ## Example Usage ```hcl @@ -19,12 +22,10 @@ resource "infoblox_zone_delegated" "subdomain" { fqdn = "subdomain.test.com" delegate_to { - address = "205.251.197.208" name = "ns-1488.awsdns-58.org" } delegate_to { - address = "205.251.199.242" name = "ns-2034.awsdns-62.co.uk" } diff --git a/examples/v0.14/Resources/ZoneDelegated/infoblox.tf b/examples/v0.14/Resources/ZoneDelegated/infoblox.tf index 2137549e2..c2503d6e7 100644 --- a/examples/v0.14/Resources/ZoneDelegated/infoblox.tf +++ b/examples/v0.14/Resources/ZoneDelegated/infoblox.tf @@ -5,12 +5,10 @@ resource "infoblox_zone_delegated" "subdomain" { fqdn = "subdomain.example.com" delegate_to { - address = "205.251.197.208" name = "ns-1488.awsdns-58.org" } delegate_to { - address = "205.251.199.242" name = "ns-2034.awsdns-62.co.uk" } diff --git a/infoblox/resource_infoblox_zone_delegated.go b/infoblox/resource_infoblox_zone_delegated.go index 31d8c17d1..d532f5262 100644 --- a/infoblox/resource_infoblox_zone_delegated.go +++ b/infoblox/resource_infoblox_zone_delegated.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" "log" + "net" + "sort" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ibclient "github.com/infobloxopen/infoblox-go-client/v2" @@ -43,7 +45,7 @@ func resourceNameServer() *schema.Schema { Schema: map[string]*schema.Schema{ "address": { Type: schema.TypeString, - Required: true, + Computed: true, Description: "IP of Name Server", }, "name": { @@ -56,6 +58,27 @@ func resourceNameServer() *schema.Schema { } } +func computeDelegations(delegations []interface{}) ([]ibclient.NameServer, []map[string]interface{}, error) { + + var nameServers []ibclient.NameServer + computedDelegations := make([]map[string]interface{}, 0) + for _, delegation := range delegations { + var ns ibclient.NameServer + var delegationMap = delegation.(map[string]interface{}) + ns.Name = delegationMap["name"].(string) + lookupHosts, err := net.LookupHost(delegationMap["name"].(string)) + if err != nil { + return nil, nil, fmt.Errorf("Failed to resolve delegate_to: %s", err.Error()) + } + sort.Strings(lookupHosts) + ns.Address = lookupHosts[0] + delegationMap["address"] = ns.Address + nameServers = append(nameServers, ns) + computedDelegations = append(computedDelegations, delegationMap) + } + return nameServers, computedDelegations, nil +} + func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { log.Printf("[DEBUG] %s: Beginning to create Zone Delegated", resourceZoneDelegatedIDString(d)) @@ -69,14 +92,11 @@ func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { delegatedFQDN := d.Get("fqdn").(string) - var nameServers []ibclient.NameServer delegations := d.Get("delegate_to").(*schema.Set).List() - for _, delegation := range delegations { - var ns ibclient.NameServer - var delegationMap = delegation.(map[string]interface{}) - ns.Address = delegationMap["address"].(string) - ns.Name = delegationMap["name"].(string) - nameServers = append(nameServers, ns) + + nameServers, computedDelegations, err := computeDelegations(delegations) + if err != nil { + return err } var tenantID string @@ -95,6 +115,8 @@ func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { return fmt.Errorf("Error creating Zone Delegated: %s", err) } + d.Set("delegate_to", computedDelegations) + d.SetId(zoneDelegated.Ref) log.Printf("[DEBUG] %s: Creation of Zone Delegated complete", resourceZoneDelegatedIDString(d)) @@ -158,14 +180,11 @@ func resourceZoneDelegatedUpdate(d *schema.ResourceData, m interface{}) error { } } - var nameServers []ibclient.NameServer delegations := d.Get("delegate_to").(*schema.Set).List() - for _, delegation := range delegations { - var ns ibclient.NameServer - var delegationMap = delegation.(map[string]interface{}) - ns.Address = delegationMap["address"].(string) - ns.Name = delegationMap["name"].(string) - nameServers = append(nameServers, ns) + + nameServers, computedDelegations, err := computeDelegations(delegations) + if err != nil { + return err } var tenantID string @@ -182,6 +201,8 @@ func resourceZoneDelegatedUpdate(d *schema.ResourceData, m interface{}) error { return fmt.Errorf("Updating of Zone Delegated failed : %s", err.Error()) } + d.Set("delegate_to", computedDelegations) + d.SetId(zoneDelegatedUpdated.Ref) return nil } diff --git a/infoblox/resource_infoblox_zone_delegated_test.go b/infoblox/resource_infoblox_zone_delegated_test.go index faddc307f..89afecc4c 100644 --- a/infoblox/resource_infoblox_zone_delegated_test.go +++ b/infoblox/resource_infoblox_zone_delegated_test.go @@ -2,6 +2,8 @@ package infoblox import ( "fmt" + "net" + "sort" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -39,6 +41,13 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl connector := meta.(ibclient.IBConnector) objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") + lookupHosts, err := net.LookupHost(expectedRec.Nameserver) + if err != nil { + return fmt.Errorf("Failed to resolve delegate_to: %s", err.Error()) + } + sort.Strings(lookupHosts) + expectedRec.Addresses = append(expectedRec.Addresses, ibclient.ZoneNameServer{Address: lookupHosts[0]}) + rec, _ := objMgr.GetZoneDelegatedByRef(res.Primary.ID) if rec == nil { return fmt.Errorf("record not found") @@ -75,15 +84,13 @@ func TestAccResourceZoneDelegated(t *testing.T) { resource "infoblox_zone_delegated" "foo"{ fqdn="subdomain.test.com" delegate_to { - address = "1.2.3.4" - name = "dns.test.com" + name = "ns2.infoblox.com" } }`), Check: resource.ComposeTestCheckFunc( testAccZoneDelegatedCompare(t, "infoblox_zone_delegated.foo", &ibclient.RecordNS{ Name: "subdomain.test.com", - Addresses: []ibclient.ZoneNameServer{ibclient.ZoneNameServer{Address: "1.2.3.4"}}, - Nameserver: "dns.test.com", + Nameserver: "ns2.infoblox.com", }), ), }, From b2b43c3bbdfcee2a27e3797dad3b12fb35362ede Mon Sep 17 00:00:00 2001 From: Piper Dougherty Date: Wed, 15 May 2024 20:44:49 -0500 Subject: [PATCH 3/7] fix: removed deprecated function --- infoblox/resource_infoblox_zone_delegated.go | 10 +++------- infoblox/resource_infoblox_zone_delegated_test.go | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/infoblox/resource_infoblox_zone_delegated.go b/infoblox/resource_infoblox_zone_delegated.go index d532f5262..2591f1bd3 100644 --- a/infoblox/resource_infoblox_zone_delegated.go +++ b/infoblox/resource_infoblox_zone_delegated.go @@ -59,12 +59,11 @@ func resourceNameServer() *schema.Schema { } func computeDelegations(delegations []interface{}) ([]ibclient.NameServer, []map[string]interface{}, error) { - var nameServers []ibclient.NameServer computedDelegations := make([]map[string]interface{}, 0) for _, delegation := range delegations { var ns ibclient.NameServer - var delegationMap = delegation.(map[string]interface{}) + delegationMap := delegation.(map[string]interface{}) ns.Name = delegationMap["name"].(string) lookupHosts, err := net.LookupHost(delegationMap["name"].(string)) if err != nil { @@ -144,12 +143,9 @@ func resourceZoneDelegatedRead(d *schema.ResourceData, m interface{}) error { objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) // first attempt to read by ref, otherwise assume import and support fqdn - zoneDelegatedObj, err := objMgr.GetZoneDelegatedByRef(d.Id()) + zoneDelegatedObj, err := objMgr.GetZoneDelegated(d.Id()) if err != nil { - zoneDelegatedObj, err = objMgr.GetZoneDelegated(d.Id()) - if err != nil { - return fmt.Errorf("Getting Zone Delegated failed: %s", err) - } + return fmt.Errorf("Getting Zone Delegated failed: %s", err) } var delegations []map[string]interface{} diff --git a/infoblox/resource_infoblox_zone_delegated_test.go b/infoblox/resource_infoblox_zone_delegated_test.go index 89afecc4c..e205b83ca 100644 --- a/infoblox/resource_infoblox_zone_delegated_test.go +++ b/infoblox/resource_infoblox_zone_delegated_test.go @@ -20,7 +20,7 @@ func testAccCheckZoneDelegatedDestroy(s *terraform.State) error { } connector := meta.(ibclient.IBConnector) objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") - rec, _ := objMgr.GetZoneDelegatedByRef(rs.Primary.ID) + rec, _ := objMgr.GetZoneDelegated(rs.Primary.ID) if rec != nil { return fmt.Errorf("Zone Delegation record found after destroy") } @@ -48,7 +48,7 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl sort.Strings(lookupHosts) expectedRec.Addresses = append(expectedRec.Addresses, ibclient.ZoneNameServer{Address: lookupHosts[0]}) - rec, _ := objMgr.GetZoneDelegatedByRef(res.Primary.ID) + rec, _ := objMgr.GetZoneDelegated(res.Primary.ID) if rec == nil { return fmt.Errorf("record not found") } @@ -73,7 +73,6 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl } func TestAccResourceZoneDelegated(t *testing.T) { - resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, From f7e659571bc0b3be8b19aba8b32e176d7e1b19bc Mon Sep 17 00:00:00 2001 From: Piper Dougherty Date: Wed, 15 May 2024 20:59:15 -0500 Subject: [PATCH 4/7] fix: refactoring deprecated tests --- infoblox/resource_infoblox_zone_delegated_test.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/infoblox/resource_infoblox_zone_delegated_test.go b/infoblox/resource_infoblox_zone_delegated_test.go index e205b83ca..35176f5cc 100644 --- a/infoblox/resource_infoblox_zone_delegated_test.go +++ b/infoblox/resource_infoblox_zone_delegated_test.go @@ -41,12 +41,12 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl connector := meta.(ibclient.IBConnector) objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") - lookupHosts, err := net.LookupHost(expectedRec.Nameserver) + lookupHosts, err := net.LookupHost(*expectedRec.Nameserver) if err != nil { return fmt.Errorf("Failed to resolve delegate_to: %s", err.Error()) } sort.Strings(lookupHosts) - expectedRec.Addresses = append(expectedRec.Addresses, ibclient.ZoneNameServer{Address: lookupHosts[0]}) + expectedRec.Addresses = append(expectedRec.Addresses, &ibclient.ZoneNameServer{Address: lookupHosts[0]}) rec, _ := objMgr.GetZoneDelegated(res.Primary.ID) if rec == nil { @@ -63,15 +63,19 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl "'delegate_to['address']' does not match: got '%s', expected '%s'", rec.DelegateTo[0].Address, expectedRec.Addresses[0].Address) } - if rec.DelegateTo[0].Name != expectedRec.Nameserver { + if rec.DelegateTo[0].Name != *expectedRec.Nameserver { return fmt.Errorf( "'delegate_to['name']' does not match: got '%s', expected '%s'", - rec.DelegateTo[0].Name, expectedRec.Nameserver) + rec.DelegateTo[0].Name, *expectedRec.Nameserver) } return nil } } +func strPtr(s string) *string { + return &s +} + func TestAccResourceZoneDelegated(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -89,7 +93,7 @@ func TestAccResourceZoneDelegated(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccZoneDelegatedCompare(t, "infoblox_zone_delegated.foo", &ibclient.RecordNS{ Name: "subdomain.test.com", - Nameserver: "ns2.infoblox.com", + Nameserver: strPtr("ns2.infoblox.com"), }), ), }, From 87b3902a2e59fad7257eedf637895a0d25c3d86a Mon Sep 17 00:00:00 2001 From: Piper Dougherty Date: Wed, 15 May 2024 21:12:33 -0500 Subject: [PATCH 5/7] cleanup: #217 suggestions --- infoblox/resource_infoblox_zone_delegated.go | 37 ++++++++++++++------ 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/infoblox/resource_infoblox_zone_delegated.go b/infoblox/resource_infoblox_zone_delegated.go index 2591f1bd3..778c1ffb2 100644 --- a/infoblox/resource_infoblox_zone_delegated.go +++ b/infoblox/resource_infoblox_zone_delegated.go @@ -26,7 +26,24 @@ func resourceZoneDelegated() *schema.Resource { Required: true, Description: "The FQDN of the delegated zone.", }, - "delegate_to": resourceNameServer(), + "delegate_to": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + Description: "IP of Name Server", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "FQDN of Name Server", + }, + }, + }, + }, "ext_attrs": { Type: schema.TypeString, Default: "", @@ -67,7 +84,7 @@ func computeDelegations(delegations []interface{}) ([]ibclient.NameServer, []map ns.Name = delegationMap["name"].(string) lookupHosts, err := net.LookupHost(delegationMap["name"].(string)) if err != nil { - return nil, nil, fmt.Errorf("Failed to resolve delegate_to: %s", err.Error()) + return nil, nil, fmt.Errorf("Failed to resolve delegate_to: %w", err) } sort.Strings(lookupHosts) ns.Address = lookupHosts[0] @@ -85,7 +102,7 @@ func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { extAttrs := make(map[string]interface{}) if extAttrJSON != "" { if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { - return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + return fmt.Errorf("cannot process 'ext_attrs' field: %w", err) } } @@ -111,7 +128,7 @@ func resourceZoneDelegatedCreate(d *schema.ResourceData, m interface{}) error { delegatedFQDN, nameServers) if err != nil { - return fmt.Errorf("Error creating Zone Delegated: %s", err) + return fmt.Errorf("Error creating Zone Delegated: %w", err) } d.Set("delegate_to", computedDelegations) @@ -129,7 +146,7 @@ func resourceZoneDelegatedRead(d *schema.ResourceData, m interface{}) error { extAttrs := make(map[string]interface{}) if extAttrJSON != "" { if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { - return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + return fmt.Errorf("cannot process 'ext_attrs' field: %w", err) } } @@ -145,7 +162,7 @@ func resourceZoneDelegatedRead(d *schema.ResourceData, m interface{}) error { // first attempt to read by ref, otherwise assume import and support fqdn zoneDelegatedObj, err := objMgr.GetZoneDelegated(d.Id()) if err != nil { - return fmt.Errorf("Getting Zone Delegated failed: %s", err) + return fmt.Errorf("Getting Zone Delegated failed: %w", err) } var delegations []map[string]interface{} @@ -172,7 +189,7 @@ func resourceZoneDelegatedUpdate(d *schema.ResourceData, m interface{}) error { extAttrs := make(map[string]interface{}) if extAttrJSON != "" { if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { - return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + return fmt.Errorf("cannot process 'ext_attrs' field: %w", err) } } @@ -194,7 +211,7 @@ func resourceZoneDelegatedUpdate(d *schema.ResourceData, m interface{}) error { zoneDelegatedUpdated, err := objMgr.UpdateZoneDelegated(d.Id(), nameServers) if err != nil { - return fmt.Errorf("Updating of Zone Delegated failed : %s", err.Error()) + return fmt.Errorf("Updating of Zone Delegated failed : %w", err) } d.Set("delegate_to", computedDelegations) @@ -210,7 +227,7 @@ func resourceZoneDelegatedDelete(d *schema.ResourceData, m interface{}) error { extAttrs := make(map[string]interface{}) if extAttrJSON != "" { if err := json.Unmarshal([]byte(extAttrJSON), &extAttrs); err != nil { - return fmt.Errorf("cannot process 'ext_attrs' field: %s", err.Error()) + return fmt.Errorf("cannot process 'ext_attrs' field: %w", err) } } @@ -225,7 +242,7 @@ func resourceZoneDelegatedDelete(d *schema.ResourceData, m interface{}) error { _, err := objMgr.DeleteZoneDelegated(d.Id()) if err != nil { - return fmt.Errorf("Deletion of Zone Delegated failed : %s", err) + return fmt.Errorf("Deletion of Zone Delegated failed : %w", err) } d.SetId("") From fac3a8fba8de3e66a7255deae48a90a0c452a6c7 Mon Sep 17 00:00:00 2001 From: Piper Dougherty Date: Wed, 15 May 2024 21:36:30 -0500 Subject: [PATCH 6/7] fix: add back GetZoneDelegatedByRef --- infoblox/resource_infoblox_zone_delegated.go | 7 +++++-- infoblox/resource_infoblox_zone_delegated_test.go | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/infoblox/resource_infoblox_zone_delegated.go b/infoblox/resource_infoblox_zone_delegated.go index 778c1ffb2..ef34d2d88 100644 --- a/infoblox/resource_infoblox_zone_delegated.go +++ b/infoblox/resource_infoblox_zone_delegated.go @@ -160,9 +160,12 @@ func resourceZoneDelegatedRead(d *schema.ResourceData, m interface{}) error { objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) // first attempt to read by ref, otherwise assume import and support fqdn - zoneDelegatedObj, err := objMgr.GetZoneDelegated(d.Id()) + zoneDelegatedObj, err := objMgr.GetZoneDelegatedByRef(d.Id()) if err != nil { - return fmt.Errorf("Getting Zone Delegated failed: %w", err) + zoneDelegatedObj, err = objMgr.GetZoneDelegated(d.Id()) + if err != nil { + return fmt.Errorf("Getting Zone Delegated failed: %s", err) + } } var delegations []map[string]interface{} diff --git a/infoblox/resource_infoblox_zone_delegated_test.go b/infoblox/resource_infoblox_zone_delegated_test.go index 35176f5cc..3be553eb5 100644 --- a/infoblox/resource_infoblox_zone_delegated_test.go +++ b/infoblox/resource_infoblox_zone_delegated_test.go @@ -20,7 +20,7 @@ func testAccCheckZoneDelegatedDestroy(s *terraform.State) error { } connector := meta.(ibclient.IBConnector) objMgr := ibclient.NewObjectManager(connector, "terraform_test", "test") - rec, _ := objMgr.GetZoneDelegated(rs.Primary.ID) + rec, _ := objMgr.GetZoneDelegatedByRef(rs.Primary.ID) if rec != nil { return fmt.Errorf("Zone Delegation record found after destroy") } @@ -48,7 +48,7 @@ func testAccZoneDelegatedCompare(t *testing.T, resPath string, expectedRec *ibcl sort.Strings(lookupHosts) expectedRec.Addresses = append(expectedRec.Addresses, &ibclient.ZoneNameServer{Address: lookupHosts[0]}) - rec, _ := objMgr.GetZoneDelegated(res.Primary.ID) + rec, _ := objMgr.GetZoneDelegatedByRef(res.Primary.ID) if rec == nil { return fmt.Errorf("record not found") } @@ -77,6 +77,7 @@ func strPtr(s string) *string { } func TestAccResourceZoneDelegated(t *testing.T) { + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, From 2d7b74e26dd53343c23d08d14beff4a31538b5df Mon Sep 17 00:00:00 2001 From: Piper Dougherty Date: Thu, 16 May 2024 09:59:13 -0500 Subject: [PATCH 7/7] feature: assuming 2.7.0 as release that includes GetZoneDelegatedByRef --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b1ede1ea7..3fa6c1d11 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/uuid v1.3.0 github.com/hashicorp/terraform-plugin-log v0.7.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.19.0 - github.com/infobloxopen/infoblox-go-client/v2 v2.6.0 + github.com/infobloxopen/infoblox-go-client/v2 v2.7.0 github.com/sirupsen/logrus v1.8.0 )