diff --git a/CHANGELOG.md b/CHANGELOG.md index 39447ca9..6362bd10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.11 (unreleased) + +- Fix issue with import of `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/122) + ## 0.1.10 - Add `catalystcenter_fabric_l2_handoff` resource and data source diff --git a/docs/data-sources/ip_pool_reservation.md b/docs/data-sources/ip_pool_reservation.md index 5f81a152..7a9c6fce 100644 --- a/docs/data-sources/ip_pool_reservation.md +++ b/docs/data-sources/ip_pool_reservation.md @@ -14,8 +14,8 @@ This data source can read the IP Pool Reservation. ```terraform data "catalystcenter_ip_pool_reservation" "example" { - id = "76d24097-41c4-4558-a4d0-a8c07ac08470" site_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1" + name = "MyRes1" } ``` @@ -24,11 +24,12 @@ data "catalystcenter_ip_pool_reservation" "example" { ### Required -- `id` (String) The id of the object +- `name` (String) The name of the IP pool reservation - `site_id` (String) The site ID ### Read-Only +- `id` (String) The id of the object - `ipv4_dhcp_servers` (Set of String) List of DHCP Server IPs - `ipv4_dns_servers` (Set of String) List of DNS Server IPs - `ipv4_gateway` (String) The gateway for the IP pool reservation @@ -46,6 +47,5 @@ data "catalystcenter_ip_pool_reservation" "example" { - `ipv6_prefix_length` (Number) The IPv6 prefix length is required when `ipv6_prefix` value is `true`. - `ipv6_subnet` (String) The IPv6 subnet, for example `2001:db8:85a3:0:100::` - `ipv6_total_host` (Number) The total number of IPv6 hosts -- `name` (String) The name of the IP pool reservation - `slaac_support` (Boolean) Enable SLAAC support - `type` (String) The type of the IP pool reservation diff --git a/docs/guides/changelog.md b/docs/guides/changelog.md index 82fd4862..94f9cb3c 100644 --- a/docs/guides/changelog.md +++ b/docs/guides/changelog.md @@ -7,6 +7,10 @@ description: |- # Changelog +## 0.1.11 (unreleased) + +- Fix issue with import of `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/122) + ## 0.1.10 - Add `catalystcenter_fabric_l2_handoff` resource and data source diff --git a/docs/resources/ip_pool_reservation.md b/docs/resources/ip_pool_reservation.md index a663a5c0..bf3a3548 100644 --- a/docs/resources/ip_pool_reservation.md +++ b/docs/resources/ip_pool_reservation.md @@ -68,5 +68,5 @@ resource "catalystcenter_ip_pool_reservation" "example" { Import is supported using the following syntax: ```shell -terraform import catalystcenter_ip_pool_reservation.example "," +terraform import catalystcenter_ip_pool_reservation.example "," ``` diff --git a/examples/data-sources/catalystcenter_ip_pool_reservation/data-source.tf b/examples/data-sources/catalystcenter_ip_pool_reservation/data-source.tf index 08259a83..f16bdf41 100644 --- a/examples/data-sources/catalystcenter_ip_pool_reservation/data-source.tf +++ b/examples/data-sources/catalystcenter_ip_pool_reservation/data-source.tf @@ -1,4 +1,4 @@ data "catalystcenter_ip_pool_reservation" "example" { - id = "76d24097-41c4-4558-a4d0-a8c07ac08470" site_id = "5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1" + name = "MyRes1" } diff --git a/examples/resources/catalystcenter_ip_pool_reservation/import.sh b/examples/resources/catalystcenter_ip_pool_reservation/import.sh index 3337f06d..e8d5d3a3 100644 --- a/examples/resources/catalystcenter_ip_pool_reservation/import.sh +++ b/examples/resources/catalystcenter_ip_pool_reservation/import.sh @@ -1 +1 @@ -terraform import catalystcenter_ip_pool_reservation.example "," +terraform import catalystcenter_ip_pool_reservation.example "," diff --git a/gen/definitions/ip_pool_reservation.yaml b/gen/definitions/ip_pool_reservation.yaml index 782d0dc1..b3f68372 100644 --- a/gen/definitions/ip_pool_reservation.yaml +++ b/gen/definitions/ip_pool_reservation.yaml @@ -1,21 +1,26 @@ --- name: IP Pool Reservation rest_endpoint: /dna/intent/api/v1/reserve-ip-subpool -get_from_all: true -id_from_query_path: response +id_from_query_path: response.0 +id_from_query_path_attribute: id put_id_query_param: id +import_no_id: true +data_source_no_id: true doc_category: Network Settings attributes: - model_name: siteId type: String query_param: true create_query_path: true + response_data_path: response.0.siteId description: The site ID example: 5e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1 test_value: catalystcenter_area.test.id - model_name: name response_model_name: groupName - response_data_path: groupName + query_param: true + query_param_name: groupName + response_data_path: response.0.groupName type: String match_id: true description: The name of the IP pool reservation @@ -24,6 +29,7 @@ attributes: type: String mandatory: true write_only: true + response_data_path: response.0.type exclude_from_put: true enum_values: [Generic, LAN, WAN, management, service] description: The type of the IP pool reservation @@ -64,19 +70,19 @@ attributes: - model_name: ipv4GateWay tf_name: ipv4_gateway type: String - write_only: true + response_data_path: response.0.ipPools.0.gateways.0 description: The gateway for the IP pool reservation example: 172.32.1.1 - model_name: ipv4DhcpServers type: Set element_type: String - write_only: true + response_data_path: response.0.ipPools.0.dhcpServerIps description: List of DHCP Server IPs example: 1.2.3.4 - model_name: ipv4DnsServers type: Set element_type: String - write_only: true + response_data_path: response.0.ipPools.0.dnsServerIps description: List of DNS Server IPs example: 2.3.4.5 - model_name: ipv6GlobalPool diff --git a/internal/provider/data_source_catalystcenter_ip_pool_reservation.go b/internal/provider/data_source_catalystcenter_ip_pool_reservation.go index e4e23ee9..678db193 100644 --- a/internal/provider/data_source_catalystcenter_ip_pool_reservation.go +++ b/internal/provider/data_source_catalystcenter_ip_pool_reservation.go @@ -60,7 +60,7 @@ func (d *IPPoolReservationDataSource) Schema(ctx context.Context, req datasource Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ MarkdownDescription: "The id of the object", - Required: true, + Computed: true, }, "site_id": schema.StringAttribute{ MarkdownDescription: "The site ID", @@ -68,7 +68,7 @@ func (d *IPPoolReservationDataSource) Schema(ctx context.Context, req datasource }, "name": schema.StringAttribute{ MarkdownDescription: "The name of the IP pool reservation", - Computed: true, + Required: true, }, "type": schema.StringAttribute{ MarkdownDescription: "The type of the IP pool reservation", @@ -178,13 +178,12 @@ func (d *IPPoolReservationDataSource) Read(ctx context.Context, req datasource.R tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) params := "" - params += "?siteId=" + url.QueryEscape(config.SiteId.ValueString()) + params += "?siteId=" + url.QueryEscape(config.SiteId.ValueString()) + "&groupName=" + url.QueryEscape(config.Name.ValueString()) res, err := d.client.Get(config.getPath() + params) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err)) return } - res = res.Get("response.#(id==\"" + config.Id.ValueString() + "\")") config.fromBody(ctx, res) diff --git a/internal/provider/data_source_catalystcenter_ip_pool_reservation_test.go b/internal/provider/data_source_catalystcenter_ip_pool_reservation_test.go index afa0d661..f43389fe 100644 --- a/internal/provider/data_source_catalystcenter_ip_pool_reservation_test.go +++ b/internal/provider/data_source_catalystcenter_ip_pool_reservation_test.go @@ -30,6 +30,7 @@ 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_gateway", "172.32.1.1")) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -79,8 +80,9 @@ func testAccDataSourceCcIPPoolReservationConfig() string { config += ` data "catalystcenter_ip_pool_reservation" "test" { - id = catalystcenter_ip_pool_reservation.test.id site_id = catalystcenter_area.test.id + name = "MyRes1" + depends_on = [catalystcenter_ip_pool_reservation.test] } ` return config diff --git a/internal/provider/model_catalystcenter_ip_pool_reservation.go b/internal/provider/model_catalystcenter_ip_pool_reservation.go index 43e59434..c8668fd8 100644 --- a/internal/provider/model_catalystcenter_ip_pool_reservation.go +++ b/internal/provider/model_catalystcenter_ip_pool_reservation.go @@ -21,6 +21,7 @@ package provider import ( "context" + "github.com/CiscoDevNet/terraform-provider-catalystcenter/internal/provider/helpers" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/tidwall/gjson" "github.com/tidwall/sjson" @@ -146,31 +147,64 @@ func (data IPPoolReservation) toBody(ctx context.Context, state IPPoolReservatio // Section below is generated&owned by "gen/generator.go". //template:begin fromBody func (data *IPPoolReservation) fromBody(ctx context.Context, res gjson.Result) { - if value := res.Get("groupName"); value.Exists() { + // Retrieve the 'id' attribute, if Data Source doesn't require id + if value := res.Get("response.0.id"); value.Exists() { + data.Id = types.StringValue(value.String()) + } else { + data.Id = types.StringNull() + } + if value := res.Get("response.0.groupName"); value.Exists() { 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 = 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) + } } // 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("groupName"); value.Exists() && !data.Name.IsNull() { + 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) + } } // 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.Name.IsNull() { - return false - } if !data.Type.IsNull() { return false } diff --git a/internal/provider/resource_catalystcenter_ip_pool_reservation.go b/internal/provider/resource_catalystcenter_ip_pool_reservation.go index 8af9da4e..3de967c5 100644 --- a/internal/provider/resource_catalystcenter_ip_pool_reservation.go +++ b/internal/provider/resource_catalystcenter_ip_pool_reservation.go @@ -202,13 +202,13 @@ func (r *IPPoolReservationResource) Create(ctx context.Context, req resource.Cre return } params = "" - params += "?siteId=" + url.QueryEscape(plan.SiteId.ValueString()) + params += "?siteId=" + url.QueryEscape(plan.SiteId.ValueString()) + "&groupName=" + url.QueryEscape(plan.Name.ValueString()) res, err = r.client.Get(plan.getPath() + params) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String())) return } - plan.Id = types.StringValue(res.Get("response.#(groupName==\"" + plan.Name.ValueString() + "\").id").String()) + plan.Id = types.StringValue(res.Get("response.0.id").String()) tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) @@ -232,7 +232,7 @@ func (r *IPPoolReservationResource) Read(ctx context.Context, req resource.ReadR tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) params := "" - params += "?siteId=" + url.QueryEscape(state.SiteId.ValueString()) + params += "?siteId=" + url.QueryEscape(state.SiteId.ValueString()) + "&groupName=" + url.QueryEscape(state.Name.ValueString()) res, err := r.client.Get(state.getPath() + params) if err != nil && strings.Contains(err.Error(), "StatusCode 404") { resp.State.RemoveResource(ctx) @@ -241,7 +241,6 @@ func (r *IPPoolReservationResource) Read(ctx context.Context, req resource.ReadR resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String())) return } - res = res.Get("response.#(id==\"" + state.Id.ValueString() + "\")") // If every attribute is set to null we are dealing with an import operation and therefore reading all attributes if state.isNull(ctx, res) { @@ -327,12 +326,12 @@ func (r *IPPoolReservationResource) ImportState(ctx context.Context, req resourc if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { resp.Diagnostics.AddError( "Unexpected Import Identifier", - fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), + fmt.Sprintf("Expected import identifier with format: ,. Got: %q", req.ID), ) return } resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("site_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[1])...) } // End of section. //template:end import diff --git a/internal/provider/resource_catalystcenter_ip_pool_reservation_test.go b/internal/provider/resource_catalystcenter_ip_pool_reservation_test.go index a2d73a37..51cb461c 100644 --- a/internal/provider/resource_catalystcenter_ip_pool_reservation_test.go +++ b/internal/provider/resource_catalystcenter_ip_pool_reservation_test.go @@ -31,6 +31,7 @@ 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_gateway", "172.32.1.1")) var steps []resource.TestStep if os.Getenv("SKIP_MINIMUM_TEST") == "" { diff --git a/templates/guides/changelog.md.tmpl b/templates/guides/changelog.md.tmpl index 82fd4862..94f9cb3c 100644 --- a/templates/guides/changelog.md.tmpl +++ b/templates/guides/changelog.md.tmpl @@ -7,6 +7,10 @@ description: |- # Changelog +## 0.1.11 (unreleased) + +- Fix issue with import of `catalystcenter_ip_pool_reservation` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/122) + ## 0.1.10 - Add `catalystcenter_fabric_l2_handoff` resource and data source