Skip to content

Commit

Permalink
recovery_services - Add new recovery_service block to the provide…
Browse files Browse the repository at this point in the history
…r that supports `vm_backup_stop_protection_and_retain_data_on_destroy` and `purge_protected_items_from_vault_on_destroy` (#25515)
  • Loading branch information
mbfrahry authored Apr 4, 2024
1 parent fd3d17b commit 8b8edff
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 12 deletions.
4 changes: 4 additions & 0 deletions internal/features/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,9 @@ func Default() UserFeatures {
PostgresqlFlexibleServer: PostgresqlFlexibleServerFeatures{
RestartServerOnConfigurationValueChange: true,
},
RecoveryService: RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
}
}
6 changes: 6 additions & 0 deletions internal/features/user_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type UserFeatures struct {
ManagedDisk ManagedDiskFeatures
Subscription SubscriptionFeatures
PostgresqlFlexibleServer PostgresqlFlexibleServerFeatures
RecoveryService RecoveryServiceFeatures
}

type CognitiveAccountFeatures struct {
Expand Down Expand Up @@ -85,3 +86,8 @@ type SubscriptionFeatures struct {
type PostgresqlFlexibleServerFeatures struct {
RestartServerOnConfigurationValueChange bool
}

type RecoveryServiceFeatures struct {
VMBackupStopProtectionAndRetainDataOnDestroy bool
PurgeProtectedItemsFromVaultOnDestroy bool
}
33 changes: 33 additions & 0 deletions internal/provider/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,26 @@ func schemaFeatures(supportLegacyTestSuite bool) *pluginsdk.Schema {
},
},
},

"recovery_service": {
Type: pluginsdk.TypeList,
Optional: true,
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
"vm_backup_stop_protection_and_retain_data_on_destroy": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},
"purge_protected_items_from_vault_on_destroy": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},
},
},
},
}

// this is a temporary hack to enable us to gradually add provider blocks to test configurations
Expand Down Expand Up @@ -514,5 +534,18 @@ func expandFeatures(input []interface{}) features.UserFeatures {
}
}

if raw, ok := val["recovery_service"]; ok {
items := raw.([]interface{})
if len(items) > 0 {
recoveryServicesRaw := items[0].(map[string]interface{})
if v, ok := recoveryServicesRaw["vm_backup_stop_protection_and_retain_data_on_destroy"]; ok {
featuresMap.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy = v.(bool)
}
if v, ok := recoveryServicesRaw["purge_protected_items_from_vault_on_destroy"]; ok {
featuresMap.RecoveryService.PurgeProtectedItemsFromVaultOnDestroy = v.(bool)
}
}
}

return featuresMap
}
94 changes: 94 additions & 0 deletions internal/provider/features_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ func TestExpandFeatures(t *testing.T) {
PostgresqlFlexibleServer: features.PostgresqlFlexibleServerFeatures{
RestartServerOnConfigurationValueChange: true,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
{
Expand Down Expand Up @@ -161,6 +165,12 @@ func TestExpandFeatures(t *testing.T) {
"scale_to_zero_before_deletion": true,
},
},
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": true,
"purge_protected_items_from_vault_on_destroy": true,
},
},
},
},
Expected: features.UserFeatures{
Expand Down Expand Up @@ -218,6 +228,10 @@ func TestExpandFeatures(t *testing.T) {
PostgresqlFlexibleServer: features.PostgresqlFlexibleServerFeatures{
RestartServerOnConfigurationValueChange: true,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
},
},
},
{
Expand Down Expand Up @@ -304,6 +318,12 @@ func TestExpandFeatures(t *testing.T) {
"scale_to_zero_before_deletion": false,
},
},
"recovery_service": []interface{}{
map[string]interface{}{
"vm_backup_stop_protection_and_retain_data_on_destroy": false,
"purge_protected_items_from_vault_on_destroy": false,
},
},
},
},
Expected: features.UserFeatures{
Expand Down Expand Up @@ -361,6 +381,10 @@ func TestExpandFeatures(t *testing.T) {
PostgresqlFlexibleServer: features.PostgresqlFlexibleServerFeatures{
RestartServerOnConfigurationValueChange: false,
},
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
}
Expand Down Expand Up @@ -1358,3 +1382,73 @@ func TestExpandFeaturesPosgresqlFlexibleServer(t *testing.T) {
}
}
}

func TestExpandFeaturesRecoveryService(t *testing.T) {
testData := []struct {
Name string
Input []interface{}
EnvVars map[string]interface{}
Expected features.UserFeatures
}{
{
Name: "Empty Block",
Input: []interface{}{
map[string]interface{}{
"recovery_service": []interface{}{},
},
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
{
Name: "Recovery Service Features Enabled",
Input: []interface{}{
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,
},
},
},
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: true,
PurgeProtectedItemsFromVaultOnDestroy: true,
},
},
},
{
Name: "Recovery Service Features Disabled",
Input: []interface{}{
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,
},
},
},
},
Expected: features.UserFeatures{
RecoveryService: features.RecoveryServiceFeatures{
VMBackupStopProtectionAndRetainDataOnDestroy: false,
PurgeProtectedItemsFromVaultOnDestroy: false,
},
},
},
}

for _, testCase := range testData {
t.Logf("[DEBUG] Test Case: %q", testCase.Name)
result := expandFeatures(testCase.Input)
if !reflect.DeepEqual(result.Subscription, testCase.Expected.Subscription) {
t.Fatalf("Expected %+v but got %+v", result.Subscription, testCase.Expected.Subscription)
}
}
}
44 changes: 44 additions & 0 deletions internal/services/recoveryservices/backup_protected_vm_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func resourceRecoveryServicesBackupProtectedVMRead(d *pluginsdk.ResourceData, me
func resourceRecoveryServicesBackupProtectedVMDelete(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).RecoveryServices.ProtectedItemsClient
opResultClient := meta.(*clients.Client).RecoveryServices.BackupOperationResultsClient
opClient := meta.(*clients.Client).RecoveryServices.ProtectedItemOperationResultsClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

Expand All @@ -242,6 +243,49 @@ func resourceRecoveryServicesBackupProtectedVMDelete(d *pluginsdk.ResourceData,
return err
}

if meta.(*clients.Client).Features.RecoveryService.VMBackupStopProtectionAndRetainDataOnDestroy {
log.Printf("[DEBUG] Retaining Data and Stopping Protection for %s", id)

existing, err := client.Get(ctx, *id, protecteditems.GetOperationOptions{})
if err != nil {
if response.WasNotFound(existing.HttpResponse) {
d.SetId("")
return nil
}

return fmt.Errorf("making Read request on %s: %+v", id, err)
}

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),
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)
}

operationId, err := parseBackupOperationId(resp.HttpResponse)
if err != nil {
return fmt.Errorf("issuing creating/updating request for %s: %+v", id, err)
}

if err = resourceRecoveryServicesBackupProtectedVMWaitForStateCreateUpdate(ctx, opClient, *id, operationId); err != nil {
return err
}

return nil
}
}
}
}

log.Printf("[DEBUG] Deleting %s", id)

resp, err := client.Delete(ctx, *id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,25 @@ func TestAccBackupProtectedVm_protectionStopped(t *testing.T) {
})
}

func TestAccBackupProtectedVm_protectionStoppedOnDestroy(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.protectionStoppedOnDestroy(data),
},
})
}

func (t BackupProtectedVmResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := protecteditems.ParseProtectedItemID(state.ID)
if err != nil {
Expand All @@ -248,10 +267,6 @@ func (t BackupProtectedVmResource) Exists(ctx context.Context, clients *clients.

func (BackupProtectedVmResource) base(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-backup-%d"
location = "%s"
Expand Down Expand Up @@ -395,10 +410,6 @@ resource "azurerm_backup_policy_vm" "test" {

func (BackupProtectedVmResource) baseWithoutVM(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-backup-%d"
location = "%s"
Expand Down Expand Up @@ -475,6 +486,10 @@ resource "azurerm_backup_policy_vm" "test" {

func (r BackupProtectedVmResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_backup_protected_vm" "test" {
Expand All @@ -490,6 +505,10 @@ resource "azurerm_backup_protected_vm" "test" {

func (r BackupProtectedVmResource) updateDiskExclusion(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_backup_protected_vm" "test" {
Expand All @@ -506,10 +525,6 @@ resource "azurerm_backup_protected_vm" "test" {
// For update backup policy id test
func (BackupProtectedVmResource) basePolicyTest(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-backup-%d-1"
location = "%s"
Expand Down Expand Up @@ -594,6 +609,10 @@ resource "azurerm_backup_policy_vm" "test_change_backup" {
// For update backup policy id test
func (r BackupProtectedVmResource) linkFirstBackupPolicy(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_backup_protected_vm" "test" {
Expand All @@ -608,6 +627,10 @@ resource "azurerm_backup_protected_vm" "test" {
// For update backup policy id test
func (r BackupProtectedVmResource) linkSecondBackupPolicy(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_backup_protected_vm" "test" {
Expand All @@ -634,6 +657,10 @@ resource "azurerm_backup_protected_vm" "import" {

func (r BackupProtectedVmResource) additionalVault(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
%s
resource "azurerm_resource_group" "test2" {
Expand Down Expand Up @@ -734,3 +761,18 @@ resource "azurerm_backup_protected_vm" "test" {
}
`, r.base(data))
}

func (r BackupProtectedVmResource) protectionStoppedOnDestroy(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {
recovery_service {
vm_backup_stop_protection_and_retain_data_on_destroy = true
purge_protected_items_from_vault_on_destroy = true
}
}
}
%s
`, r.base(data))
}
Loading

0 comments on commit 8b8edff

Please sign in to comment.