From 252b9e5d7f2000f641a49d974d6439548c1bb2e6 Mon Sep 17 00:00:00 2001 From: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:35:29 +0800 Subject: [PATCH] `azurerm_data_protection_backup_vault` : support new property `cross_region_restore_enabled` (#27197) --- .../data_protection_backup_vault_resource.go | 41 +++++++++++++++++++ ...a_protection_backup_vault_resource_test.go | 30 ++++++++++++++ ...data_protection_backup_vault.html.markdown | 4 ++ 3 files changed, 75 insertions(+) diff --git a/internal/services/dataprotection/data_protection_backup_vault_resource.go b/internal/services/dataprotection/data_protection_backup_vault_resource.go index a5e7be76fa48..93259ed969d2 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_resource.go +++ b/internal/services/dataprotection/data_protection_backup_vault_resource.go @@ -71,6 +71,11 @@ func resourceDataProtectionBackupVault() *pluginsdk.Resource { }, false), }, + "cross_region_restore_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "identity": commonschema.SystemAssignedIdentityOptional(), "retention_duration_in_days": { @@ -94,6 +99,21 @@ func resourceDataProtectionBackupVault() *pluginsdk.Resource { pluginsdk.ForceNewIfChange("soft_delete", func(ctx context.Context, old, new, meta interface{}) bool { return old.(string) == string(backupvaults.SoftDeleteStateAlwaysOn) && new.(string) != string(backupvaults.SoftDeleteStateAlwaysOn) }), + + // Once `cross_region_restore_enabled` is enabled it cannot be disabled. + pluginsdk.ForceNewIfChange("cross_region_restore_enabled", func(ctx context.Context, old, new, meta interface{}) bool { + return old.(bool) && new.(bool) != old.(bool) + }), + + pluginsdk.CustomizeDiffShim(func(ctx context.Context, d *pluginsdk.ResourceDiff, v interface{}) error { + redundancy := d.Get("redundancy").(string) + crossRegionRestore := d.GetRawConfig().AsValueMap()["cross_region_restore_enabled"] + if !crossRegionRestore.IsNull() && redundancy != string(backupvaults.StorageSettingTypesGeoRedundant) { + // Cross region restore is only allowed on `GeoRedundant` vault. + return fmt.Errorf("`cross_region_restore_enabled` can only be specified when `redundancy` is specified for `GeoRedundant`.") + } + return nil + }), ), } @@ -175,6 +195,17 @@ func resourceDataProtectionBackupVaultCreateUpdate(d *pluginsdk.ResourceData, me Tags: expandTags(d.Get("tags").(map[string]interface{})), } + if !pluginsdk.IsExplicitlyNullInConfig(d, "cross_region_restore_enabled") { + parameters.Properties.FeatureSettings = &backupvaults.FeatureSettings{ + CrossRegionRestoreSettings: &backupvaults.CrossRegionRestoreSettings{}, + } + if d.Get("cross_region_restore_enabled").(bool) { + parameters.Properties.FeatureSettings.CrossRegionRestoreSettings.State = pointer.To(backupvaults.CrossRegionRestoreStateEnabled) + } else { + parameters.Properties.FeatureSettings.CrossRegionRestoreSettings.State = pointer.To(backupvaults.CrossRegionRestoreStateDisabled) + } + } + if v, ok := d.GetOk("retention_duration_in_days"); ok { parameters.Properties.SecuritySettings.SoftDeleteSettings.RetentionDurationInDays = pointer.To(v.(float64)) } @@ -223,6 +254,16 @@ func resourceDataProtectionBackupVaultRead(d *pluginsdk.ResourceData, meta inter d.Set("retention_duration_in_days", pointer.From(softDelete.RetentionDurationInDays)) } } + crossRegionStoreEnabled := false + if featureSetting := model.Properties.FeatureSettings; featureSetting != nil { + if featureSetting := model.Properties.FeatureSettings; featureSetting != nil { + if pointer.From(featureSetting.CrossRegionRestoreSettings.State) == backupvaults.CrossRegionRestoreStateEnabled { + crossRegionStoreEnabled = true + } + } + } + + d.Set("cross_region_restore_enabled", crossRegionStoreEnabled) if err = d.Set("identity", flattenBackupVaultDppIdentityDetails(model.Identity)); err != nil { return fmt.Errorf("setting `identity`: %+v", err) diff --git a/internal/services/dataprotection/data_protection_backup_vault_resource_test.go b/internal/services/dataprotection/data_protection_backup_vault_resource_test.go index acc75c8793e1..31a7b0bd2469 100644 --- a/internal/services/dataprotection/data_protection_backup_vault_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_vault_resource_test.go @@ -33,6 +33,20 @@ func TestAccDataProtectionBackupVault_basic(t *testing.T) { }) } +func TestAccDataProtectionBackupVault_crossRegionRestore(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_data_protection_backup_vault", "test") + r := DataProtectionBackupVaultResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.crossRegionRestore(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccDataProtectionBackupVault_zoneRedundant(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_data_protection_backup_vault", "test") r := DataProtectionBackupVaultResource{} @@ -178,6 +192,22 @@ resource "azurerm_data_protection_backup_vault" "test" { `, template, data.RandomInteger) } +func (r DataProtectionBackupVaultResource) crossRegionRestore(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_data_protection_backup_vault" "test" { + name = "acctest-bv-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + datastore_type = "VaultStore" + redundancy = "GeoRedundant" + cross_region_restore_enabled = true +} +`, template, data.RandomInteger) +} + func (r DataProtectionBackupVaultResource) requiresImport(data acceptance.TestData) string { config := r.basic(data) return fmt.Sprintf(` diff --git a/website/docs/r/data_protection_backup_vault.html.markdown b/website/docs/r/data_protection_backup_vault.html.markdown index ac374ba87211..df58c302a2b3 100644 --- a/website/docs/r/data_protection_backup_vault.html.markdown +++ b/website/docs/r/data_protection_backup_vault.html.markdown @@ -43,6 +43,10 @@ The following arguments are supported: * `redundancy` - (Required) Specifies the backup storage redundancy. Possible values are `GeoRedundant`, `LocallyRedundant` and `ZoneRedundant`. Changing this forces a new Backup Vault to be created. +* `cross_region_restore_enabled` - (Optional) Whether to enable cross-region restore for the Backup Vault. + +-> **Note:** The `cross_region_restore_enabled` can only be specified when `redundancy` is specified for `GeoRedundant`. Once `cross_region_restore_enabled` is enabled, it cannot be disabled. + --- * `identity` - (Optional) An `identity` block as defined below.