Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_backup_protected_vm - protection can now be suspended during destroy #27950

Merged
merged 10 commits into from
Jan 21, 2025
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
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
Loading