diff --git a/docs/resources/infoblox_zone_auth.md b/docs/resources/infoblox_zone_auth.md new file mode 100644 index 000000000..6648da1d7 --- /dev/null +++ b/docs/resources/infoblox_zone_auth.md @@ -0,0 +1,50 @@ +# Authoritative Zone Resource + +The `infoblox_zone_auth` resource creates a DNS zone with SOA and NS records for the given FQDN. + +## Parameter Reference + +The following list describes the parameters you can define in the resource block for the zone: + +* `fqdn`: required, specifies the fully qualified domain name for the DNS zone. Example: `prod123.example.com` +* `ns_group`: required, name of Nameserver Group in Infoblox; will create NS records +* `restart_if_needed`: optional, restart the member service if necessary for changes to take effect +* `comment`: required, description of this Authoritative Zone; max 256 characters +* `soa_default_ttl`: optional, Time To Live (TTL) of the SOA record, in seconds; default `3600` +* `soa_expire`: optional, time in seconds for secondary servers to stop answering about the zone because the data is stale; default `2419200` (1 week) +* `soa_negative_ttl`: optional, time in seconds for secondary servers to cache data for 'Does Not Respond' responses; default `900` +* `soa_refresh`: optional, interval in seconds for secondary servers to check the primary server for fresh data about the zone; default `10800` +* `soa_retry`: optional, interval in seconds for secondary servers to wait before recontacting primary server about the zone after failure; default `3600` +* `ext_attrs`: optional, a set of NIOS extensible attributes that are attached to the record, using jsonencode(). + +## Example Usage + +```hcl +resource "infoblox_zone_auth" "prod123_zone" { + fqdn = "prod123.example.com" + ns_group = "Prod_NS_Group" + restart_if_needed = true + comment = "Managed by Terraform" + soa_default_ttl = 3600 + soa_expire = 2419200 + soa_negative_ttl = 900 + soa_refresh = 10800 + soa_retry = 3600 +} +``` + +## Terraform Import + +Authoritative Zone resources can be imported using the Zone Reference from the Infoblox NIOS API. + +Example query to see the Zone Refs for an Infoblox instance. Find the Ref for your zone: + +``` +> curl -k -u $USER:$PASSWORD -X GET "https://infoblox-dns.example.com/wapi/v2.11/zone_auth?_return_as_object=1" +``` + +Then import into your Terraform state: + +``` +> terraform import infoblox_zone_auth.prod123_zone zone_auth/kZWZhdWx0LmlvLnZG5zLnpvbmUkLl9RrdG0udXxLnNhbmRib3gxMQ:prod123.example.com/default +``` \ No newline at end of file diff --git a/infoblox/provider.go b/infoblox/provider.go index ab603f0b8..8413d3c66 100644 --- a/infoblox/provider.go +++ b/infoblox/provider.go @@ -177,6 +177,7 @@ func Provider() *schema.Provider { "infoblox_aaaa_record": resourceAAAARecord(), "infoblox_cname_record": resourceCNAMERecord(), "infoblox_ptr_record": resourcePTRRecord(), + "infoblox_zone_auth": resourceZoneAuth(), }, DataSourcesMap: map[string]*schema.Resource{ "infoblox_ipv4_network": dataSourceIPv4Network(), diff --git a/infoblox/resource_infoblox_zone_auth.go b/infoblox/resource_infoblox_zone_auth.go new file mode 100644 index 000000000..357a683f6 --- /dev/null +++ b/infoblox/resource_infoblox_zone_auth.go @@ -0,0 +1,232 @@ +package infoblox + +import ( + "encoding/json" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + ibclient "github.com/infobloxopen/infoblox-go-client/v2" +) + +func resourceZoneAuth() *schema.Resource { + return &schema.Resource{ + Create: resourceZoneAuthCreate, + Read: resourceZoneAuthGet, + Update: resourceZoneAuthUpdate, + Delete: resourceZoneAuthDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "dns_view": { + Type: schema.TypeString, + Optional: true, + Default: "default", + Description: "Dns View under which the zone has been created", + }, + "fqdn": { + Type: schema.TypeString, + Required: true, + Description: "The FQDN of the Authoritative zone", + }, + "ns_group": { + Type: schema.TypeString, + Required: true, + Description: "Name of Nameserver Group in Infoblox; will create NS records", + }, + "restart_if_needed": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Restart the member service if necessary for changes to take effect", + }, + "comment": { + Type: schema.TypeString, + Required: true, + Description: "Description of this Authoritative Zone; max 256 characters", + }, + "soa_default_ttl": { + Type: schema.TypeInt, + Default: 3600, + Optional: true, + Description: "Time To Live (TTL) of the SOA record, in seconds", + }, + "soa_expire": { + Type: schema.TypeInt, + Default: 2419200, + Optional: true, + Description: "Time in seconds for secondary servers to stop answering about the zone because the data is stale (default 1 week)", + }, + "soa_negative_ttl": { + Type: schema.TypeInt, + Default: 900, + Optional: true, + Description: "Time in seconds for secondary servers to cache data for 'Does Not Respond' responses", + }, + "soa_refresh": { + Type: schema.TypeInt, + Default: 10800, + Optional: true, + Description: "Interval in seconds for secondary servers to check the primary server for fresh data about the zone", + }, + "soa_retry": { + Type: schema.TypeInt, + Default: 3600, + Optional: true, + Description: "Interval in seconds for secondary servers to wait before recontacting primary server about the zone after failure", + }, + "zone_format": { + Type: schema.TypeString, + Optional: true, + Default: "FORWARD", + Description: "Format of the zone: FORWARD, IPV4, IPV6", + }, + "ext_attrs": { + Type: schema.TypeString, + Default: "", + Optional: true, + Description: "Extensible attributes, as a map in JSON format", + }, + }, + } +} + +// CRUD FUNCTIONS + +func resourceZoneAuthCreate(d *schema.ResourceData, m interface{}) error { + dnsview := d.Get("dns_view").(string) + fqdn := d.Get("fqdn").(string) + nsGroup := d.Get("ns_group").(string) + restartIfNeeded := d.Get("restart_if_needed").(bool) + comment := d.Get("comment").(string) + soaDefaultTtl := d.Get("soa_default_ttl").(int) + soaExpire := d.Get("soa_expire").(int) + soaNegativeTtl := d.Get("soa_negative_ttl").(int) + soaRefresh := d.Get("soa_refresh").(int) + soaRetry := d.Get("soa_retry").(int) + zoneFormat := d.Get("zone_format").(string) + + 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 + tempVal, found := extAttrs["Tenant ID"] + if found { + tenantID = tempVal.(string) + } + connector := m.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + newZone, err := objMgr.CreateZoneAuth( + dnsview, fqdn, nsGroup, restartIfNeeded, comment, + soaDefaultTtl, soaExpire, soaNegativeTtl, soaRefresh, soaRetry, zoneFormat, extAttrs) + if err != nil { + return fmt.Errorf("error creating Zone Auth: %s", err.Error()) + } + + d.SetId(newZone.Ref) + + return nil +} + +func resourceZoneAuthGet(d *schema.ResourceData, m interface{}) error { + 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 + tempVal, found := extAttrs["Tenant ID"] + if found { + tenantID = tempVal.(string) + } + connector := m.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + obj, err := objMgr.GetZoneAuthByRef(d.Id()) + if err != nil { + return fmt.Errorf("getting Zone Auth failed: %s", err.Error()) + } + + d.Set("fqdn", obj.Fqdn) + d.Set("comment", obj.Comment) + d.SetId(obj.Ref) + + return nil +} + +func resourceZoneAuthUpdate(d *schema.ResourceData, m interface{}) error { + dnsview := d.Get("dns_view").(string) + // fqdn := d.Get("fqdn").(string) CANNOT BE UPDATED IN WAPI + nsGroup := d.Get("ns_group").(string) + restartIfNeeded := d.Get("restart_if_needed").(bool) + comment := d.Get("comment").(string) + soaDefaultTtl := d.Get("soa_default_ttl").(int) + soaExpire := d.Get("soa_expire").(int) + soaNegativeTtl := d.Get("soa_negative_ttl").(int) + soaRefresh := d.Get("soa_refresh").(int) + soaRetry := d.Get("soa_retry").(int) + // zoneFormat := d.Get("zone_format").(string) CANNOT BE UPDATED IN WAPI + + 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 + tempVal, found := extAttrs["Tenant ID"] + if found { + tenantID = tempVal.(string) + } + connector := m.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + updatedZone, err := objMgr.UpdateZoneAuth( + d.Id(), dnsview, nsGroup, restartIfNeeded, comment, + soaDefaultTtl, soaExpire, soaNegativeTtl, soaRefresh, soaRetry, extAttrs) + if err != nil { + return fmt.Errorf("error creating Zone Auth: %s", err.Error()) + } + + d.SetId(updatedZone.Ref) + + return nil +} + +func resourceZoneAuthDelete(d *schema.ResourceData, m interface{}) error { + dnsview := d.Get("dns_view").(string) + 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 + tempVal, found := extAttrs["Tenant ID"] + if found { + tenantID = tempVal.(string) + } + connector := m.(ibclient.IBConnector) + objMgr := ibclient.NewObjectManager(connector, "Terraform", tenantID) + + _, err := objMgr.DeleteZoneAuth(d.Id()) + if err != nil { + return fmt.Errorf("deletion of Zone Auth from dns view %s failed: %s", dnsview, err.Error()) + } + d.SetId("") + + return nil +}