diff --git a/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource.go b/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource.go index b4464347ea21..7e11b28a3d23 100644 --- a/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource.go +++ b/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource.go @@ -4,10 +4,12 @@ package dataprotection import ( + "context" "fmt" "log" "time" + "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" @@ -70,7 +72,22 @@ func resourceDataProtectionBackupInstanceBlobStorage() *schema.Resource { Required: true, ValidateFunc: backuppolicies.ValidateBackupPolicyID, }, + + "storage_account_container_names": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, }, + + CustomizeDiff: pluginsdk.CustomDiffWithAll( + // The `storage_account_container_names` can not be removed once specified. + pluginsdk.ForceNewIfChange("storage_account_container_names", func(ctx context.Context, old, new, _ interface{}) bool { + return len(old.([]interface{})) > 0 && len(new.([]interface{})) == 0 + }), + ), } } @@ -124,6 +141,16 @@ func resourceDataProtectionBackupInstanceBlobStorageCreateUpdate(d *schema.Resou }, } + if v, ok := d.GetOk("storage_account_container_names"); ok { + parameters.Properties.PolicyInfo.PolicyParameters = &backupinstances.PolicyParameters{ + BackupDatasourceParametersList: &[]backupinstances.BackupDatasourceParameters{ + backupinstances.BlobBackupDatasourceParameters{ + ContainersList: pointer.From(utils.ExpandStringSlice(v.([]interface{}))), + }, + }, + } + } + if err := client.CreateOrUpdateThenPoll(ctx, id, parameters, backupinstances.DefaultCreateOrUpdateOperationOptions()); err != nil { return fmt.Errorf("creating/updating DataProtection BackupInstance (%q): %+v", id, err) } @@ -175,6 +202,15 @@ func resourceDataProtectionBackupInstanceBlobStorageRead(d *schema.ResourceData, d.Set("storage_account_id", props.DataSourceInfo.ResourceID) d.Set("location", props.DataSourceInfo.ResourceLocation) d.Set("backup_policy_id", props.PolicyInfo.PolicyId) + if policyParas := props.PolicyInfo.PolicyParameters; policyParas != nil { + if dataStoreParas := policyParas.BackupDatasourceParametersList; dataStoreParas != nil { + if dsp := pointer.From(dataStoreParas); len(dsp) > 0 { + if parameter, ok := dsp[0].(backupinstances.BlobBackupDatasourceParameters); ok { + d.Set("storage_account_container_names", utils.FlattenStringSlice(¶meter.ContainersList)) + } + } + } + } } } return nil diff --git a/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource_test.go b/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource_test.go index e4b3144b5ace..15b4f1665eed 100644 --- a/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource_test.go +++ b/internal/services/dataprotection/data_protection_backup_instance_blob_storage_resource_test.go @@ -58,6 +58,13 @@ func TestAccDataProtectionBackupInstanceBlobStorage_complete(t *testing.T) { ), }, data.ImportStep(), + { + Config: r.completeUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), }) } @@ -73,7 +80,7 @@ func TestAccDataProtectionBackupInstanceBlobStorage_update(t *testing.T) { }, data.ImportStep(), { - Config: r.complete(data), + Config: r.basicUpdate(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -111,24 +118,37 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctest-dataprotection-%d" - location = "%s" + name = "acctest-dataprotection-%[1]d" + location = "%[2]s" } resource "azurerm_storage_account" "test" { - name = "acctestsa%d" + name = "acctestsa%[3]d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location account_tier = "Standard" account_replication_type = "LRS" } +resource "azurerm_storage_container" "test" { + name = "testaccsc%[3]d" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "blob" +} + +resource "azurerm_storage_container" "another" { + name = "testaccsc2%[3]d" + storage_account_name = azurerm_storage_account.test.name + container_access_type = "blob" +} + resource "azurerm_data_protection_backup_vault" "test" { - name = "acctest-dataprotection-vault-%d" + name = "acctest-dataprotection-vault-%[1]d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location datastore_type = "VaultStore" redundancy = "LocallyRedundant" + soft_delete = "Off" identity { type = "SystemAssigned" } @@ -141,17 +161,38 @@ resource "azurerm_role_assignment" "test" { } resource "azurerm_data_protection_backup_policy_blob_storage" "test" { - name = "acctest-dbp-%d" - vault_id = azurerm_data_protection_backup_vault.test.id - retention_duration = "P30D" + name = "acctest-dbp-%[1]d" + vault_id = azurerm_data_protection_backup_vault.test.id + operational_default_retention_duration = "P30D" } resource "azurerm_data_protection_backup_policy_blob_storage" "another" { - name = "acctest-dbp-other-%d" - vault_id = azurerm_data_protection_backup_vault.test.id - retention_duration = "P30D" + name = "acctest-dbp-other-%[1]d" + vault_id = azurerm_data_protection_backup_vault.test.id + operational_default_retention_duration = "P30D" +} + +resource "azurerm_data_protection_backup_policy_blob_storage" "hybrid" { + name = "acctest-dbp-hybrid-%[1]d" + vault_id = azurerm_data_protection_backup_vault.test.id + operational_default_retention_duration = "P30D" + + backup_repeating_time_intervals = ["R/2024-05-08T11:30:00+00:00/P1W"] + vault_default_retention_duration = "P7D" + + retention_rule { + name = "Monthly" + priority = 15 + life_cycle { + duration = "P6M" + data_store_type = "VaultStore" + } + criteria { + days_of_month = [1, 2, 0] + } + } } -`, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(8), data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomIntOfLength(8)) } func (r DataProtectionBackupInstanceBlobStorageResource) basic(data acceptance.TestData) string { @@ -170,6 +211,22 @@ resource "azurerm_data_protection_backup_instance_blob_storage" "test" { `, template, data.RandomInteger) } +func (r DataProtectionBackupInstanceBlobStorageResource) basicUpdate(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s +resource "azurerm_data_protection_backup_instance_blob_storage" "test" { + name = "acctest-dbi-%d" + location = azurerm_resource_group.test.location + vault_id = azurerm_data_protection_backup_vault.test.id + storage_account_id = azurerm_storage_account.test.id + backup_policy_id = azurerm_data_protection_backup_policy_blob_storage.another.id + + depends_on = [azurerm_role_assignment.test] +} +`, template, data.RandomInteger) +} + func (r DataProtectionBackupInstanceBlobStorageResource) requiresImport(data acceptance.TestData) string { config := r.basic(data) return fmt.Sprintf(` @@ -191,11 +248,29 @@ func (r DataProtectionBackupInstanceBlobStorageResource) complete(data acceptanc return fmt.Sprintf(` %s resource "azurerm_data_protection_backup_instance_blob_storage" "test" { - name = "acctest-dbi-%d" - location = azurerm_resource_group.test.location - vault_id = azurerm_data_protection_backup_vault.test.id - storage_account_id = azurerm_storage_account.test.id - backup_policy_id = azurerm_data_protection_backup_policy_blob_storage.another.id + name = "acctest-dbi-%d" + location = azurerm_resource_group.test.location + vault_id = azurerm_data_protection_backup_vault.test.id + storage_account_id = azurerm_storage_account.test.id + backup_policy_id = azurerm_data_protection_backup_policy_blob_storage.hybrid.id + storage_account_container_names = [azurerm_storage_container.test.name] + + depends_on = [azurerm_role_assignment.test] +} +`, template, data.RandomInteger) +} + +func (r DataProtectionBackupInstanceBlobStorageResource) completeUpdate(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s +resource "azurerm_data_protection_backup_instance_blob_storage" "test" { + name = "acctest-dbi-%d" + location = azurerm_resource_group.test.location + vault_id = azurerm_data_protection_backup_vault.test.id + storage_account_id = azurerm_storage_account.test.id + backup_policy_id = azurerm_data_protection_backup_policy_blob_storage.hybrid.id + storage_account_container_names = [azurerm_storage_container.another.name] depends_on = [azurerm_role_assignment.test] } diff --git a/website/docs/r/data_protection_backup_instance_blob_storage.html.markdown b/website/docs/r/data_protection_backup_instance_blob_storage.html.markdown index 0450cde57f15..98c08e9f0d67 100644 --- a/website/docs/r/data_protection_backup_instance_blob_storage.html.markdown +++ b/website/docs/r/data_protection_backup_instance_blob_storage.html.markdown @@ -74,6 +74,10 @@ The following arguments are supported: * `backup_policy_id` - (Required) The ID of the Backup Policy. +* `storage_account_container_names` - (Optional) The list of the container names of the source Storage Account. + +-> **Note:** The `storage_account_container_names` should be specified in the vaulted backup policy/operational and vaulted hybrid backup policy. Removing the `storage_account_container_names` will force a new resource to be created since it can't be removed once specified. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: