Skip to content

Commit

Permalink
azurerm_backup_protected_vm - protection can now be suspended during …
Browse files Browse the repository at this point in the history
…destroy (#27950)

* azurerm_backup_protected_vm - protection can now be suspended during destroy

* make terrafmt

* fix unit tests

* fix unit tests

* Update internal/services/recoveryservices/backup_protected_vm_resource.go

Co-authored-by: Matthew Frahry <mbfrahry@gmail.com>

* fix test with duplicate azurerm provider block

* Fix TestAccBackupProtectedVm_protectionSuspendedOnDestroy

* Address review

---------

Co-authored-by: Matthew Frahry <mbfrahry@gmail.com>
  • Loading branch information
katbyte and mbfrahry authored Jan 21, 2025
1 parent 7f0b79b commit d40831d
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 44 deletions.
5 changes: 3 additions & 2 deletions internal/features/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ func Default() UserFeatures {
PurgeSoftDeletedWorkspaceOnDestroy: false,
},
RecoveryService: RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
VMBackupStopProtectionAndRetainDataOnDestroy: false,
VMBackupSuspendProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
NetApp: NetAppFeatures{
DeleteBackupsOnBackupVaultDestroy: false,
Expand Down
5 changes: 3 additions & 2 deletions internal/features/user_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ type MachineLearningFeatures struct {
}

type RecoveryServiceFeatures struct {
VMBackupStopProtectionAndRetainDataOnDestroy bool
PurgeProtectedItemsFromVaultOnDestroy bool
VMBackupStopProtectionAndRetainDataOnDestroy bool
VMBackupSuspendProtectionAndRetainDataOnDestroy bool
PurgeProtectedItemsFromVaultOnDestroy bool
}

type NetAppFeatures struct {
Expand Down
18 changes: 15 additions & 3 deletions internal/provider/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,16 @@ func schemaFeatures(supportLegacyTestSuite bool) *pluginsdk.Schema {
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"vm_backup_stop_protection_and_retain_data_on_destroy": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
ExactlyOneOf: []string{"features.0.recovery_service.0.vm_backup_stop_protection_and_retain_data_on_destroy", "features.0.recovery_service.0.vm_backup_suspend_protection_and_retain_data_on_destroy"},
},
"vm_backup_suspend_protection_and_retain_data_on_destroy": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
ExactlyOneOf: []string{"features.0.recovery_service.0.vm_backup_stop_protection_and_retain_data_on_destroy", "features.0.recovery_service.0.vm_backup_suspend_protection_and_retain_data_on_destroy"},
},
"purge_protected_items_from_vault_on_destroy": {
Type: pluginsdk.TypeBool,
Expand Down Expand Up @@ -417,6 +424,8 @@ func schemaFeatures(supportLegacyTestSuite bool) *pluginsdk.Schema {
return &pluginsdk.Schema{
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
MinItems: 1,
Elem: &pluginsdk.Resource{
Schema: featuresMap,
},
Expand Down Expand Up @@ -664,6 +673,9 @@ func expandFeatures(input []interface{}) features.UserFeatures {
if v, ok := recoveryServicesRaw["vm_backup_stop_protection_and_retain_data_on_destroy"]; ok {
featuresMap.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy = v.(bool)
}
if v, ok := recoveryServicesRaw["vm_backup_suspend_protection_and_retain_data_on_destroy"]; ok {
featuresMap.RecoveryService.VMBackupSuspendProtectionAndRetainDataOnDestroy = v.(bool)
}
if v, ok := recoveryServicesRaw["purge_protected_items_from_vault_on_destroy"]; ok {
featuresMap.RecoveryService.PurgeProtectedItemsFromVaultOnDestroy = v.(bool)
}
Expand Down
50 changes: 30 additions & 20 deletions internal/provider/features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ func TestExpandFeatures(t *testing.T) {
PurgeSoftDeletedWorkspaceOnDestroy: false,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
VMBackupStopProtectionAndRetainDataOnDestroy: false,
VMBackupSuspendProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
NetApp: features.NetAppFeatures{
DeleteBackupsOnBackupVaultDestroy: false,
Expand Down Expand Up @@ -201,8 +202,9 @@ func TestExpandFeatures(t *testing.T) {
},
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": true,
"purge_protected_items_from_vault_on_destroy": true,
"vm_backup_stop_protection_and_retain_data_on_destroy": true,
"vm_backup_suspend_protection_and_retain_data_on_destroy": true,
"purge_protected_items_from_vault_on_destroy": true,
},
},
"netapp": []interface{}{
Expand Down Expand Up @@ -281,8 +283,9 @@ func TestExpandFeatures(t *testing.T) {
PurgeSoftDeletedWorkspaceOnDestroy: true,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
VMBackupStopProtectionAndRetainDataOnDestroy: true,
VMBackupSuspendProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
},
NetApp: features.NetAppFeatures{
DeleteBackupsOnBackupVaultDestroy: true,
Expand Down Expand Up @@ -394,8 +397,9 @@ func TestExpandFeatures(t *testing.T) {
},
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": false,
"purge_protected_items_from_vault_on_destroy": false,
"vm_backup_stop_protection_and_retain_data_on_destroy": false,
"vm_backup_suspend_protection_and_retain_data_on_destroy": false,
"purge_protected_items_from_vault_on_destroy": false,
},
},
"netapp": []interface{}{
Expand Down Expand Up @@ -474,8 +478,9 @@ func TestExpandFeatures(t *testing.T) {
PurgeSoftDeletedWorkspaceOnDestroy: false,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
VMBackupStopProtectionAndRetainDataOnDestroy: false,
VMBackupSuspendProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
NetApp: features.NetAppFeatures{
DeleteBackupsOnBackupVaultDestroy: false,
Expand Down Expand Up @@ -1716,8 +1721,9 @@ func TestExpandFeaturesRecoveryService(t *testing.T) {
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
VMBackupStopProtectionAndRetainDataOnDestroy: false,
VMBackupSuspendProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
Expand All @@ -1727,16 +1733,18 @@ func TestExpandFeaturesRecoveryService(t *testing.T) {
map[string]interface{}{
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": true,
"purge_protected_items_from_vault_on_destroy": true,
"vm_backup_stop_protection_and_retain_data_on_destroy": true,
"vm_backup_suspend_protection_and_retain_data_on_destroy": true,
"purge_protected_items_from_vault_on_destroy": true,
},
},
},
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
VMBackupStopProtectionAndRetainDataOnDestroy: true,
VMBackupSuspendProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
},
},
},
Expand All @@ -1746,16 +1754,18 @@ func TestExpandFeaturesRecoveryService(t *testing.T) {
map[string]interface{}{
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": false,
"purge_protected_items_from_vault_on_destroy": false,
"vm_backup_stop_protection_and_retain_data_on_destroy": false,
"vm_backup_suspend_protection_and_retain_data_on_destroy": false,
"purge_protected_items_from_vault_on_destroy": false,
},
},
},
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
VMBackupStopProtectionAndRetainDataOnDestroy: false,
VMBackupSuspendProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions internal/provider/framework/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@ func (p *ProviderConfig) Load(ctx context.Context, data *ProviderModel, tfVersio
f.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy = feature[0].VMBackupStopProtectionAndRetainDataOnDestroy.ValueBool()
}

f.RecoveryService.VMBackupSuspendProtectionAndRetainDataOnDestroy = false
if !feature[0].VMBackupSuspendProtectionAndRetainDataOnDestroy.IsNull() && !feature[0].VMBackupSuspendProtectionAndRetainDataOnDestroy.IsUnknown() {
f.RecoveryService.VMBackupSuspendProtectionAndRetainDataOnDestroy = feature[0].VMBackupSuspendProtectionAndRetainDataOnDestroy.ValueBool()
}

f.RecoveryService.PurgeProtectedItemsFromVaultOnDestroy = false
if !feature[0].PurgeProtectedItemsFromVaultOnDestroy.IsNull() && !feature[0].PurgeProtectedItemsFromVaultOnDestroy.IsUnknown() {
f.RecoveryService.PurgeProtectedItemsFromVaultOnDestroy = feature[0].PurgeProtectedItemsFromVaultOnDestroy.ValueBool()
Expand Down
16 changes: 11 additions & 5 deletions internal/provider/framework/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,11 @@ func TestProviderConfig_LoadDefault(t *testing.T) {
}

if features.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy {
t.Errorf("expected recver_services.vm_backup_stop_protection_and_retain_data_on_destroy to be false")
t.Errorf("expected recovery_service.vm_backup_stop_protection_and_retain_data_on_destroy to be false")
}

if features.RecoveryService.VMBackupSuspendProtectionAndRetainDataOnDestroy {
t.Errorf("expected recovery_service.vm_backup_suspend_protection_and_retain_data_on_destroy to be false")
}

if features.RecoveryService.PurgeProtectedItemsFromVaultOnDestroy {
Expand Down Expand Up @@ -306,14 +310,16 @@ func defaultFeaturesList() types.List {
machineLearningList, _ := basetypes.NewListValue(types.ObjectType{}.WithAttributeTypes(MachineLearningAttributes), []attr.Value{machineLearning})

recoveryServices, _ := basetypes.NewObjectValueFrom(context.Background(), RecoveryServiceAttributes, map[string]attr.Value{
"vm_backup_stop_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"purge_protected_items_from_vault_on_destroy": basetypes.NewBoolNull(),
"vm_backup_stop_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"vm_backup_suspend_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"purge_protected_items_from_vault_on_destroy": basetypes.NewBoolNull(),
})
recoveryServicesList, _ := basetypes.NewListValue(types.ObjectType{}.WithAttributeTypes(RecoveryServiceAttributes), []attr.Value{recoveryServices})

recoveryServicesVaults, _ := basetypes.NewObjectValueFrom(context.Background(), RecoveryServiceVaultsAttributes, map[string]attr.Value{
"vm_backup_stop_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"purge_protected_items_from_vault_on_destroy": basetypes.NewBoolNull(),
"vm_backup_stop_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"vm_backup_suspend_protection_and_retain_data_on_destroy": basetypes.NewBoolNull(),
"purge_protected_items_from_vault_on_destroy": basetypes.NewBoolNull(),
})
recoveryServicesVaultsList, _ := basetypes.NewListValue(types.ObjectType{}.WithAttributeTypes(RecoveryServiceVaultsAttributes), []attr.Value{recoveryServicesVaults})

Expand Down
10 changes: 6 additions & 4 deletions internal/provider/framework/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,15 @@ var MachineLearningAttributes = map[string]attr.Type{
}

type RecoveryService struct {
VMBackupStopProtectionAndRetainDataOnDestroy types.Bool `tfsdk:"vm_backup_stop_protection_and_retain_data_on_destroy"`
PurgeProtectedItemsFromVaultOnDestroy types.Bool `tfsdk:"purge_protected_items_from_vault_on_destroy"`
VMBackupStopProtectionAndRetainDataOnDestroy types.Bool `tfsdk:"vm_backup_stop_protection_and_retain_data_on_destroy"`
VMBackupSuspendProtectionAndRetainDataOnDestroy types.Bool `tfsdk:"vm_backup_suspend_protection_and_retain_data_on_destroy"`
PurgeProtectedItemsFromVaultOnDestroy types.Bool `tfsdk:"purge_protected_items_from_vault_on_destroy"`
}

var RecoveryServiceAttributes = map[string]attr.Type{
"vm_backup_stop_protection_and_retain_data_on_destroy": types.BoolType,
"purge_protected_items_from_vault_on_destroy": types.BoolType,
"vm_backup_stop_protection_and_retain_data_on_destroy": types.BoolType,
"vm_backup_suspend_protection_and_retain_data_on_destroy": types.BoolType,
"purge_protected_items_from_vault_on_destroy": types.BoolType,
}

type RecoveryServiceVaults struct {
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/framework/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,9 @@ func (p *azureRmFrameworkProvider) Schema(_ context.Context, _ provider.SchemaRe
"vm_backup_stop_protection_and_retain_data_on_destroy": schema.BoolAttribute{
Optional: true,
},
"vm_backup_suspend_protection_and_retain_data_on_destroy": schema.BoolAttribute{
Optional: true,
},
"purge_protected_items_from_vault_on_destroy": schema.BoolAttribute{
Optional: true,
},
Expand Down
18 changes: 12 additions & 6 deletions internal/services/recoveryservices/backup_protected_vm_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@ func resourceRecoveryServicesBackupProtectedVMDelete(d *pluginsdk.ResourceData,
return err
}

if meta.(*clients.Client).Features.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy {
features := meta.(*clients.Client).Features.RecoveryService

if features.VMBackupStopProtectionAndRetainDataOnDestroy || features.VMBackupSuspendProtectionAndRetainDataOnDestroy {
log.Printf("[DEBUG] Retaining Data and Stopping Protection for %s", id)

existing, err := client.Get(ctx, *id, protecteditems.GetOperationOptions{})
Expand All @@ -370,19 +372,24 @@ func resourceRecoveryServicesBackupProtectedVMDelete(d *pluginsdk.ResourceData,
return fmt.Errorf("making Read request on %s: %+v", id, err)
}

desiredState := protecteditems.ProtectionStateProtectionStopped
if features.VMBackupSuspendProtectionAndRetainDataOnDestroy {
desiredState = protecteditems.ProtectionStateBackupsSuspended
}

if model := existing.Model; model != nil {
if properties := model.Properties; properties != nil {
if vm, ok := properties.(protecteditems.AzureIaaSComputeVMProtectedItem); ok {
updateInput := protecteditems.ProtectedItemResource{
Properties: &protecteditems.AzureIaaSComputeVMProtectedItem{
ProtectionState: pointer.To(protecteditems.ProtectionStateProtectionStopped),
ProtectionState: pointer.To(desiredState),
SourceResourceId: vm.SourceResourceId,
},
}

resp, err := client.CreateOrUpdate(ctx, *id, updateInput)
if err != nil {
return fmt.Errorf("stopping protection and retaining data for %s: %+v", id, err)
return fmt.Errorf("setting protection to %s and retaining data for %s: %+v", desiredState, id, err)
}

operationId, err := parseBackupOperationId(resp.HttpResponse)
Expand Down Expand Up @@ -415,7 +422,7 @@ func resourceRecoveryServicesBackupProtectedVMDelete(d *pluginsdk.ResourceData,
}

if err = resourceRecoveryServicesBackupProtectedVMWaitForDeletion(ctx, client, opResultClient, *id, operationId); err != nil {
return err
return fmt.Errorf("waiting for deletion %s: %+v", id, err)
}

return nil
Expand All @@ -442,8 +449,7 @@ func resourceRecoveryServicesBackupProtectedVMWaitForStateCreateUpdate(ctx conte
},
}

_, err := state.WaitForStateContext(ctx)
if err != nil {
if _, err := state.WaitForStateContext(ctx); err != nil {
return fmt.Errorf("waiting for %s to provision: %+v", id, err)
}

Expand Down
Loading

0 comments on commit d40831d

Please sign in to comment.