diff --git a/internal/services/recoveryservices/backup_protected_vm_resource.go b/internal/services/recoveryservices/backup_protected_vm_resource.go index 7724e3dfd344..7520eb42a4af 100644 --- a/internal/services/recoveryservices/backup_protected_vm_resource.go +++ b/internal/services/recoveryservices/backup_protected_vm_resource.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/recoveryservices/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -63,6 +64,26 @@ func resourceRecoveryServicesBackupProtectedVM() *pluginsdk.Resource { ValidateFunc: azure.ValidateResourceID, }, + "exclude_disk_luns": { + Type: pluginsdk.TypeSet, + ConflictsWith: []string{"include_disk_luns"}, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + ValidateFunc: validation.IntAtLeast(0), + }, + }, + + "include_disk_luns": { + Type: pluginsdk.TypeSet, + ConflictsWith: []string{"exclude_disk_luns"}, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + ValidateFunc: validation.IntAtLeast(0), + }, + }, + "tags": tags.Schema(), }, } @@ -107,12 +128,13 @@ func resourceRecoveryServicesBackupProtectedVMCreateUpdate(d *pluginsdk.Resource item := backup.ProtectedItemResource{ Tags: tags.Expand(t), Properties: &backup.AzureIaaSComputeVMProtectedItem{ - PolicyID: &policyId, - ProtectedItemType: backup.ProtectedItemTypeMicrosoftClassicComputevirtualMachines, - WorkloadType: backup.DataSourceTypeVM, - SourceResourceID: utils.String(vmId), - FriendlyName: utils.String(parsedVmId.Name), - VirtualMachineID: utils.String(vmId), + PolicyID: &policyId, + ProtectedItemType: backup.ProtectedItemTypeMicrosoftClassicComputevirtualMachines, + WorkloadType: backup.DataSourceTypeVM, + SourceResourceID: utils.String(vmId), + FriendlyName: utils.String(parsedVmId.Name), + ExtendedProperties: expandDiskExclusion(d), + VirtualMachineID: utils.String(vmId), }, } @@ -163,6 +185,18 @@ func resourceRecoveryServicesBackupProtectedVMRead(d *pluginsdk.ResourceData, me if v := vm.PolicyID; v != nil { d.Set("backup_policy_id", strings.Replace(*v, "Subscriptions", "subscriptions", 1)) } + + if v := vm.ExtendedProperties; v != nil && v.DiskExclusionProperties != nil { + if *v.DiskExclusionProperties.IsInclusionList { + if err := d.Set("include_disk_luns", utils.FlattenInt32Slice(v.DiskExclusionProperties.DiskLunList)); err != nil { + return fmt.Errorf("setting include_disk_luns: %+v", err) + } + } else { + if err := d.Set("exclude_disk_luns", utils.FlattenInt32Slice(v.DiskExclusionProperties.DiskLunList)); err != nil { + return fmt.Errorf("setting exclude_disk_luns: %+v", err) + } + } + } } } @@ -268,3 +302,36 @@ func resourceRecoveryServicesBackupProtectedVMRefreshFunc(ctx context.Context, c return resp, "Found", nil } } + +func expandDiskExclusion(d *pluginsdk.ResourceData) *backup.ExtendedProperties { + if v, ok := d.GetOk("include_disk_luns"); ok { + var diskLun = expandDiskLunList(v.(*pluginsdk.Set).List()) + + return &backup.ExtendedProperties{ + DiskExclusionProperties: &backup.DiskExclusionProperties{ + DiskLunList: utils.ExpandInt32Slice(diskLun), + IsInclusionList: utils.Bool(true), + }, + } + } + + if v, ok := d.GetOk("exclude_disk_luns"); ok { + var diskLun = expandDiskLunList(v.(*pluginsdk.Set).List()) + + return &backup.ExtendedProperties{ + DiskExclusionProperties: &backup.DiskExclusionProperties{ + DiskLunList: utils.ExpandInt32Slice(diskLun), + IsInclusionList: utils.Bool(false), + }, + } + } + return nil +} + +func expandDiskLunList(input []interface{}) []interface{} { + result := make([]interface{}, 0, len(input)) + for _, v := range input { + result = append(result, v.(int)) + } + return result +} diff --git a/internal/services/recoveryservices/backup_protected_vm_resource_test.go b/internal/services/recoveryservices/backup_protected_vm_resource_test.go index ae39823f4ec7..fee98e7fe172 100644 --- a/internal/services/recoveryservices/backup_protected_vm_resource_test.go +++ b/internal/services/recoveryservices/backup_protected_vm_resource_test.go @@ -119,6 +119,38 @@ func TestAccBackupProtectedVm_updateBackupPolicyId(t *testing.T) { }) } +func TestAccBackupProtectedVm_updateDiskExclusion(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_backup_protected_vm", "test") + r := BackupProtectedVmResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + ), + }, + data.ImportStep(), + { + Config: r.updateDiskExclusion(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + ), + }, + data.ImportStep(), + }) +} + func (t BackupProtectedVmResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ProtectedItemID(state.ID) if err != nil { @@ -200,7 +232,7 @@ resource "azurerm_virtual_machine" "test" { name = "acctestvm" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name - vm_size = "Standard_A0" + vm_size = "Standard_D1_v2" network_interface_ids = [azurerm_network_interface.test.id] storage_image_reference { @@ -226,6 +258,14 @@ resource "azurerm_virtual_machine" "test" { lun = 0 } + storage_data_disk { + name = "acctest-another-datadisk" + create_option = "Empty" + disk_size_gb = "1" + lun = 1 + managed_disk_type = "Standard_LRS" + } + os_profile { computer_name = "acctest" admin_username = "vmadmin" @@ -277,6 +317,23 @@ resource "azurerm_backup_protected_vm" "test" { recovery_vault_name = azurerm_recovery_services_vault.test.name source_vm_id = azurerm_virtual_machine.test.id backup_policy_id = azurerm_backup_policy_vm.test.id + + include_disk_luns = [0] +} +`, r.base(data)) +} + +func (r BackupProtectedVmResource) updateDiskExclusion(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_backup_protected_vm" "test" { + resource_group_name = azurerm_resource_group.test.name + recovery_vault_name = azurerm_recovery_services_vault.test.name + source_vm_id = azurerm_virtual_machine.test.id + backup_policy_id = azurerm_backup_policy_vm.test.id + + exclude_disk_luns = [0, 1] } `, r.base(data)) } diff --git a/website/docs/r/backup_protected_vm.html.markdown b/website/docs/r/backup_protected_vm.html.markdown index 5e8debb7576d..f7aca9ea25ba 100644 --- a/website/docs/r/backup_protected_vm.html.markdown +++ b/website/docs/r/backup_protected_vm.html.markdown @@ -56,6 +56,10 @@ The following arguments are supported: * `backup_policy_id` - (Required) Specifies the id of the backup policy to use. +* `exclude_disk_luns` - (Optional) A list of Disks' Logical Unit Numbers(LUN) to be excluded for VM Protection. + +* `include_disk_luns` - (Optional) A list of Disks' Logical Unit Numbers(LUN) to be included for VM Protection. + * `tags` - (Optional) A mapping of tags to assign to the resource. ## Attributes Reference