From 7807dabace74b49328cef6d03d165fd8dfb18b12 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 4 Jun 2024 16:52:06 +0200 Subject: [PATCH] `azurerm_advisor_recommendations`: Add new filters --- CHANGELOG.md | 1 + .../advisor_recommendations_data_source.go | 32 +++++++++++- ...dvisor_recommendations_data_source_test.go | 50 ++++++++++++++++++- .../d/advisor_recommendations.html.markdown | 6 +++ 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41c5d915eda67..85991d98c1312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ENHANCEMENTS: * dependencies: updating to `v0.20240603.1145333` of `github.com/hashicorp/go-azure-sdk` [GH-26197] * `advisor`: update API version to `2023-01-01` [GH-26205] +* `keyvault`: handling the Resources API returning Key Vaults that have been deleted when populating the cache [GH-26199] * `machinelearning`: update API version to `2024-04-01` [GH-26168] * `azurerm_container_app_job`: support new properties `key_vault_secret_id` and `identity` in `secret` block [GH-25969] * `azurerm_notification_hub_authorization_rule` - add support for `primary_connection_string` and `secondary_connection_string` properties [GH-26188] diff --git a/internal/services/advisor/advisor_recommendations_data_source.go b/internal/services/advisor/advisor_recommendations_data_source.go index e6f8ebf9c3ed8..90f85a743a3d0 100644 --- a/internal/services/advisor/advisor_recommendations_data_source.go +++ b/internal/services/advisor/advisor_recommendations_data_source.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-sdk/resource-manager/advisor/2023-01-01/getrecommendations" + "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -44,6 +45,23 @@ func dataSourceAdvisorRecommendations() *pluginsdk.Resource { "filter_by_resource_groups": commonschema.ResourceGroupNameSetOptional(), + "filter_by_resource_ids": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: azure.ValidateResourceID, + }, + }, + + "filter_by_recommendation_type_guids": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "recommendations": { Type: pluginsdk.TypeList, Computed: true, @@ -59,6 +77,11 @@ func dataSourceAdvisorRecommendations() *pluginsdk.Resource { Computed: true, }, + "id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "impact": { Type: pluginsdk.TypeString, Computed: true, @@ -117,6 +140,12 @@ func dataSourceAdvisorRecommendationsRead(d *pluginsdk.ResourceData, meta interf if resGroups := expandAzureRmAdvisorRecommendationsMapString("ResourceGroup", d.Get("filter_by_resource_groups").(*pluginsdk.Set).List()); resGroups != "" { filterList = append(filterList, resGroups) } + if resIDs := expandAzureRmAdvisorRecommendationsMapString("ResourceId", d.Get("filter_by_resource_ids").(*pluginsdk.Set).List()); resIDs != "" { + filterList = append(filterList, resIDs) + } + if recommendationTypeGuids := expandAzureRmAdvisorRecommendationsMapString("RecommendationTypeGuid", d.Get("filter_by_recommendation_type_guids").(*pluginsdk.Set).List()); recommendationTypeGuids != "" { + filterList = append(filterList, recommendationTypeGuids) + } opts := getrecommendations.RecommendationsListOperationOptions{} if len(filterList) > 0 { @@ -132,7 +161,7 @@ func dataSourceAdvisorRecommendationsRead(d *pluginsdk.ResourceData, meta interf return fmt.Errorf("setting `recommendations`: %+v", err) } - d.SetId(fmt.Sprintf("avdisor/recommendations/%s", time.Now().UTC().String())) + d.SetId(fmt.Sprintf("advisor/recommendations/%s", time.Now().UTC().String())) return nil } @@ -161,6 +190,7 @@ func flattenAzureRmAdvisorRecommendations(recommends []getrecommendations.Resour result = append(result, map[string]interface{}{ "category": string(pointer.From(v.Category)), "description": description, + "id": pointer.From(r.Id), "impact": string(pointer.From(v.Impact)), "recommendation_name": pointer.From(r.Name), "recommendation_type_id": pointer.From(v.RecommendationTypeId), diff --git a/internal/services/advisor/advisor_recommendations_data_source_test.go b/internal/services/advisor/advisor_recommendations_data_source_test.go index f18191a64309f..15fce7c9842f3 100644 --- a/internal/services/advisor/advisor_recommendations_data_source_test.go +++ b/internal/services/advisor/advisor_recommendations_data_source_test.go @@ -23,6 +23,7 @@ func TestAccAdvisorRecommendationsDataSource_basic(t *testing.T) { check.That(data.ResourceName).Key("recommendations.#").Exists(), check.That(data.ResourceName).Key("recommendations.0.category").Exists(), check.That(data.ResourceName).Key("recommendations.0.description").Exists(), + check.That(data.ResourceName).Key("recommendations.0.id").Exists(), check.That(data.ResourceName).Key("recommendations.0.impact").Exists(), check.That(data.ResourceName).Key("recommendations.0.recommendation_name").Exists(), check.That(data.ResourceName).Key("recommendations.0.recommendation_type_id").Exists(), @@ -61,6 +62,20 @@ func TestAccAdvisorRecommendationsDataSource_categoriesFilter(t *testing.T) { }) } +func TestAccAdvisorRecommendationsDataSource_resourceFilter(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_advisor_recommendations", "test") + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: AdvisorRecommendationsDataSourceTests{}.resourceFilterConfig(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("recommendations.#").Exists(), + check.That(data.ResourceName).Key("recommendations.0.category").HasValue("Cost"), + ), + }, + }) +} + func (AdvisorRecommendationsDataSourceTests) basicConfig() string { return `provider "azurerm" { features {} @@ -93,8 +108,10 @@ resource "azurerm_storage_account" "test" { } data "azurerm_advisor_recommendations" "test" { - filter_by_category = ["Security"] - filter_by_resource_groups = [azurerm_resource_group.test.name] + filter_by_category = ["Security"] + filter_by_resource_groups = [azurerm_resource_group.test.name] + filter_by_resource_ids = [azurerm_storage_account.test.id] + filter_by_recommendation_type_guids = ["42dbf883-9e4b-4f84-9da4-232b87c4b5e9"] } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } @@ -109,3 +126,32 @@ data "azurerm_advisor_recommendations" "test" { } ` } + +// Advisor generated recommendations needs long time to take effects, sometimes up to one day or more, +// Please refer to the issue https://github.com/Azure/azure-rest-api-specs/issues/9284 +// So here we get an empty list of recommendations +func (AdvisorRecommendationsDataSourceTests) resourceFilterConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-advisor-%d" + location = "%s" +} + +resource "azurerm_storage_account" "test" { + name = "accteststr%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + enable_https_traffic_only = false + account_tier = "Standard" + account_replication_type = "LRS" +} + +data "azurerm_advisor_recommendations" "test" { + filter_by_resource_ids = [azurerm_storage_account.test.id] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/website/docs/d/advisor_recommendations.html.markdown b/website/docs/d/advisor_recommendations.html.markdown index 20bd7918f3d86..903c4291bdba5 100644 --- a/website/docs/d/advisor_recommendations.html.markdown +++ b/website/docs/d/advisor_recommendations.html.markdown @@ -35,6 +35,10 @@ The following arguments are supported: * `filter_by_resource_groups` - (Optional) Specifies a list of resource groups about which the Advisor Recommendations will be listed. +* `filter_by_resource_ids` - (Optional) Specifies a list of resource about which the Advisor Recommendations will be listed. + +* `filter_by_recommendation_type_guids` - (Optional) Specifies a list of recommendation types about which the Advisor Recommendations will be listed. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: @@ -51,6 +55,8 @@ A `recommendations` block exports the following: * `description` - The description of the issue or the opportunity identified by the recommendation. +* `id` - The name of the Advisor Recommendation. + * `impact` - The business impact of the recommendation. * `recommendation_name` - The name of the Advisor Recommendation.