diff --git a/internal/services/securitycenter/security_center_subscription_pricing_resource.go b/internal/services/securitycenter/security_center_subscription_pricing_resource.go index 63ab47a216b7..8e8c51c5387f 100644 --- a/internal/services/securitycenter/security_center_subscription_pricing_resource.go +++ b/internal/services/securitycenter/security_center_subscription_pricing_resource.go @@ -107,7 +107,6 @@ func resourceSecurityCenterSubscriptionPricing() *pluginsdk.Resource { } func resourceSecurityCenterSubscriptionPricingUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).SecurityCenter.PricingClient subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) @@ -148,15 +147,27 @@ func resourceSecurityCenterSubscriptionPricingUpdate(d *pluginsdk.ResourceData, if vSub, okSub := d.GetOk("subplan"); okSub { pricing.Properties.SubPlan = utils.String(vSub.(string)) } + + // When the state file contains an `extension` with `additional_extension_properties` + // But the tf config does not, `d.Get("extension")` will contain a zero element. + // Tracked by https://github.com/hashicorp/terraform-plugin-sdk/issues/1248 + realCfgExtensions := make([]interface{}, 0) + for _, e := range d.Get("extension").(*pluginsdk.Set).List() { + v := e.(map[string]interface{}) + if v["name"] != "" { + realCfgExtensions = append(realCfgExtensions, e) + } + } + if d.HasChange("extension") { // can not set extensions for free tier if pricing.Properties.PricingTier == pricings_v2023_01_01.PricingTierStandard { - var extensions = expandSecurityCenterSubscriptionPricingExtensions(d.Get("extension").(*pluginsdk.Set).List(), &extensionsStatusFromBackend) + extensions := expandSecurityCenterSubscriptionPricingExtensions(realCfgExtensions, &extensionsStatusFromBackend) pricing.Properties.Extensions = extensions } } - if len(d.Get("extension").(*pluginsdk.Set).List()) > 0 && pricing.Properties.PricingTier == pricings_v2023_01_01.PricingTierFree { + if len(realCfgExtensions) > 0 && pricing.Properties.PricingTier == pricings_v2023_01_01.PricingTierFree { return fmt.Errorf("extensions cannot be enabled when using free tier") } @@ -173,7 +184,7 @@ func resourceSecurityCenterSubscriptionPricingUpdate(d *pluginsdk.ResourceData, // after turning on the bundle, we have now the extensions list if d.IsNewResource() || isCurrentlyInFree { - var extensions = expandSecurityCenterSubscriptionPricingExtensions(d.Get("extension").(*pluginsdk.Set).List(), &extensionsStatusFromBackend) + extensions := expandSecurityCenterSubscriptionPricingExtensions(realCfgExtensions, &extensionsStatusFromBackend) pricing.Properties.Extensions = extensions _, updateErr := client.Update(ctx, id, pricing) if err != nil { @@ -248,8 +259,8 @@ func resourceSecurityCenterSubscriptionPricingDelete(d *pluginsdk.ResourceData, } func expandSecurityCenterSubscriptionPricingExtensions(inputList []interface{}, extensionsStatusFromBackend *[]pricings_v2023_01_01.Extension) *[]pricings_v2023_01_01.Extension { - var extensionStatuses = map[string]bool{} - var extensionProperties = map[string]*interface{}{} + extensionStatuses := map[string]bool{} + extensionProperties := map[string]*interface{}{} var outputList []pricings_v2023_01_01.Extension if extensionsStatusFromBackend != nil { @@ -291,7 +302,6 @@ func expandSecurityCenterSubscriptionPricingExtensions(inputList []interface{}, } func flattenExtensions(inputList *[]pricings_v2023_01_01.Extension) []interface{} { - outputList := make([]interface{}, 0) if inputList == nil { diff --git a/internal/services/securitycenter/security_center_subscription_pricing_resource_test.go b/internal/services/securitycenter/security_center_subscription_pricing_resource_test.go index 79c80bd6520e..cc068d58218e 100644 --- a/internal/services/securitycenter/security_center_subscription_pricing_resource_test.go +++ b/internal/services/securitycenter/security_center_subscription_pricing_resource_test.go @@ -49,11 +49,22 @@ func TestAccServerVulnerabilityAssessment(t *testing.T) { }) } +func TestAccSecurityCenterSubscriptionPricing_cloudPosture(t *testing.T) { + // These tests will change pricing tier of cloud posture + acceptance.RunTestsInSequence(t, map[string]map[string]func(t *testing.T){ + "securityCenterSubscriptionPricing": { + "basic": testAccSecurityCenterSubscriptionPricing_cloudPostureExtension, + "standardToFree": testAccSecurityCenterSubscriptionPricing_cloudPostureExtensionStandardToFreeExtensions, + "freeToStandard": testAccSecurityCenterSubscriptionPricing_cloudPostureExtensionFreeToStandardDisabledExtensions, + }, + }) +} + func TestAccSecurityCenterSubscriptionPricing_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.tier("Standard", "AppServices"), Check: acceptance.ComposeTestCheckFunc( @@ -69,7 +80,7 @@ func TestAccSecurityCenterSubscriptionPricing_cosmosDbs(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.tier("Standard", "CosmosDbs"), Check: acceptance.ComposeTestCheckFunc( @@ -85,7 +96,7 @@ func TestAccSecurityCenterSubscriptionPricing_storageAccountSubplan(t *testing.T data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.storageAccountSubplan(), Check: acceptance.ComposeTestCheckFunc( @@ -98,11 +109,11 @@ func TestAccSecurityCenterSubscriptionPricing_storageAccountSubplan(t *testing.T }) } -func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtension(t *testing.T) { +func testAccSecurityCenterSubscriptionPricing_cloudPostureExtension(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.cloudPostureExtension(), Check: acceptance.ComposeTestCheckFunc( @@ -135,15 +146,15 @@ func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtension(t *testing.T }) } -func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtensionFreeToStandardDisabledExtensions(t *testing.T) { +func testAccSecurityCenterSubscriptionPricing_cloudPostureExtensionFreeToStandardDisabledExtensions(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.cloudPostureFree(), Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), + // for `free` tier it can not be checked if exist check.That(data.ResourceName).Key("tier").HasValue("Free"), check.That(data.ResourceName).Key("resource_type").HasValue("CloudPosture"), ), @@ -162,11 +173,11 @@ func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtensionFreeToStandar }) } -func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtensioStandardToFreeExtensions(t *testing.T) { +func testAccSecurityCenterSubscriptionPricing_cloudPostureExtensionStandardToFreeExtensions(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_security_center_subscription_pricing", "test") r := SecurityCenterSubscriptionPricingResource{} - data.ResourceSequentialTestSkipCheckDestroyed(t, []acceptance.TestStep{ + data.ResourceSequentialTest(t, r, []acceptance.TestStep{ { Config: r.cloudPostureExtension(), Check: acceptance.ComposeTestCheckFunc( @@ -180,7 +191,7 @@ func TestAccSecurityCenterSubscriptionPricing_cloudPostureExtensioStandardToFree { Config: r.cloudPostureFree(), Check: acceptance.ComposeTestCheckFunc( - check.That(data.ResourceName).ExistsInAzure(r), + // The existence can not be checked, the Exists() takes `free` as non-exist. check.That(data.ResourceName).Key("tier").HasValue("Free"), check.That(data.ResourceName).Key("resource_type").HasValue("CloudPosture"), check.That(data.ResourceName).Key("extension.#").HasValue("0"), @@ -201,7 +212,7 @@ func (SecurityCenterSubscriptionPricingResource) Exists(ctx context.Context, cli return nil, fmt.Errorf("retrieving %s: %+v", *id, err) } - return utils.Bool(resp.Model.Properties != nil), nil + return utils.Bool(resp.Model.Properties != nil && resp.Model.Properties.PricingTier != pricings_v2023_01_01.PricingTierFree), nil } func (SecurityCenterSubscriptionPricingResource) tier(tier string, resource_type string) string {