Skip to content
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

Added support for ZoneDelegated object #379

Merged
merged 13 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ curl -k -u <user>:<password> -H "Content-Type: application/json" -X POST https:/

> **Note:**
>
>Either the Terraform Internal ID extensible attribute definition must be present in NIOS or IPAM Plug-In for Terraform
>Either the Terraform Internal ID extensible attribute definition must be present in NIOS or IPAM Plug-In for Terraform
must be configured with superuser access for it to automatically create the extensible attribute. If not, the connection
to Terraform will fail.
to Terraform will fail.
>
>If you choose to create the Terraform Internal ID extensible attribute manually or by using the cURL command,
the creation of the extensible attribute is not managed by IPAM Plug-In for Terraform.
>
>You must not modify the Terraform Internal ID for a resource under any circumstances. If it is modified, the resource
will no longer be managed by Terraform.
will no longer be managed by Terraform.


## Configuring Infoblox Terraform IPAM Plug-In
Expand Down Expand Up @@ -101,6 +101,7 @@ There are resources for the following objects, supported by the plugin:
* Zone Auth (`infoblox_zone_auth`)
* Zone Forward (`infoblox_zone_forward`)
* Host record (`infoblox_ip_allocation` / `infoblox_ip_association`)
* Zone Delegated (`infoblox_zone_delegated`)

Network and network container resources have two versions: IPv4 and IPv6. In
addition, there are two operations which are implemented as resources:
Expand Down Expand Up @@ -152,12 +153,13 @@ There are data sources for the following objects:
* Zone Auth (`infoblox_zone_auth`)
* Zone Forward (`infoblox_zone_forward`)
* Host Record (`infoblox_host_record`)
* Zone Delegated (`infoblox_zone_delegated`)

!> From version 2.5.0, new feature filters are introduced. Now the data sources support to populate more than one
matching NIOS objects.

* `filters`: the schema, with passing combination of searchable fields are supported by NIOS server, which
returns one or more matching objects from the NIOS server.
returns one or more matching objects from the NIOS server.

For usage of filters, add the fields as keys and appropriate values to be passed to the keys like `name`, `view` corresponding to object.

Expand Down Expand Up @@ -265,11 +267,11 @@ with a randomly generated value in the form of a UUID to the record.
- You may use the command-line tool `uuid` for Linux-based systems to generate a UUID.

> The `Terraform Internal ID` extensible attribute is not shown in to terraform.tfstate file. Use it to create
or import the `infoblox_ip_allocation` and `infoblox_ip_association` resources.
You must not add it in a resource block with other extensible attributes.
or import the `infoblox_ip_allocation` and `infoblox_ip_association` resources.
You must not add it in a resource block with other extensible attributes.

> You must not delete (ex. with 'terraform destroy' command) an `infoblox_ip_association` resource right after importing, but you may do this after 'terraform apply'.
The reason: after 'terraform import' the dependency between `infoblox_ip_association` and respective `infoblox_ip_allocation` is not established by Terraform.
The reason: after 'terraform import' the dependency between `infoblox_ip_association` and respective `infoblox_ip_allocation` is not established by Terraform.


### Utilizing the Import Block to Import Resources:
Expand Down Expand Up @@ -311,5 +313,5 @@ resource "infoblox_a_record" "imported_records" {
}
```
> **Note:**
>
> When using the Terraform import block for a resource, a new Terraform internal ID is assigned to the resource when the terraform plan command is run for the first time. If a subsequent terraform apply is aborted, the record will still retain the Terraform Internal ID though the resource is not managed by Terraform.
>
> When using the Terraform import block for a resource, a new Terraform internal ID is assigned to the resource when the terraform plan command is run for the first time. If a subsequent terraform apply is aborted, the record will still retain the Terraform Internal ID though the resource is not managed by Terraform.
40 changes: 40 additions & 0 deletions docs/resources/infoblox_zone_delegated.md
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
```
13 changes: 13 additions & 0 deletions examples/resources/infoblox_zone_delegated.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Zone Delegated

resource "infoblox_zone_delegated" "subdomain" {
fqdn = "subdomain.example.com"
delegate_to {
name = "ns-1488.awsdns-58.org"
address = "10.1.1.1"
}
delegate_to {
name = "ns-2034.awsdns-62.co.uk"
address = "10.10.1.1"
}
}
201 changes: 201 additions & 0 deletions infoblox/datasource_infoblox_zone_delegated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package infoblox

import (
"context"
"encoding/json"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
ibclient "github.com/infobloxopen/infoblox-go-client/v2"
"strconv"
"time"
)

func dataSourceZoneDelegated() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceZoneDelegatedRead,
Schema: map[string]*schema.Schema{
"filters": {
Type: schema.TypeMap,
Required: true,
},
"results": {
Type: schema.TypeList,
Computed: true,
Description: "List of Forward Zones matching filters",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"fqdn": {
Type: schema.TypeString,
Required: true,
Description: "The FQDN of the delegated zone.",
},
"delegate_to": {
Type: schema.TypeSet,
Optional: true,
Description: "The Infoblox appliance redirects queries for data for the delegated zone to this remote name server.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"address": {
Type: schema.TypeString,
Required: true,
Description: "The IPv4 Address or IPv6 Address of the server.",
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "A resolvable domain name for the external DNS server.",
},
},
},
},
"comment": {
Type: schema.TypeString,
Optional: true,
Description: "A descriptive comment.",
},
"disable": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Determines if the zone is disabled or not.",
},
"locked": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "If you enable this flag, other administrators cannot make conflicting changes. This is for administration purposes only. " +
"The zone will continue to serve DNS data even when it is locked.",
},
"ns_group": {
Type: schema.TypeString,
Optional: true,
Description: "The delegation NS group bound with delegated zone.",
},
"delegated_ttl": {
Type: schema.TypeInt,
Optional: true,
Default: ttlUndef,
Description: "TTL value for zone-delegated.",
},
"ext_attrs": {
Type: schema.TypeString,
Default: "",
Optional: true,
Description: "Extensible attributes, as a map in JSON format",
},
"view": {
Type: schema.TypeString,
Optional: true,
Default: "default",
Description: "The DNS view in which the zone is created.",
},
"zone_format": {
Type: schema.TypeString,
Optional: true,
Default: "FORWARD",
Description: "The format of the zone. Valid values are: FORWARD, IPV4, IPV6.",
},
},
},
},
},
}
}

func dataSourceZoneDelegatedRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
connector := m.(ibclient.IBConnector)

var diags diag.Diagnostics

filters := filterFromMap(d.Get("filters").(map[string]interface{}))

objMgr := ibclient.NewObjectManager(connector, "Terraform", "")

qp := ibclient.NewQueryParams(false, filters)
res, err := objMgr.GetZoneDelegatedByFilters(qp)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to get zone delegated records: %w", err))
}

if res == nil {
return diag.FromErr(fmt.Errorf("API returns a nil/empty ID for zone delegated"))
}
// TODO: temporary scaffold, need to rework marshalling/unmarshalling of EAs
// (avoiding additional layer of keys ("value" key)
results := make([]interface{}, 0, len(res))
for _, r := range res {
zoneDelegatedFlat, err := flattenZoneDelegated(r)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to flatten zone delegated : %w", err))
}
results = append(results, zoneDelegatedFlat)
}

err = d.Set("results", results)
if err != nil {
return diag.FromErr(err)
}

// always run
d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

return diags

}

func flattenZoneDelegated(zoneDelegated ibclient.ZoneDelegated) (map[string]interface{}, error) {
var eaMap map[string]interface{}
if zoneDelegated.Ea != nil && len(zoneDelegated.Ea) > 0 {
eaMap = zoneDelegated.Ea
} else {
eaMap = make(map[string]interface{})
}

ea, err := json.Marshal(eaMap)
if err != nil {
return nil, err
}

res := map[string]interface{}{
"id": zoneDelegated.Ref,
"fqdn": zoneDelegated.Fqdn,
"ext_attrs": string(ea),
"zone_format": zoneDelegated.ZoneFormat,
"view": *zoneDelegated.View,
}
if zoneDelegated.Comment != nil {
res["comment"] = *zoneDelegated.Comment
}
if zoneDelegated.Disable != nil {
res["disable"] = *zoneDelegated.Disable
}
if zoneDelegated.Locked != nil {
res["locked"] = *zoneDelegated.Locked
}
if zoneDelegated.NsGroup != nil {
res["ns_group"] = *zoneDelegated.NsGroup
}
if zoneDelegated.UseDelegatedTtl != nil {
if !*zoneDelegated.UseDelegatedTtl {
res["delegated_ttl"] = ttlUndef
}
}

if zoneDelegated.DelegatedTtl != nil && *zoneDelegated.DelegatedTtl > 0 {
res["delegated_ttl"] = *zoneDelegated.DelegatedTtl
} else {
res["delegated_ttl"] = ttlUndef
}

if zoneDelegated.DelegateTo.IsNull == false {
nsInterface := convertNullableNameServersToInterface(zoneDelegated.DelegateTo)
res["delegate_to"] = nsInterface
}

return res, nil
}
Loading