-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add infoblox_zone_delegated resource #217
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# 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 | ||
* `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 | ||
resource "infoblox_zone_delegated" "subdomain" { | ||
|
||
fqdn = "subdomain.test.com" | ||
|
||
delegate_to { | ||
name = "ns-1488.awsdns-58.org" | ||
} | ||
|
||
delegate_to { | ||
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 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Zone Delegated | ||
|
||
resource "infoblox_zone_delegated" "subdomain" { | ||
|
||
fqdn = "subdomain.example.com" | ||
|
||
delegate_to { | ||
name = "ns-1488.awsdns-58.org" | ||
} | ||
|
||
delegate_to { | ||
name = "ns-2034.awsdns-62.co.uk" | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
terraform { | ||
required_providers { | ||
infoblox = { | ||
source = "infobloxopen/infoblox" | ||
version = ">= 2.1" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,250 @@ | ||||||
package infoblox | ||||||
|
||||||
import ( | ||||||
"encoding/json" | ||||||
"fmt" | ||||||
"log" | ||||||
"net" | ||||||
"sort" | ||||||
|
||||||
"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, | ||||||
Computed: true, | ||||||
Description: "IP of Name Server", | ||||||
}, | ||||||
"name": { | ||||||
Type: schema.TypeString, | ||||||
Required: true, | ||||||
Description: "FQDN of Name Server", | ||||||
}, | ||||||
}, | ||||||
}, | ||||||
} | ||||||
} | ||||||
|
||||||
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)) | ||||||
|
||||||
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()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's better to wrap the error:
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
delegatedFQDN := d.Get("fqdn").(string) | ||||||
|
||||||
delegations := d.Get("delegate_to").(*schema.Set).List() | ||||||
|
||||||
nameServers, computedDelegations, err := computeDelegations(delegations) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
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) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
d.Set("delegate_to", computedDelegations) | ||||||
|
||||||
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) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
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()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
delegations := d.Get("delegate_to").(*schema.Set).List() | ||||||
|
||||||
nameServers, computedDelegations, err := computeDelegations(delegations) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
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()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
d.Set("delegate_to", computedDelegations) | ||||||
|
||||||
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()) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
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) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
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 = "<new resource>" | ||||||
} | ||||||
return fmt.Sprintf("infoblox_zone_delegated (ID = %s)", id) | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you move
delegate_to
schema definition into a separate function? There's no complex initialization logic involved, and this function is used only here.