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

implementation of DTC LBDN resource and datasource and DTC Pool datasource #423

Merged
merged 8 commits into from
Jan 10, 2025
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/google/uuid v1.6.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/infobloxopen/infoblox-go-client/v2 v2.8.0
github.com/infobloxopen/infoblox-go-client/v2 v2.8.1-0.20250107110944-605cad462ca6
github.com/sirupsen/logrus v1.9.3
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/infobloxopen/infoblox-go-client/v2 v2.8.0 h1:JWdBwjuXOLV7Fwf8yGMBdU/SbS+Cm4f/lgO12yg7Jjs=
github.com/infobloxopen/infoblox-go-client/v2 v2.8.0/go.mod h1:NeNJpz09efw/edzqkVivGv1bWqBXTomqYBRFbP+XBqg=
github.com/infobloxopen/infoblox-go-client/v2 v2.8.1-0.20250107110944-605cad462ca6 h1:p8pB9c/o/xuJtrv34pCT+K+h3wt5zPsVvqLqGXrrspc=
github.com/infobloxopen/infoblox-go-client/v2 v2.8.1-0.20250107110944-605cad462ca6/go.mod h1:NeNJpz09efw/edzqkVivGv1bWqBXTomqYBRFbP+XBqg=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
Expand Down
255 changes: 255 additions & 0 deletions infoblox/datasource_infoblox_dtc_lbdn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
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 dataSourceDtcLbdnRecord() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceDtcLbdnRecordRead,
Schema: map[string]*schema.Schema{
"filters": {
Type: schema.TypeMap,
Required: true,
},
"results": {
Type: schema.TypeList,
Computed: true,
Description: "List of DTC LBDN Records matching filters",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Required: true,
Description: "The display name of the DTC LBDN.",
},
"auth_zones": {
Type: schema.TypeList,
Optional: true,
Description: "List of linked auth zones.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"auto_consolidated_monitors": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Flag for enabling auto managing DTC Consolidated Monitors on related DTC Pools.",
},
"comment": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "Description of the DTC LBDN record.",
},
"ext_attrs": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "Extensible attributes of the DTC LBDN record to be added/updated, as a map in JSON format.",
},
"disable": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Determines whether the DTC LBDN is disabled or not. When this is set to False, the fixed address is enabled.",
},
"lb_method": {
Type: schema.TypeString,
Required: true,
Description: "The load balancing method. Used to select pool. Valid values are GLOBAL_AVAILABILITY, RATIO, ROUND_ROBIN, SOURCE_IP_HASH and TOPOLOGY.",
},
"patterns": {
Type: schema.TypeList,
Optional: true,
Description: "LBDN wildcards for pattern match.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"persistence": {
Type: schema.TypeInt,
Optional: true,
Default: 0,
Description: "Maximum time, in seconds, for which client specific LBDN responses will be cached. Zero specifies no caching.",
},
"pools": {
Type: schema.TypeList,
Optional: true,
Description: "The maximum time, in seconds, for which client specific LBDN responses will be cached. Zero specifies no caching.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"pool": {
Type: schema.TypeString,
Required: true,
Description: "The pool to link with.",
},
"ratio": {
Type: schema.TypeInt,
Required: true,
Description: "The weight of pool.",
},
},
},
},
"priority": {
Type: schema.TypeInt,
Optional: true,
Description: "The LBDN pattern match priority for “overlapping” DTC LBDN objects. LBDNs are “overlapping” if " +
"they are simultaneously assigned to a zone and have patterns that can match the same FQDN. The matching LBDN with highest priority (lowest ordinal) will be used.",
},
"topology": {
Type: schema.TypeString,
Optional: true,
Description: "The topology rules for TOPOLOGY method.",
},
"ttl": {
Type: schema.TypeInt,
Optional: true,
Default: ttlUndef,
Description: "The Time To Live (TTL) value for the DTC LBDN. A 32-bit unsigned integer that represents the duration, in seconds, for which the record is valid (cached). Zero indicates that the record should not be cached.",
},
"types": {
Type: schema.TypeList,
Optional: true,
Description: "The list of resource record types supported by LBDN. Valid values are A, AAAA, CNAME, NAPTR, SRV. Default value is A and AAAA",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
},
}
}

func dataSourceDtcLbdnRecordRead(ctx 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.GetAllDtcLbdn(qp)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to get DTC LBDN records: %w", err))
}

if res == nil {
return diag.FromErr(fmt.Errorf("API returns a nil/empty ID for DTC LBDN"))
}
results := make([]interface{}, 0, len(res))
for _, r := range res {
dtcLbdn, err := flattenDtcLbdn(r, connector)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to flatten DTC LBDN : %w", err))
}
results = append(results, dtcLbdn)
}

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 flattenDtcLbdn(lbdn ibclient.DtcLbdn, connector ibclient.IBConnector) (map[string]interface{}, error) {
var eaMap map[string]interface{}
if lbdn.Ea != nil && len(lbdn.Ea) > 0 {
eaMap = lbdn.Ea
} else {
eaMap = make(map[string]interface{})
}

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

res := map[string]interface{}{
"id": lbdn.Ref,
"name": lbdn.Name,
"ext_attrs": string(ea),
"lb_method": lbdn.LbMethod,
}
if lbdn.Comment != nil {
res["comment"] = *lbdn.Comment
}
if lbdn.Disable != nil {
res["disable"] = *lbdn.Disable
}
if lbdn.AuthZones != nil {
authZones, err := ConvertAuthZonesToInterface(connector, &lbdn)
if err != nil {
return nil, err
}
res["auth_zones"] = authZones
}

if lbdn.AutoConsolidatedMonitors != nil {
res["auto_consolidated_monitors"] = *lbdn.AutoConsolidatedMonitors
}

if lbdn.Patterns != nil {
res["patterns"] = convertSliceToInterface(lbdn.Patterns)
}

if lbdn.Persistence != nil {
res["persistence"] = lbdn.Persistence
}

if lbdn.Pools != nil {
pools, err := convertPoolsToInterface(&lbdn, connector)
if err != nil {
return nil, err
} else {
res["pools"] = pools
}
}
if lbdn.Priority != nil {
res["priority"] = lbdn.Priority
}
if lbdn.Topology != nil {
var topology ibclient.DtcTopology
err := connector.GetObject(&ibclient.DtcTopology{}, *lbdn.Topology, nil, &topology)
if err != nil {
return nil, fmt.Errorf("error getting %s DtcTopology object: %s", *lbdn.Topology, err)
}
res["topology"] = *topology.Name
}
if lbdn.Types != nil {
res["types"] = convertSliceToInterface(lbdn.Types)
}
if lbdn.UseTtl != nil {
if !*lbdn.UseTtl {
res["ttl"] = ttlUndef
}
}
if lbdn.Ttl != nil && *lbdn.Ttl > 0 {
res["ttl"] = *lbdn.Ttl
} else {
res["ttl"] = ttlUndef
}
return res, nil
}
105 changes: 105 additions & 0 deletions infoblox/datasource_infoblox_dtc_lbdn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package infoblox

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"testing"
)

var testAccDataSourceDtcLbdn = fmt.Sprintf(`resource "infoblox_dtc_lbdn" "testLbdn_src_1" {
name = "testLbdn444"
lb_method = "RATIO"
}
data "infoblox_dtc_lbdn" "testLbdn_src_read1" {
filters = {
name = infoblox_dtc_lbdn.testLbdn_src_1.name
}
depends_on = [infoblox_dtc_lbdn.testLbdn_src_1]
}`)

var testAccDatasourceDtcLbdn = fmt.Sprintf(`resource "infoblox_dtc_lbdn" "testLbdn_src" {
name = "testLbdn888"
auth_zones = ["test.com"]
comment = "test lbdn with max params"
ext_attrs = jsonencode({
"Site" = "Malpe"
})
lb_method = "TOPOLOGY"
patterns = ["test.com*", "info.com*"]
pools {
pool = "pool2"
ratio = 2
}
pools {
pool = "rrpool"
ratio = 3
}
pools {
pool = "test-pool"
ratio = 6
}
topology = "test-topo"
ttl = 120
disable = true
types = ["A", "AAAA", "CNAME"]
persistence = 60
priority = 2
}
data "infoblox_dtc_lbdn" "testLbdn_src_read" {
filters = {
name = infoblox_dtc_lbdn.testLbdn_src.name
}
depends_on = [infoblox_dtc_lbdn.testLbdn_src]
}`)

func TestAccDataSourceDtcLbdn(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceDtcLbdn,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read1", "results.0.name", "testLbdn444"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read1", "results.0.lb_method", "RATIO"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read1", "results.0.types.0", "A"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read1", "results.0.types.1", "AAAA"),
),
},
},
})
}

func TestAccDataSourceDtcLbdnSearchByEA(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDatasourceDtcLbdn,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.#", "1"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.name", "testLbdn888"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.auth_zones.0", "test.com"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.comment", "test lbdn with max params"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.lb_method", "TOPOLOGY"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.topology", "test-topo"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.0.pool", "pool2"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.0.ratio", "2"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.1.pool", "rrpool"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.1.ratio", "3"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.2.pool", "test-pool"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.pools.2.ratio", "6"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.ttl", "120"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.disable", "true"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.types.0", "A"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.types.1", "AAAA"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.types.2", "CNAME"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.persistence", "60"),
resource.TestCheckResourceAttr("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.priority", "2"),
resource.TestCheckResourceAttrPair("data.infoblox_dtc_lbdn.testLbdn_src_read", "results.0.ext_attrs.Site", "infoblox_dtc_lbdn.testLbdn_src", "ext_attrs.Site"),
),
},
},
})
}
Loading
Loading