Skip to content

Commit

Permalink
Fix dual stack ip pool reservation issue
Browse files Browse the repository at this point in the history
  • Loading branch information
danischm committed Dec 20, 2024
1 parent b4b0cfc commit 838bf7c
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Add `catalystcenter_fabric_l3_virtual_network` resource and data source
- Add `Free Space` allowed value to `rf_model` attribute of `catalystcenter_floor` resource
- Add device unreachability warning to 'delete' implementation of `catalystcenter_fabric_l3_handoff_ip_transit`, `catalystcenter_anycast_gateway`, `catalystcenter_fabric_l2_handoff`, `catalystcenter_fabric_device`, `catalystcenter_fabric_port_assignment` and `catalystcenter_provision_device` resources
- Fix issue with `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/156)

## 0.1.17

Expand Down
1 change: 1 addition & 0 deletions docs/guides/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description: |-
- Add `catalystcenter_fabric_l3_virtual_network` resource and data source
- Add `Free Space` allowed value to `rf_model` attribute of `catalystcenter_floor` resource
- Add device unreachability warning to 'delete' implementation of `catalystcenter_fabric_l3_handoff_ip_transit`, `catalystcenter_anycast_gateway`, `catalystcenter_fabric_l2_handoff`, `catalystcenter_fabric_device`, `catalystcenter_fabric_port_assignment` and `catalystcenter_provision_device` resources
- Fix issue with `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/156)

## 0.1.17

Expand Down
1 change: 1 addition & 0 deletions gen/definitions/ip_pool.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ attributes:
type: String
enum_values: [IPv4, IPv6]
default_value: IPv4
write_only: true
description: IP address version
example: IPv4
- model_name: type
Expand Down
9 changes: 3 additions & 6 deletions gen/definitions/ip_pool_reservation.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
name: IP Pool Reservation
# Manual modifications in model file in updateFromBody and fromBody to support dual-stack pools
rest_endpoint: /dna/intent/api/v1/reserve-ip-subpool
id_from_query_path: response.0
id_from_query_path_attribute: id
Expand Down Expand Up @@ -55,14 +56,14 @@ attributes:
example: true
- model_name: ipv4PrefixLength
type: Int64
write_only: true
requires_replace: true
exclude_from_put: true
description: The IPv4 prefix length is required when `ipv4_prefix` value is `true`.
example: 24
minimum_test_value: 24
- model_name: ipv4Subnet
type: String
write_only: true
requires_replace: true
exclude_from_put: true
description: The IPv4 subnet
example: 172.32.1.0
Expand Down Expand Up @@ -112,21 +113,18 @@ attributes:
- model_name: ipv6GateWay
tf_name: ipv6_gateway
type: String
write_only: true
description: The gateway for the IP pool reservation
example: "2001:db8:85a3:0:100::1"
exclude_test: true
- model_name: ipv6DhcpServers
type: Set
element_type: String
write_only: true
description: List of DHCP Server IPs
example: "2001:db8::1234"
exclude_test: true
- model_name: ipv6DnsServers
type: Set
element_type: String
write_only: true
description: List of DNS Server IPs
example: "2001:db8::1234"
exclude_test: true
Expand Down Expand Up @@ -160,4 +158,3 @@ test_prerequisites: |
name = "MyPool1"
ip_subnet = "172.32.0.0/16"
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
func TestAccDataSourceCcIPPoolReservation(t *testing.T) {
var checks []resource.TestCheckFunc
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool_reservation.test", "name", "MyRes1"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool_reservation.test", "ipv4_prefix_length", "24"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool_reservation.test", "ipv4_subnet", "172.32.1.0"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool_reservation.test", "ipv4_gateway", "172.32.1.1"))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (
func TestAccDataSourceCcIPPool(t *testing.T) {
var checks []resource.TestCheckFunc
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool.test", "name", "MyPool1"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool.test", "ip_address_space", "IPv4"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool.test", "type", "generic"))
checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_ip_pool.test", "ip_subnet", "21.1.1.0/24"))
resource.Test(t, resource.TestCase{
Expand Down
10 changes: 0 additions & 10 deletions internal/provider/model_catalystcenter_ip_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,6 @@ func (data *IPPool) fromBody(ctx context.Context, res gjson.Result) {
} else {
data.Name = types.StringNull()
}
if value := res.Get("IpAddressSpace"); value.Exists() {
data.IpAddressSpace = types.StringValue(value.String())
} else {
data.IpAddressSpace = types.StringValue("IPv4")
}
if value := res.Get("type"); value.Exists() {
data.Type = types.StringValue(value.String())
} else {
Expand Down Expand Up @@ -142,11 +137,6 @@ func (data *IPPool) updateFromBody(ctx context.Context, res gjson.Result) {
} else {
data.Name = types.StringNull()
}
if value := res.Get("IpAddressSpace"); value.Exists() && !data.IpAddressSpace.IsNull() {
data.IpAddressSpace = types.StringValue(value.String())
} else if data.IpAddressSpace.ValueString() != "IPv4" {
data.IpAddressSpace = types.StringNull()
}
if value := res.Get("type"); value.Exists() && !data.Type.IsNull() {
data.Type = types.StringValue(value.String())
} else if data.Type.ValueString() != "generic" {
Expand Down
188 changes: 154 additions & 34 deletions internal/provider/model_catalystcenter_ip_pool_reservation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ package provider
// Section below is generated&owned by "gen/generator.go". //template:begin imports
import (
"context"
"strconv"
"strings"

"github.com/CiscoDevNet/terraform-provider-catalystcenter/internal/provider/helpers"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand Down Expand Up @@ -145,7 +147,6 @@ func (data IPPoolReservation) toBody(ctx context.Context, state IPPoolReservatio

// End of section. //template:end toBody

// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
func (data *IPPoolReservation) fromBody(ctx context.Context, res gjson.Result) {
// Retrieve the 'id' attribute, if Data Source doesn't require id
if value := res.Get("response.0.id"); value.Exists() {
Expand All @@ -158,51 +159,170 @@ func (data *IPPoolReservation) fromBody(ctx context.Context, res gjson.Result) {
} else {
data.Name = types.StringNull()
}
if value := res.Get("response.0.ipPools.0.gateways.0"); value.Exists() {
data.Ipv4Gateway = types.StringValue(value.String())
} else {
data.Ipv4Gateway = types.StringNull()
}
if value := res.Get("response.0.ipPools.0.dhcpServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv4DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DhcpServers = types.SetNull(types.StringType)
}
if value := res.Get("response.0.ipPools.0.dnsServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv4DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DnsServers = types.SetNull(types.StringType)
// Added support for Dual Stack Pool Reservations
if pools := res.Get("response.0.ipPools"); pools.IsArray() {
ipPools := pools.Array()
for _, pool := range ipPools {
if pool.Get("ipv6").Bool() { // Check if the pool is IPv6
if value := pool.Get("gateways.0"); value.Exists() {
data.Ipv6Gateway = types.StringValue(value.String())
} else {
data.Ipv6Gateway = types.StringNull()
}
if value := pool.Get("dhcpServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv6DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv6DhcpServers = types.SetNull(types.StringType)
}
if value := pool.Get("dnsServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv6DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv6DnsServers = types.SetNull(types.StringType)
}
// Extract and assign Ipv6Subnet and Ipv6Prefix from ipPoolCidr
if cidr := pool.Get("ipPoolCidr"); cidr.Exists() && cidr.String() != "" {
cidrParts := strings.Split(cidr.String(), "/")
if len(cidrParts) == 2 {
data.Ipv6Subnet = types.StringValue(cidrParts[0])
if prefixLength, err := strconv.ParseInt(cidrParts[1], 10, 64); err == nil {
data.Ipv6PrefixLength = types.Int64Value(prefixLength)
} else {
data.Ipv6PrefixLength = types.Int64Null()
}
} else {
data.Ipv6Subnet = types.StringNull()
data.Ipv6PrefixLength = types.Int64Null()
}
} else {
data.Ipv6Subnet = types.StringNull()
data.Ipv6PrefixLength = types.Int64Null()
}
} else { // Otherwise it's IPv4
if value := pool.Get("gateways.0"); value.Exists() {
data.Ipv4Gateway = types.StringValue(value.String())
} else {
data.Ipv4Gateway = types.StringNull()
}
if value := pool.Get("dhcpServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv4DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DhcpServers = types.SetNull(types.StringType)
}
if value := pool.Get("dnsServerIps"); value.Exists() && len(value.Array()) > 0 {
data.Ipv4DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DnsServers = types.SetNull(types.StringType)
}
// Extract and assign Ipv4Subnet and Ipv4Prefix from ipPoolCidr
if cidr := pool.Get("ipPoolCidr"); cidr.Exists() && cidr.String() != "" {
cidrParts := strings.Split(cidr.String(), "/")
if len(cidrParts) == 2 {
data.Ipv4Subnet = types.StringValue(cidrParts[0])
if prefixLength, err := strconv.ParseInt(cidrParts[1], 10, 64); err == nil {
data.Ipv4PrefixLength = types.Int64Value(prefixLength)
} else {
data.Ipv4PrefixLength = types.Int64Null()
}
} else {
data.Ipv4Subnet = types.StringNull()
data.Ipv4PrefixLength = types.Int64Null()
}
} else {
data.Ipv4Subnet = types.StringNull()
data.Ipv4PrefixLength = types.Int64Null()
}
}
}
}
}

// End of section. //template:end fromBody

// Section below is generated&owned by "gen/generator.go". //template:begin updateFromBody
func (data *IPPoolReservation) updateFromBody(ctx context.Context, res gjson.Result) {
if value := res.Get("response.0.groupName"); value.Exists() && !data.Name.IsNull() {
data.Name = types.StringValue(value.String())
} else {
data.Name = types.StringNull()
}
if value := res.Get("response.0.ipPools.0.gateways.0"); value.Exists() && !data.Ipv4Gateway.IsNull() {
data.Ipv4Gateway = types.StringValue(value.String())
} else {
data.Ipv4Gateway = types.StringNull()
}
if value := res.Get("response.0.ipPools.0.dhcpServerIps"); value.Exists() && !data.Ipv4DhcpServers.IsNull() {
data.Ipv4DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DhcpServers = types.SetNull(types.StringType)
}
if value := res.Get("response.0.ipPools.0.dnsServerIps"); value.Exists() && !data.Ipv4DnsServers.IsNull() {
data.Ipv4DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DnsServers = types.SetNull(types.StringType)
// Added support for Dual Stack Pool Reservations
if pools := res.Get("response.0.ipPools"); pools.IsArray() {
ipPools := pools.Array()
for _, pool := range ipPools {
if pool.Get("ipv6").Bool() { // Check if the pool is IPv6
if value := pool.Get("gateways.0"); value.Exists() && !data.Ipv6Gateway.IsNull() {
data.Ipv6Gateway = types.StringValue(value.String())
} else {
data.Ipv6Gateway = types.StringNull()
}
if value := pool.Get("dhcpServerIps"); value.Exists() && !data.Ipv6DhcpServers.IsNull() {
data.Ipv6DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv6DhcpServers = types.SetNull(types.StringType)
}
if value := pool.Get("dnsServerIps"); value.Exists() && !data.Ipv6DnsServers.IsNull() {
data.Ipv6DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv6DnsServers = types.SetNull(types.StringType)
}
// Extract and assign Ipv6Subnet and Ipv6Prefix from ipPoolCidr
if cidr := pool.Get("ipPoolCidr"); cidr.Exists() && cidr.String() != "" {
cidrParts := strings.Split(cidr.String(), "/")
if len(cidrParts) == 2 {
if data.Ipv6Subnet.IsNull() {
data.Ipv6Subnet = types.StringValue(cidrParts[0])
}
if prefixLength, err := strconv.ParseInt(cidrParts[1], 10, 64); err == nil && !data.Ipv6PrefixLength.IsNull() {
data.Ipv6PrefixLength = types.Int64Value(prefixLength)
} else {
data.Ipv6PrefixLength = types.Int64Null()
}
} else {
data.Ipv6Subnet = types.StringNull()
data.Ipv6PrefixLength = types.Int64Null()
}
} else {
data.Ipv6Subnet = types.StringNull()
data.Ipv6PrefixLength = types.Int64Null()
}
} else { // Otherwise it's IPv4
if value := pool.Get("gateways.0"); value.Exists() && !data.Ipv4Gateway.IsNull() {
data.Ipv4Gateway = types.StringValue(value.String())
} else {
data.Ipv4Gateway = types.StringNull()
}
if value := pool.Get("dhcpServerIps"); value.Exists() && !data.Ipv4DhcpServers.IsNull() {
data.Ipv4DhcpServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DhcpServers = types.SetNull(types.StringType)
}
if value := pool.Get("dnsServerIps"); value.Exists() && !data.Ipv4DnsServers.IsNull() {
data.Ipv4DnsServers = helpers.GetStringSet(value.Array())
} else {
data.Ipv4DnsServers = types.SetNull(types.StringType)
}
// Extract and assign Ipv4Subnet and Ipv4Prefix from ipPoolCidr
if cidr := pool.Get("ipPoolCidr"); cidr.Exists() && cidr.String() != "" {
cidrParts := strings.Split(cidr.String(), "/")
if len(cidrParts) == 2 {
if data.Ipv4Subnet.IsNull() {
data.Ipv4Subnet = types.StringValue(cidrParts[0])
}
if prefixLength, err := strconv.ParseInt(cidrParts[1], 10, 64); err == nil && !data.Ipv4PrefixLength.IsNull() {
data.Ipv4PrefixLength = types.Int64Value(prefixLength)
} else {
data.Ipv4PrefixLength = types.Int64Null()
}
} else {
data.Ipv4Subnet = types.StringNull()
data.Ipv4PrefixLength = types.Int64Null()
}
} else {
data.Ipv4Subnet = types.StringNull()
data.Ipv4PrefixLength = types.Int64Null()
}
}
}
}
}

// End of section. //template:end updateFromBody

// Section below is generated&owned by "gen/generator.go". //template:begin isNull
func (data *IPPoolReservation) isNull(ctx context.Context, res gjson.Result) bool {
if !data.Type.IsNull() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
Expand Down Expand Up @@ -103,10 +104,16 @@ func (r *IPPoolReservationResource) Schema(ctx context.Context, req resource.Sch
"ipv4_prefix_length": schema.Int64Attribute{
MarkdownDescription: helpers.NewAttributeDescription("The IPv4 prefix length is required when `ipv4_prefix` value is `true`.").String,
Optional: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
},
},
"ipv4_subnet": schema.StringAttribute{
MarkdownDescription: helpers.NewAttributeDescription("The IPv4 subnet").String,
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"ipv4_gateway": schema.StringAttribute{
MarkdownDescription: helpers.NewAttributeDescription("The gateway for the IP pool reservation").String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import (
func TestAccCcIPPoolReservation(t *testing.T) {
var checks []resource.TestCheckFunc
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool_reservation.test", "name", "MyRes1"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool_reservation.test", "ipv4_prefix_length", "24"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool_reservation.test", "ipv4_subnet", "172.32.1.0"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool_reservation.test", "ipv4_gateway", "172.32.1.1"))

var steps []resource.TestStep
Expand Down
1 change: 0 additions & 1 deletion internal/provider/resource_catalystcenter_ip_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (
func TestAccCcIPPool(t *testing.T) {
var checks []resource.TestCheckFunc
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool.test", "name", "MyPool1"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool.test", "ip_address_space", "IPv4"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool.test", "type", "generic"))
checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_ip_pool.test", "ip_subnet", "21.1.1.0/24"))

Expand Down
1 change: 1 addition & 0 deletions templates/guides/changelog.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description: |-
- Add `catalystcenter_fabric_l3_virtual_network` resource and data source
- Add `Free Space` allowed value to `rf_model` attribute of `catalystcenter_floor` resource
- Add device unreachability warning to 'delete' implementation of `catalystcenter_fabric_l3_handoff_ip_transit`, `catalystcenter_anycast_gateway`, `catalystcenter_fabric_l2_handoff`, `catalystcenter_fabric_device`, `catalystcenter_fabric_port_assignment` and `catalystcenter_provision_device` resources
- Fix issue with `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/156)

## 0.1.17

Expand Down

0 comments on commit 838bf7c

Please sign in to comment.