Skip to content

Commit

Permalink
fix: Uses overwriteBackupPolicies in `mongodbatlas_backup_complianc…
Browse files Browse the repository at this point in the history
…e_policy` to avoid overwriting non complying backup policies in updates (#2054)
  • Loading branch information
maastha committed Mar 26, 2024
1 parent 3c68921 commit 717ba68
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 13 deletions.
Expand Up @@ -8,13 +8,15 @@ import (
"net/http"
"strings"

"go.mongodb.org/atlas-sdk/v20231115008/admin"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/spf13/cast"

"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/config"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/service/cloudbackupschedule"
"github.com/spf13/cast"
"go.mongodb.org/atlas-sdk/v20231115008/admin"
)

const (
Expand Down Expand Up @@ -233,7 +235,7 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.
connV2 := meta.(*config.MongoDBClient).AtlasV2
projectID := d.Get("project_id").(string)

params := &admin.DataProtectionSettings20231001{
dataProtectionSettings := &admin.DataProtectionSettings20231001{
ProjectId: conversion.StringPtr(projectID),
AuthorizedEmail: d.Get("authorized_email").(string),
AuthorizedUserFirstName: d.Get("authorized_user_first_name").(string),
Expand Down Expand Up @@ -291,10 +293,15 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.
}
}
if len(backupPoliciesItem) > 0 {
params.ScheduledPolicyItems = &backupPoliciesItem
dataProtectionSettings.ScheduledPolicyItems = &backupPoliciesItem
}

_, _, err := connV2.CloudBackupsApi.UpdateDataProtectionSettings(ctx, projectID, params).Execute()
params := admin.UpdateDataProtectionSettingsApiParams{
GroupId: projectID,
DataProtectionSettings20231001: dataProtectionSettings,
OverwriteBackupPolicies: conversion.Pointer(false),
}
_, _, err := connV2.CloudBackupsApi.UpdateDataProtectionSettingsWithParams(ctx, &params).Execute()
if err != nil {
return diag.FromErr(fmt.Errorf(errorBackupPolicyUpdate, projectID, err))
}
Expand Down Expand Up @@ -393,7 +400,7 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.
ids := conversion.DecodeStateID(d.Id())
projectID := ids["project_id"]

params := &admin.DataProtectionSettings20231001{
dataProtectionSettings := &admin.DataProtectionSettings20231001{
ProjectId: conversion.StringPtr(projectID),
AuthorizedEmail: d.Get("authorized_email").(string),
AuthorizedUserFirstName: d.Get("authorized_user_first_name").(string),
Expand All @@ -402,19 +409,19 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.
}

if d.HasChange("copy_protection_enabled") {
params.CopyProtectionEnabled = conversion.Pointer(d.Get("copy_protection_enabled").(bool))
dataProtectionSettings.CopyProtectionEnabled = conversion.Pointer(d.Get("copy_protection_enabled").(bool))
}

if d.HasChange("encryption_at_rest_enabled") {
params.EncryptionAtRestEnabled = conversion.Pointer(d.Get("encryption_at_rest_enabled").(bool))
dataProtectionSettings.EncryptionAtRestEnabled = conversion.Pointer(d.Get("encryption_at_rest_enabled").(bool))
}

if d.HasChange("pit_enabled") {
params.PitEnabled = conversion.Pointer(d.Get("pit_enabled").(bool))
dataProtectionSettings.PitEnabled = conversion.Pointer(d.Get("pit_enabled").(bool))
}

if d.HasChange("restore_window_days") {
params.RestoreWindowDays = conversion.Pointer(cast.ToInt(d.Get("restore_window_days")))
dataProtectionSettings.RestoreWindowDays = conversion.Pointer(cast.ToInt(d.Get("restore_window_days")))
}

var backupPoliciesItem []admin.BackupComplianceScheduledPolicyItem
Expand Down Expand Up @@ -463,10 +470,15 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.
}
}
if len(backupPoliciesItem) > 0 {
params.ScheduledPolicyItems = &backupPoliciesItem
dataProtectionSettings.ScheduledPolicyItems = &backupPoliciesItem
}

_, _, err := connV2.CloudBackupsApi.UpdateDataProtectionSettings(ctx, projectID, params).Execute()
params := admin.UpdateDataProtectionSettingsApiParams{
GroupId: projectID,
DataProtectionSettings20231001: dataProtectionSettings,
OverwriteBackupPolicies: conversion.Pointer(false),
}
_, _, err := connV2.CloudBackupsApi.UpdateDataProtectionSettingsWithParams(ctx, &params).Execute()
if err != nil {
return diag.FromErr(fmt.Errorf(errorBackupPolicyUpdate, projectID, err))
}
Expand Down
Expand Up @@ -4,10 +4,12 @@ import (
"context"
"fmt"
"os"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"

"github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion"
"github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc"
)
Expand Down Expand Up @@ -41,7 +43,7 @@ func TestAccGenericBackupRSBackupCompliancePolicy_basic(t *testing.T) {
})
}

func TestAccGenericBackupRSBackupCompliancePolicy_withFirstLastName(t *testing.T) {
func TestAccGenericBackupRSBackupCompliancePolicy_update(t *testing.T) {
var (
orgID = os.Getenv("MONGODB_ATLAS_ORG_ID")
projectOwnerID = os.Getenv("MONGODB_ATLAS_PROJECT_OWNER_ID")
Expand All @@ -53,6 +55,17 @@ func TestAccGenericBackupRSBackupCompliancePolicy_withFirstLastName(t *testing.T
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
CheckDestroy: checkDestroy,
Steps: []resource.TestStep{
{
Config: configWithoutOptionals(projectName, orgID, projectOwnerID),
Check: resource.ComposeTestCheckFunc(
checkExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "authorized_user_first_name", "First"),
resource.TestCheckResourceAttr(resourceName, "authorized_user_last_name", "Last"),
resource.TestCheckResourceAttr(resourceName, "pit_enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "encryption_at_rest_enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "copy_protection_enabled", "false"),
),
},
{
Config: configBasic(projectName, orgID, projectOwnerID),
Check: resource.ComposeTestCheckFunc(
Expand All @@ -65,6 +78,150 @@ func TestAccGenericBackupRSBackupCompliancePolicy_withFirstLastName(t *testing.T
})
}

func TestAccGenericBackupRSBackupCompliancePolicy_overwriteBackupPolicies(t *testing.T) {
var (
orgID = os.Getenv("MONGODB_ATLAS_ORG_ID")
projectOwnerID = os.Getenv("MONGODB_ATLAS_PROJECT_OWNER_ID")
projectName = acc.RandomProjectName()
)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acc.PreCheckBasic(t) },
ProtoV6ProviderFactories: acc.TestAccProviderV6Factories,
CheckDestroy: checkDestroy,
Steps: []resource.TestStep{
{
Config: configClusterWithBackupSchedule(projectName, orgID, projectOwnerID),
},
{
Config: configOverwriteIncompatibleBackupPoliciesError(projectName, orgID, projectOwnerID),
ExpectError: regexp.MustCompile(`BACKUP_POLICIES_NOT_MEETING_BACKUP_COMPLIANCE_POLICY_REQUIREMENTS`),
},
},
})
}

func configOverwriteIncompatibleBackupPoliciesError(projectName, orgID, projectOwnerID string) string {
return acc.ConfigProjectWithSettings(projectName, orgID, projectOwnerID, false) + `
resource "mongodbatlas_cluster" "test" {
project_id = mongodbatlas_project.test.id
name = "test1"
provider_name = "AWS"
cluster_type = "REPLICASET"
mongo_db_major_version = "6.0"
provider_instance_size_name = "M10"
auto_scaling_compute_enabled = false
cloud_backup = true
auto_scaling_disk_gb_enabled = true
disk_size_gb = 12
provider_volume_type = "STANDARD"
retain_backups_enabled = true
advanced_configuration {
oplog_min_retention_hours = 8
}
replication_specs {
num_shards = 1
regions_config {
region_name = "US_EAST_1"
electable_nodes = 3
priority = 7
read_only_nodes = 0
}
}
}
resource "mongodbatlas_cloud_backup_schedule" "test" {
cluster_name = mongodbatlas_cluster.test.name
project_id = mongodbatlas_project.test.id
reference_hour_of_day = 3
reference_minute_of_hour = 45
restore_window_days = 2
copy_settings {
cloud_provider = "AWS"
frequencies = ["DAILY"]
region_name = "US_WEST_1"
replication_spec_id = one(mongodbatlas_cluster.test.replication_specs).id
should_copy_oplogs = false
}
}
resource "mongodbatlas_backup_compliance_policy" "test" {
project_id = mongodbatlas_project.test.id
authorized_email = "test@example.com"
authorized_user_first_name = "First"
authorized_user_last_name = "Last"
copy_protection_enabled = true
pit_enabled = false
encryption_at_rest_enabled = false
on_demand_policy_item {
frequency_interval = 1
retention_unit = "days"
retention_value = 1
}
policy_item_daily {
frequency_interval = 1
retention_unit = "days"
retention_value = 1
}
}
`
}

func configClusterWithBackupSchedule(projectName, orgID, projectOwnerID string) string {
return acc.ConfigProjectWithSettings(projectName, orgID, projectOwnerID, false) + `
resource "mongodbatlas_cluster" "test" {
project_id = mongodbatlas_project.test.id
name = "test1"
provider_name = "AWS"
cluster_type = "REPLICASET"
mongo_db_major_version = "6.0"
provider_instance_size_name = "M10"
auto_scaling_compute_enabled = false
cloud_backup = true
auto_scaling_disk_gb_enabled = true
disk_size_gb = 12
provider_volume_type = "STANDARD"
retain_backups_enabled = true
advanced_configuration {
oplog_min_retention_hours = 8
}
replication_specs {
num_shards = 1
regions_config {
region_name = "US_EAST_1"
electable_nodes = 3
priority = 7
read_only_nodes = 0
}
}
}
resource "mongodbatlas_cloud_backup_schedule" "test" {
cluster_name = mongodbatlas_cluster.test.name
project_id = mongodbatlas_project.test.id
reference_hour_of_day = 3
reference_minute_of_hour = 45
restore_window_days = 2
copy_settings {
cloud_provider = "AWS"
frequencies = ["DAILY"]
region_name = "US_WEST_1"
replication_spec_id = one(mongodbatlas_cluster.test.replication_specs).id
should_copy_oplogs = false
}
}
`
}
func TestAccGenericBackupRSBackupCompliancePolicy_withoutOptionals(t *testing.T) {
var (
orgID = os.Getenv("MONGODB_ATLAS_ORG_ID")
Expand Down

0 comments on commit 717ba68

Please sign in to comment.