From cc9a3aab335b8cb5d3bf0b2767553be56a272ab7 Mon Sep 17 00:00:00 2001 From: kuba-mazurkiewicz Date: Fri, 19 Jul 2024 07:55:58 +0200 Subject: [PATCH] BREAKING CHANGE: Modified `fabric_site` resource to use `/dna/intent/api/v1/sda/fabricSites` API endpoint this resource now only works with Catalyst Center version 2.3.7.5+ --- .gitignore | 2 + CHANGELOG.md | 1 + docs/data-sources/fabric_site.md | 7 ++- docs/guides/changelog.md | 1 + docs/resources/fabric_site.md | 22 +++---- .../catalystcenter_fabric_site/data-source.tf | 2 +- .../catalystcenter_fabric_site/import.sh | 2 +- .../catalystcenter_fabric_site/resource.tf | 5 +- gen/definitions/fabric_site.yaml | 51 ++++++++++------ .../data_source_catalystcenter_fabric_site.go | 31 +++++----- ..._source_catalystcenter_fabric_site_test.go | 7 ++- .../model_catalystcenter_fabric_site.go | 61 ++++++++++++++----- .../resource_catalystcenter_fabric_site.go | 49 +++++++++------ ...esource_catalystcenter_fabric_site_test.go | 17 +++++- templates/guides/changelog.md.tmpl | 1 + 15 files changed, 168 insertions(+), 91 deletions(-) diff --git a/.gitignore b/.gitignore index e86159ff..9997bb87 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,5 @@ log*.txt .terraform.lock.hcl # Transient Terraform backend lock .terraform.tfstate.lock.info + +.envrc diff --git a/CHANGELOG.md b/CHANGELOG.md index d17fe91c..a4d1f472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 0.1.10 (unreleased) +- BREAKING CHANGE: Modified `fabric_site` resource to use `/dna/intent/api/v1/sda/fabricSites` API endpoint, this resource now only works with Catalyst Center version 2.3.7.5+ - Fix issue with mandatory attributes in `transit_peer_network` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/92) - BREAKING CHANGE: Fix `ip_pool` update if more than 25 pools are registered - BREAKING CHANGE: Rename `radio_type_a_power_treshold_v1` attribute of `catalystcenter_wireless_rf_profile` resource to `radio_type_a_power_threshold_v1` diff --git a/docs/data-sources/fabric_site.md b/docs/data-sources/fabric_site.md index 1016b88d..840eab46 100644 --- a/docs/data-sources/fabric_site.md +++ b/docs/data-sources/fabric_site.md @@ -14,7 +14,7 @@ This data source can read the Fabric Site. ```terraform data "catalystcenter_fabric_site" "example" { - id = "Global/Site1" + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" } ``` @@ -24,8 +24,9 @@ data "catalystcenter_fabric_site" "example" { ### Optional - `id` (String) The id of the object -- `site_name_hierarchy` (String) Existing site name hierarchy available at global level +- `site_id` (String) ID of the network hierarchy ### Read-Only -- `fabric_type` (String) Type of SD-Access Fabric +- `authentication_profile_name` (String) Authentication profile used for this fabric +- `pub_sub_enabled` (Boolean) Specifies whether this fabric site will use pub/sub for control nodes diff --git a/docs/guides/changelog.md b/docs/guides/changelog.md index ee616efa..109b28ee 100644 --- a/docs/guides/changelog.md +++ b/docs/guides/changelog.md @@ -9,6 +9,7 @@ description: |- ## 0.1.10 (unreleased) +- BREAKING CHANGE: Modified `fabric_site` resource to use `/dna/intent/api/v1/sda/fabricSites` API endpoint, this resource now only works with Catalyst Center version 2.3.7.5+ - Fix issue with mandatory attributes in `transit_peer_network` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/92) - BREAKING CHANGE: Fix `ip_pool` update if more than 25 pools are registered - BREAKING CHANGE: Rename `radio_type_a_power_treshold_v1` attribute of `catalystcenter_wireless_rf_profile` resource to `radio_type_a_power_threshold_v1` diff --git a/docs/resources/fabric_site.md b/docs/resources/fabric_site.md index 82b1d721..638f9931 100644 --- a/docs/resources/fabric_site.md +++ b/docs/resources/fabric_site.md @@ -3,19 +3,20 @@ page_title: "catalystcenter_fabric_site Resource - terraform-provider-catalystcenter" subcategory: "SDA" description: |- - This resource can manage a Fabric Site. + Manages Fabric Sites --- # catalystcenter_fabric_site (Resource) -This resource can manage a Fabric Site. +Manages Fabric Sites ## Example Usage ```terraform resource "catalystcenter_fabric_site" "example" { - site_name_hierarchy = "Global/Site1" - fabric_type = "FABRIC_SITE" + site_id = "8e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1" + authentication_profile_name = "No Authentication" + pub_sub_enabled = false } ``` @@ -24,13 +25,10 @@ resource "catalystcenter_fabric_site" "example" { ### Required -- `site_name_hierarchy` (String) Existing site name hierarchy available at global level - -### Optional - -- `fabric_type` (String) Type of SD-Access Fabric - - Choices: `FABRIC_SITE`, `FABRIC_ZONE` - - Default value: `FABRIC_SITE` +- `authentication_profile_name` (String) Authentication profile used for this fabric + - Choices: `Closed Authentication`, `Low Impact`, `No Authentication`, `Open Authentication` +- `pub_sub_enabled` (Boolean) Specifies whether this fabric site will use pub/sub for control nodes +- `site_id` (String) ID of the network hierarchy ### Read-Only @@ -41,5 +39,5 @@ resource "catalystcenter_fabric_site" "example" { Import is supported using the following syntax: ```shell -terraform import catalystcenter_fabric_site.example "" +terraform import catalystcenter_fabric_site.example "" ``` diff --git a/examples/data-sources/catalystcenter_fabric_site/data-source.tf b/examples/data-sources/catalystcenter_fabric_site/data-source.tf index f101ef29..686f5fb4 100644 --- a/examples/data-sources/catalystcenter_fabric_site/data-source.tf +++ b/examples/data-sources/catalystcenter_fabric_site/data-source.tf @@ -1,3 +1,3 @@ data "catalystcenter_fabric_site" "example" { - id = "Global/Site1" + id = "76d24097-41c4-4558-a4d0-a8c07ac08470" } diff --git a/examples/resources/catalystcenter_fabric_site/import.sh b/examples/resources/catalystcenter_fabric_site/import.sh index 30a78af1..43aaafc4 100644 --- a/examples/resources/catalystcenter_fabric_site/import.sh +++ b/examples/resources/catalystcenter_fabric_site/import.sh @@ -1 +1 @@ -terraform import catalystcenter_fabric_site.example "" +terraform import catalystcenter_fabric_site.example "" diff --git a/examples/resources/catalystcenter_fabric_site/resource.tf b/examples/resources/catalystcenter_fabric_site/resource.tf index 62f3bf59..c7de85ae 100644 --- a/examples/resources/catalystcenter_fabric_site/resource.tf +++ b/examples/resources/catalystcenter_fabric_site/resource.tf @@ -1,4 +1,5 @@ resource "catalystcenter_fabric_site" "example" { - site_name_hierarchy = "Global/Site1" - fabric_type = "FABRIC_SITE" + site_id = "8e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1" + authentication_profile_name = "No Authentication" + pub_sub_enabled = false } diff --git a/gen/definitions/fabric_site.yaml b/gen/definitions/fabric_site.yaml index 8b360273..23027f0e 100644 --- a/gen/definitions/fabric_site.yaml +++ b/gen/definitions/fabric_site.yaml @@ -1,28 +1,41 @@ --- name: Fabric Site -rest_endpoint: /dna/intent/api/v1/business/sda/fabric-site -id_from_attribute: true -id_query_param: siteNameHierarchy -delete_id_query_param: siteNameHierarchy -no_update: true -skip_minimum_test: true +rest_endpoint: /dna/intent/api/v1/sda/fabricSites +get_rest_endpoint: /dna/intent/api/v1/sda/fabricSites?limit=500 +res_description: Manages Fabric Sites +id_from_query_path: response +get_from_all: true +put_id_include_path: "0.id" +put_no_id: true doc_category: SDA attributes: - - model_name: siteNameHierarchy - type: String - id: true + - model_name: siteId + requires_replace: true + data_path: '0' + match_id: true data_source_query: true - description: Existing site name hierarchy available at global level - example: Global/Site1 - test_value: '"${catalystcenter_area.test.parent_name}/${catalystcenter_area.test.name}"' - - model_name: fabricType + response_data_path: siteId + mandatory: true + type: String + description: ID of the network hierarchy + example: 8e6f7b3a-2b0b-4a7d-8b1c-0d4b1cd5e1b1 + test_value: catalystcenter_area.test.id + - model_name: authenticationProfileName + data_path: '0' + response_data_path: authenticationProfileName + mandatory: true type: String - description: Type of SD-Access Fabric - enum_values: [FABRIC_SITE, FABRIC_ZONE] - write_only: true # when configuring FABRIC_SITE, GET return FABRIC_LAN (v2.3.7.4) - requires_replace: true # PUT not implemented - example: FABRIC_SITE - default_value: FABRIC_SITE + description: Authentication profile used for this fabric + enum_values: [Closed Authentication, Low Impact, No Authentication, Open Authentication] + example: No Authentication + - model_name: isPubSubEnabled + data_path: '0' + response_data_path: isPubSubEnabled + tf_name: pub_sub_enabled + type: Bool + mandatory: true + description: Specifies whether this fabric site will use pub/sub for control nodes + example: false test_prerequisites: | resource "catalystcenter_area" "test" { name = "Area 1" diff --git a/internal/provider/data_source_catalystcenter_fabric_site.go b/internal/provider/data_source_catalystcenter_fabric_site.go index a2096594..2750df1a 100644 --- a/internal/provider/data_source_catalystcenter_fabric_site.go +++ b/internal/provider/data_source_catalystcenter_fabric_site.go @@ -21,7 +21,6 @@ package provider import ( "context" "fmt" - "net/url" "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" @@ -66,13 +65,17 @@ func (d *FabricSiteDataSource) Schema(ctx context.Context, req datasource.Schema Optional: true, Computed: true, }, - "site_name_hierarchy": schema.StringAttribute{ - MarkdownDescription: "Existing site name hierarchy available at global level", + "site_id": schema.StringAttribute{ + MarkdownDescription: "ID of the network hierarchy", Optional: true, Computed: true, }, - "fabric_type": schema.StringAttribute{ - MarkdownDescription: "Type of SD-Access Fabric", + "authentication_profile_name": schema.StringAttribute{ + MarkdownDescription: "Authentication profile used for this fabric", + Computed: true, + }, + "pub_sub_enabled": schema.BoolAttribute{ + MarkdownDescription: "Specifies whether this fabric site will use pub/sub for control nodes", Computed: true, }, }, @@ -82,7 +85,7 @@ func (d *FabricSiteDataSource) ConfigValidators(ctx context.Context) []datasourc return []datasource.ConfigValidator{ datasourcevalidator.ExactlyOneOf( path.MatchRoot("id"), - path.MatchRoot("site_name_hierarchy"), + path.MatchRoot("site_id"), ), } } @@ -109,17 +112,17 @@ func (d *FabricSiteDataSource) Read(ctx context.Context, req datasource.ReadRequ } tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String())) - if config.Id.IsNull() && !config.SiteNameHierarchy.IsNull() { - res, err := d.client.Get(config.getPath()) + if config.Id.IsNull() && !config.SiteId.IsNull() { + res, err := d.client.Get("/dna/intent/api/v1/sda/fabricSites?limit=500") if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err)) return } - if value := res; len(value.Array()) > 0 { + if value := res.Get("response"); len(value.Array()) > 0 { value.ForEach(func(k, v gjson.Result) bool { - if config.SiteNameHierarchy.ValueString() == v.Get("siteNameHierarchy").String() { + if config.SiteId.ValueString() == v.Get("siteId").String() { config.Id = types.StringValue(v.Get("id").String()) - tflog.Debug(ctx, fmt.Sprintf("%s: Found object with siteNameHierarchy '%v', id: %v", config.Id.String(), config.SiteNameHierarchy.ValueString(), config.Id.String())) + tflog.Debug(ctx, fmt.Sprintf("%s: Found object with siteId '%v', id: %v", config.Id.String(), config.SiteId.ValueString(), config.Id.String())) return false } return true @@ -127,18 +130,18 @@ func (d *FabricSiteDataSource) Read(ctx context.Context, req datasource.ReadRequ } if config.Id.IsNull() { - resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with siteNameHierarchy: %s", config.SiteNameHierarchy.ValueString())) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with siteId: %s", config.SiteId.ValueString())) return } } params := "" - params += "?siteNameHierarchy=" + url.QueryEscape(config.Id.ValueString()) - res, err := d.client.Get(config.getPath() + params) + res, err := d.client.Get("/dna/intent/api/v1/sda/fabricSites?limit=500" + 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_fabric_site_test.go b/internal/provider/data_source_catalystcenter_fabric_site_test.go index fe1eb29e..9c6225df 100644 --- a/internal/provider/data_source_catalystcenter_fabric_site_test.go +++ b/internal/provider/data_source_catalystcenter_fabric_site_test.go @@ -29,6 +29,8 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource func TestAccDataSourceCcFabricSite(t *testing.T) { var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_site.test", "authentication_profile_name", "No Authentication")) + checks = append(checks, resource.TestCheckResourceAttr("data.catalystcenter_fabric_site.test", "pub_sub_enabled", "false")) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, @@ -56,8 +58,9 @@ resource "catalystcenter_area" "test" { // Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig func testAccDataSourceCcFabricSiteConfig() string { config := `resource "catalystcenter_fabric_site" "test" {` + "\n" - config += ` site_name_hierarchy = "${catalystcenter_area.test.parent_name}/${catalystcenter_area.test.name}"` + "\n" - config += ` fabric_type = "FABRIC_SITE"` + "\n" + config += ` site_id = catalystcenter_area.test.id` + "\n" + config += ` authentication_profile_name = "No Authentication"` + "\n" + config += ` pub_sub_enabled = false` + "\n" config += `}` + "\n" config += ` diff --git a/internal/provider/model_catalystcenter_fabric_site.go b/internal/provider/model_catalystcenter_fabric_site.go index f2ef80db..f99c7fdb 100644 --- a/internal/provider/model_catalystcenter_fabric_site.go +++ b/internal/provider/model_catalystcenter_fabric_site.go @@ -30,16 +30,17 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin types type FabricSite struct { - Id types.String `tfsdk:"id"` - SiteNameHierarchy types.String `tfsdk:"site_name_hierarchy"` - FabricType types.String `tfsdk:"fabric_type"` + Id types.String `tfsdk:"id"` + SiteId types.String `tfsdk:"site_id"` + AuthenticationProfileName types.String `tfsdk:"authentication_profile_name"` + PubSubEnabled types.Bool `tfsdk:"pub_sub_enabled"` } // End of section. //template:end types // Section below is generated&owned by "gen/generator.go". //template:begin getPath func (data FabricSite) getPath() string { - return "/dna/intent/api/v1/business/sda/fabric-site" + return "/dna/intent/api/v1/sda/fabricSites" } // End of section. //template:end getPath @@ -54,13 +55,17 @@ func (data FabricSite) toBody(ctx context.Context, state FabricSite) string { put := false if state.Id.ValueString() != "" { put = true + body, _ = sjson.Set(body, "0.id", state.Id.ValueString()) } _ = put - if !data.SiteNameHierarchy.IsNull() { - body, _ = sjson.Set(body, "siteNameHierarchy", data.SiteNameHierarchy.ValueString()) + if !data.SiteId.IsNull() { + body, _ = sjson.Set(body, "0.siteId", data.SiteId.ValueString()) } - if !data.FabricType.IsNull() { - body, _ = sjson.Set(body, "fabricType", data.FabricType.ValueString()) + if !data.AuthenticationProfileName.IsNull() { + body, _ = sjson.Set(body, "0.authenticationProfileName", data.AuthenticationProfileName.ValueString()) + } + if !data.PubSubEnabled.IsNull() { + body, _ = sjson.Set(body, "0.isPubSubEnabled", data.PubSubEnabled.ValueBool()) } return body } @@ -69,10 +74,20 @@ func (data FabricSite) toBody(ctx context.Context, state FabricSite) string { // Section below is generated&owned by "gen/generator.go". //template:begin fromBody func (data *FabricSite) fromBody(ctx context.Context, res gjson.Result) { - if value := res.Get("siteNameHierarchy"); value.Exists() { - data.SiteNameHierarchy = types.StringValue(value.String()) + if value := res.Get("siteId"); value.Exists() { + data.SiteId = types.StringValue(value.String()) + } else { + data.SiteId = types.StringNull() + } + if value := res.Get("authenticationProfileName"); value.Exists() { + data.AuthenticationProfileName = types.StringValue(value.String()) } else { - data.SiteNameHierarchy = types.StringNull() + data.AuthenticationProfileName = types.StringNull() + } + if value := res.Get("isPubSubEnabled"); value.Exists() { + data.PubSubEnabled = types.BoolValue(value.Bool()) + } else { + data.PubSubEnabled = types.BoolNull() } } @@ -80,10 +95,20 @@ func (data *FabricSite) fromBody(ctx context.Context, res gjson.Result) { // Section below is generated&owned by "gen/generator.go". //template:begin updateFromBody func (data *FabricSite) updateFromBody(ctx context.Context, res gjson.Result) { - if value := res.Get("siteNameHierarchy"); value.Exists() && !data.SiteNameHierarchy.IsNull() { - data.SiteNameHierarchy = types.StringValue(value.String()) + if value := res.Get("siteId"); value.Exists() && !data.SiteId.IsNull() { + data.SiteId = types.StringValue(value.String()) + } else { + data.SiteId = types.StringNull() + } + if value := res.Get("authenticationProfileName"); value.Exists() && !data.AuthenticationProfileName.IsNull() { + data.AuthenticationProfileName = types.StringValue(value.String()) } else { - data.SiteNameHierarchy = types.StringNull() + data.AuthenticationProfileName = types.StringNull() + } + if value := res.Get("isPubSubEnabled"); value.Exists() && !data.PubSubEnabled.IsNull() { + data.PubSubEnabled = types.BoolValue(value.Bool()) + } else { + data.PubSubEnabled = types.BoolNull() } } @@ -91,7 +116,13 @@ func (data *FabricSite) updateFromBody(ctx context.Context, res gjson.Result) { // Section below is generated&owned by "gen/generator.go". //template:begin isNull func (data *FabricSite) isNull(ctx context.Context, res gjson.Result) bool { - if !data.FabricType.IsNull() { + if !data.SiteId.IsNull() { + return false + } + if !data.AuthenticationProfileName.IsNull() { + return false + } + if !data.PubSubEnabled.IsNull() { return false } return true diff --git a/internal/provider/resource_catalystcenter_fabric_site.go b/internal/provider/resource_catalystcenter_fabric_site.go index 544369fc..935eeec6 100644 --- a/internal/provider/resource_catalystcenter_fabric_site.go +++ b/internal/provider/resource_catalystcenter_fabric_site.go @@ -30,7 +30,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -61,7 +60,7 @@ func (r *FabricSiteResource) Metadata(ctx context.Context, req resource.Metadata func (r *FabricSiteResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ // This description is used by the documentation generator and the language server. - MarkdownDescription: helpers.NewAttributeDescription("This resource can manage a Fabric Site.").String, + MarkdownDescription: helpers.NewAttributeDescription("Manages Fabric Sites").String, Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -71,25 +70,24 @@ func (r *FabricSiteResource) Schema(ctx context.Context, req resource.SchemaRequ stringplanmodifier.UseStateForUnknown(), }, }, - "site_name_hierarchy": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Existing site name hierarchy available at global level").String, + "site_id": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("ID of the network hierarchy").String, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "fabric_type": schema.StringAttribute{ - MarkdownDescription: helpers.NewAttributeDescription("Type of SD-Access Fabric").AddStringEnumDescription("FABRIC_SITE", "FABRIC_ZONE").AddDefaultValueDescription("FABRIC_SITE").String, - Optional: true, - Computed: true, + "authentication_profile_name": schema.StringAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Authentication profile used for this fabric").AddStringEnumDescription("Closed Authentication", "Low Impact", "No Authentication", "Open Authentication").String, + Required: true, Validators: []validator.String{ - stringvalidator.OneOf("FABRIC_SITE", "FABRIC_ZONE"), - }, - Default: stringdefault.StaticString("FABRIC_SITE"), - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringvalidator.OneOf("Closed Authentication", "Low Impact", "No Authentication", "Open Authentication"), }, }, + "pub_sub_enabled": schema.BoolAttribute{ + MarkdownDescription: helpers.NewAttributeDescription("Specifies whether this fabric site will use pub/sub for control nodes").String, + Required: true, + }, }, } } @@ -126,7 +124,13 @@ func (r *FabricSiteResource) Create(ctx context.Context, req resource.CreateRequ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST), got error: %s, %s", err, res.String())) return } - plan.Id = types.StringValue(fmt.Sprint(plan.SiteNameHierarchy.ValueString())) + params = "" + res, err = r.client.Get("/dna/intent/api/v1/sda/fabricSites?limit=500" + 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.#(siteId==\"" + plan.SiteId.ValueString() + "\").id").String()) tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString())) @@ -150,8 +154,7 @@ func (r *FabricSiteResource) Read(ctx context.Context, req resource.ReadRequest, tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String())) params := "" - params += "?siteNameHierarchy=" + url.QueryEscape(state.Id.ValueString()) - res, err := r.client.Get(state.getPath() + params) + res, err := r.client.Get("/dna/intent/api/v1/sda/fabricSites?limit=500" + params) if err != nil && strings.Contains(err.Error(), "StatusCode 404") { resp.State.RemoveResource(ctx) return @@ -159,6 +162,7 @@ func (r *FabricSiteResource) Read(ctx context.Context, req resource.ReadRequest, 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) { @@ -194,6 +198,14 @@ func (r *FabricSiteResource) Update(ctx context.Context, req resource.UpdateRequ tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString())) + body := plan.toBody(ctx, state) + params := "" + res, err := r.client.Put(plan.getPath()+params, body) + if err != nil { + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String())) + return + } + tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString())) diags = resp.State.Set(ctx, &plan) @@ -214,7 +226,7 @@ func (r *FabricSiteResource) Delete(ctx context.Context, req resource.DeleteRequ } tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString())) - res, err := r.client.Delete(state.getPath() + "?siteNameHierarchy=" + url.QueryEscape(state.Id.ValueString())) + res, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString())) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String())) return @@ -234,11 +246,10 @@ func (r *FabricSiteResource) ImportState(ctx context.Context, req resource.Impor if len(idParts) != 1 || idParts[0] == "" { 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_name_hierarchy"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[0])...) } diff --git a/internal/provider/resource_catalystcenter_fabric_site_test.go b/internal/provider/resource_catalystcenter_fabric_site_test.go index 1ce71556..8a56092d 100644 --- a/internal/provider/resource_catalystcenter_fabric_site_test.go +++ b/internal/provider/resource_catalystcenter_fabric_site_test.go @@ -19,6 +19,7 @@ package provider // Section below is generated&owned by "gen/generator.go". //template:begin imports import ( + "os" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -29,8 +30,15 @@ import ( // Section below is generated&owned by "gen/generator.go". //template:begin testAcc func TestAccCcFabricSite(t *testing.T) { var checks []resource.TestCheckFunc + checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_site.test", "authentication_profile_name", "No Authentication")) + checks = append(checks, resource.TestCheckResourceAttr("catalystcenter_fabric_site.test", "pub_sub_enabled", "false")) var steps []resource.TestStep + if os.Getenv("SKIP_MINIMUM_TEST") == "" { + steps = append(steps, resource.TestStep{ + Config: testAccCcFabricSitePrerequisitesConfig + testAccCcFabricSiteConfig_minimum(), + }) + } steps = append(steps, resource.TestStep{ Config: testAccCcFabricSitePrerequisitesConfig + testAccCcFabricSiteConfig_all(), Check: resource.ComposeTestCheckFunc(checks...), @@ -62,7 +70,9 @@ resource "catalystcenter_area" "test" { // Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal func testAccCcFabricSiteConfig_minimum() string { config := `resource "catalystcenter_fabric_site" "test" {` + "\n" - config += ` site_name_hierarchy = "${catalystcenter_area.test.parent_name}/${catalystcenter_area.test.name}"` + "\n" + config += ` site_id = catalystcenter_area.test.id` + "\n" + config += ` authentication_profile_name = "No Authentication"` + "\n" + config += ` pub_sub_enabled = false` + "\n" config += `}` + "\n" return config } @@ -72,8 +82,9 @@ func testAccCcFabricSiteConfig_minimum() string { // Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll func testAccCcFabricSiteConfig_all() string { config := `resource "catalystcenter_fabric_site" "test" {` + "\n" - config += ` site_name_hierarchy = "${catalystcenter_area.test.parent_name}/${catalystcenter_area.test.name}"` + "\n" - config += ` fabric_type = "FABRIC_SITE"` + "\n" + config += ` site_id = catalystcenter_area.test.id` + "\n" + config += ` authentication_profile_name = "No Authentication"` + "\n" + config += ` pub_sub_enabled = false` + "\n" config += `}` + "\n" return config } diff --git a/templates/guides/changelog.md.tmpl b/templates/guides/changelog.md.tmpl index ee616efa..109b28ee 100644 --- a/templates/guides/changelog.md.tmpl +++ b/templates/guides/changelog.md.tmpl @@ -9,6 +9,7 @@ description: |- ## 0.1.10 (unreleased) +- BREAKING CHANGE: Modified `fabric_site` resource to use `/dna/intent/api/v1/sda/fabricSites` API endpoint, this resource now only works with Catalyst Center version 2.3.7.5+ - Fix issue with mandatory attributes in `transit_peer_network` resource, [link](https://github.com/CiscoDevNet/terraform-provider-catalystcenter/issues/92) - BREAKING CHANGE: Fix `ip_pool` update if more than 25 pools are registered - BREAKING CHANGE: Rename `radio_type_a_power_treshold_v1` attribute of `catalystcenter_wireless_rf_profile` resource to `radio_type_a_power_threshold_v1`