From 3b46c6a629e2d42cd2e5119b74468c4897ef65d4 Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Wed, 16 Jul 2025 12:22:15 +0200 Subject: [PATCH 1/8] change export and auto_export_enabled to Optional only --- docs/resources/cloud_backup_schedule.md | 4 ++-- .../resource_cloud_backup_schedule.go | 24 ++++--------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/docs/resources/cloud_backup_schedule.md b/docs/resources/cloud_backup_schedule.md index 8999b7064e..d55a1f4394 100644 --- a/docs/resources/cloud_backup_schedule.md +++ b/docs/resources/cloud_backup_schedule.md @@ -228,12 +228,12 @@ resource "mongodbatlas_cloud_backup_schedule" "test" { * `policy_item_weekly` - (Optional) Weekly policy item. See [below](#policy_item_weekly) * `policy_item_monthly` - (Optional) Monthly policy item. See [below](#policy_item_monthly) * `policy_item_yearly` - (Optional) Yearly policy item. See [below](#policy_item_yearly) -* `auto_export_enabled` - Flag that indicates whether MongoDB Cloud automatically exports Cloud Backup Snapshots to the Export Bucket. Once enabled, it must be disabled by explicitly setting the value to `false`. Value can be one of the following: +* `auto_export_enabled` - Flag that indicates whether MongoDB Cloud automatically exports Cloud Backup Snapshots to the Export Bucket. Value can be one of the following: * true - Enables automatic export of cloud backup snapshots to the Export Bucket. * false - Disables automatic export of cloud backup snapshots to the Export Bucket. (default) * `use_org_and_group_names_in_export_prefix` - Specify true to use organization and project names instead of organization and project UUIDs in the path for the metadata files that Atlas uploads to your bucket after it finishes exporting the snapshots. To learn more about the metadata files that Atlas uploads, see [Export Cloud Backup Snapshot](https://www.mongodb.com/docs/atlas/backup/cloud-backup/export/#std-label-cloud-provider-snapshot-export). * `copy_settings` - List that contains a document for each copy setting item in the desired backup policy. See [below](#copy_settings) -* `export` - Policy for automatically exporting Cloud Backup Snapshots. `auto_export_enabled` must be set to true when defining this attribute. See [below](#export) +* `export` - Policy for automatically exporting Cloud Backup Snapshots. See [below](#export) ### export * `export_bucket_id` - Unique identifier of the mongodbatlas_cloud_backup_snapshot_export_bucket export_bucket_id value. * `frequency_type` - Frequency associated with the export snapshot item: `weekly`, `monthly`, `yearly`, `daily` (requires reaching out to Customer Support) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule.go index d328501065..ee06914f0d 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule.go @@ -63,7 +63,6 @@ func Resource() *schema.Resource { "auto_export_enabled": { Type: schema.TypeBool, Optional: true, - Computed: true, }, "use_org_and_group_names_in_export_prefix": { Type: schema.TypeBool, @@ -116,7 +115,6 @@ func Resource() *schema.Resource { Type: schema.TypeList, MaxItems: 1, Optional: true, - Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "export_bucket_id": { @@ -436,14 +434,6 @@ func setSchemaFieldsExceptCopySettings(d *schema.ResourceData, backupPolicy *adm return diag.Errorf(errorSnapshotBackupScheduleSetting, "id_policy", clusterName, err) } - if err := d.Set("export", FlattenExport(backupPolicy)); err != nil { - return diag.Errorf(errorSnapshotBackupScheduleSetting, "export", clusterName, err) - } - - if err := d.Set("auto_export_enabled", backupPolicy.GetAutoExportEnabled()); err != nil { - return diag.Errorf(errorSnapshotBackupScheduleSetting, "auto_export_enabled", clusterName, err) - } - if err := d.Set("use_org_and_group_names_in_export_prefix", backupPolicy.GetUseOrgAndGroupNamesInExportPrefix()); err != nil { return diag.Errorf(errorSnapshotBackupScheduleSetting, "use_org_and_group_names_in_export_prefix", clusterName, err) } @@ -573,7 +563,7 @@ func cloudBackupScheduleCreateOrUpdate(ctx context.Context, connV220240530 *admi } if v, ok := d.GetOk("export"); ok { - req.Export = expandAutoExportPolicy(v.([]any), d) + req.Export = expandAutoExportPolicy(v.([]any)) } if d.HasChange("use_org_and_group_names_in_export_prefix") { @@ -700,16 +690,12 @@ func expandCopySettingOldSDK(tfMap map[string]any) *admin20240530.DiskBackupCopy return copySetting } -func expandAutoExportPolicy(items []any, d *schema.ResourceData) *admin.AutoExportPolicy { +func expandAutoExportPolicy(items []any) *admin.AutoExportPolicy { itemObj := items[0].(map[string]any) - - if autoExportEnabled := d.Get("auto_export_enabled"); autoExportEnabled != nil && autoExportEnabled.(bool) { - return &admin.AutoExportPolicy{ - ExportBucketId: conversion.StringPtr(itemObj["export_bucket_id"].(string)), - FrequencyType: conversion.StringPtr(itemObj["frequency_type"].(string)), - } + return &admin.AutoExportPolicy{ + ExportBucketId: conversion.StringPtr(itemObj["export_bucket_id"].(string)), + FrequencyType: conversion.StringPtr(itemObj["frequency_type"].(string)), } - return nil } func ExpandPolicyItems(items []any, frequencyType string) *[]admin.DiskBackupApiPolicyItem { From 97ee21a03ad5bf3ce498a0434bfb5ced5226c0c0 Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Wed, 16 Jul 2025 12:26:11 +0200 Subject: [PATCH 2/8] changelog --- .changelog/3500.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/3500.txt diff --git a/.changelog/3500.txt b/.changelog/3500.txt new file mode 100644 index 0000000000..c36eb278e4 --- /dev/null +++ b/.changelog/3500.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +resource/mongodbatlas_cloud_backup_schedule: Changes `export` and `auto_export_enabled` to Optional only +``` From 2e3ce7262e84b488e02c896e04b3989e66ecf90b Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Wed, 16 Jul 2025 16:45:55 +0200 Subject: [PATCH 3/8] add test check on unsetting optional attributes --- .../resource_cloud_backup_schedule_test.go | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_test.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_test.go index 610e7dc3ab..8c00759860 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_test.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_test.go @@ -165,7 +165,7 @@ func TestAccBackupRSCloudBackupSchedule_export(t *testing.T) { Steps: []resource.TestStep{ { - Config: configExportPolicies(&clusterInfo, policyName, roleName, bucketName), + Config: configExportPolicies(&clusterInfo, policyName, roleName, bucketName, true, true), Check: resource.ComposeAggregateTestCheckFunc( checkExists(resourceName), resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.Name), @@ -179,6 +179,15 @@ func TestAccBackupRSCloudBackupSchedule_export(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy_item_daily.0.retention_value", "4"), ), }, + { + Config: configExportPolicies(&clusterInfo, policyName, roleName, bucketName, false, false), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.Name), + resource.TestCheckResourceAttr(resourceName, "auto_export_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "export.#", "0"), + ), + }, }, }) } @@ -934,12 +943,23 @@ func configAdvancedPolicies(info *acc.ClusterInfo, p *admin20240530.DiskBackupSn `, info.TerraformNameRef, info.ProjectID, p.GetReferenceHourOfDay(), p.GetReferenceMinuteOfHour(), p.GetRestoreWindowDays()) } -func configExportPolicies(info *acc.ClusterInfo, policyName, roleName, bucketName string) string { +func configExportPolicies(info *acc.ClusterInfo, policyName, roleName, bucketName string, includeAutoExport, includeExport bool) string { + autoExport := "" + export := "" + if includeAutoExport { + autoExport = "auto_export_enabled = true" + } + if includeExport { + export = `export { + export_bucket_id = mongodbatlas_cloud_backup_snapshot_export_bucket.test.export_bucket_id + frequency_type = "monthly" + }` + } return info.TerraformStr + fmt.Sprintf(` resource "mongodbatlas_cloud_backup_schedule" "schedule_test" { cluster_name = %[1]s project_id = %[2]q - auto_export_enabled = true + %[6]s reference_hour_of_day = 20 reference_minute_of_hour = "05" restore_window_days = 4 @@ -966,10 +986,7 @@ func configExportPolicies(info *acc.ClusterInfo, policyName, roleName, bucketNam retention_value = 4 } - export { - export_bucket_id = mongodbatlas_cloud_backup_snapshot_export_bucket.test.export_bucket_id - frequency_type = "monthly" - } + %[7]s } resource "aws_s3_bucket" "backup" { @@ -1040,7 +1057,7 @@ func configExportPolicies(info *acc.ClusterInfo, policyName, roleName, bucketNam } EOF } - `, info.TerraformNameRef, info.ProjectID, policyName, roleName, bucketName) + `, info.TerraformNameRef, info.ProjectID, policyName, roleName, bucketName, autoExport, export) } func importStateIDFunc(resourceName string) resource.ImportStateIdFunc { From 62984808106282fe9ac25ce62250bdd46096c4b5 Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Wed, 16 Jul 2025 16:56:47 +0200 Subject: [PATCH 4/8] specify optional in doc --- docs/resources/cloud_backup_schedule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/resources/cloud_backup_schedule.md b/docs/resources/cloud_backup_schedule.md index d55a1f4394..1fd7e289a0 100644 --- a/docs/resources/cloud_backup_schedule.md +++ b/docs/resources/cloud_backup_schedule.md @@ -228,7 +228,7 @@ resource "mongodbatlas_cloud_backup_schedule" "test" { * `policy_item_weekly` - (Optional) Weekly policy item. See [below](#policy_item_weekly) * `policy_item_monthly` - (Optional) Monthly policy item. See [below](#policy_item_monthly) * `policy_item_yearly` - (Optional) Yearly policy item. See [below](#policy_item_yearly) -* `auto_export_enabled` - Flag that indicates whether MongoDB Cloud automatically exports Cloud Backup Snapshots to the Export Bucket. Value can be one of the following: +* `auto_export_enabled` - (Optional) Flag that indicates whether MongoDB Cloud automatically exports Cloud Backup Snapshots to the Export Bucket. Value can be one of the following: * true - Enables automatic export of cloud backup snapshots to the Export Bucket. * false - Disables automatic export of cloud backup snapshots to the Export Bucket. (default) * `use_org_and_group_names_in_export_prefix` - Specify true to use organization and project names instead of organization and project UUIDs in the path for the metadata files that Atlas uploads to your bucket after it finishes exporting the snapshots. To learn more about the metadata files that Atlas uploads, see [Export Cloud Backup Snapshot](https://www.mongodb.com/docs/atlas/backup/cloud-backup/export/#std-label-cloud-provider-snapshot-export). From 7f19b52486db63f3243c25e1b5d2daf493ef18f8 Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Wed, 16 Jul 2025 16:57:03 +0200 Subject: [PATCH 5/8] add migration test --- ...ce_cloud_backup_schedule_migration_test.go | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go index d5cef4cb6f..83797dd06e 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/mig" @@ -127,3 +128,56 @@ func TestMigBackupRSCloudBackupSchedule_copySettings(t *testing.T) { }, }) } + +func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) { + // TODO: uncomment before merging this, this is temporary to make sure the test is working + // mig.SkipIfVersionBelow(t, "2.0.0") + var ( + clusterInfo = acc.GetClusterInfo(t, &acc.ClusterRequest{CloudBackup: true, ResourceDependencyName: "mongodbatlas_cloud_backup_snapshot_export_bucket.test"}) + policyName = acc.RandomName() + roleName = acc.RandomIAMRole() + bucketName = acc.RandomS3BucketName() + + configWithExport = configExportPolicies(&clusterInfo, policyName, roleName, bucketName, true, true) + configWithoutExport = configExportPolicies(&clusterInfo, policyName, roleName, bucketName, false, false) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: mig.PreCheckBasicSleep(t), + CheckDestroy: checkDestroy, + Steps: []resource.TestStep{ + // Step 1: Apply config with export and auto_export_enabled (old provider) + { + ExternalProviders: mig.ExternalProviders(), + Config: configWithExport, + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.Name), + resource.TestCheckResourceAttr(resourceName, "auto_export_enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "export.#", "1"), + ), + }, + // Step 2: Remove export and auto_export_enabled, expect empty plan (old provider) + { + ExternalProviders: mig.ExternalProviders(), + Config: configWithExport, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // Step 3: Apply config without export and auto_export_enabled (new provider) + { + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + Config: configWithoutExport, + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "cluster_name", clusterInfo.Name), + resource.TestCheckResourceAttr(resourceName, "auto_export_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "export.#", "0"), + ), + }, + }, + }) +} From 723f2d6e4b02984a3a2e2d850fe886afc7c0725a Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Thu, 17 Jul 2025 09:23:56 +0200 Subject: [PATCH 6/8] aws provider in mig test --- .../resource_cloud_backup_schedule_migration_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go index 83797dd06e..324782e348 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go @@ -143,8 +143,9 @@ func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) { ) resource.ParallelTest(t, resource.TestCase{ - PreCheck: mig.PreCheckBasicSleep(t), - CheckDestroy: checkDestroy, + PreCheck: mig.PreCheckBasicSleep(t), + ExternalProviders: acc.ExternalProvidersOnlyAWS(), + CheckDestroy: checkDestroy, Steps: []resource.TestStep{ // Step 1: Apply config with export and auto_export_enabled (old provider) { From f01f1fd14a088da0aec2d31ce00ce25cd376e0bc Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Thu, 17 Jul 2025 10:28:24 +0200 Subject: [PATCH 7/8] fix --- .../resource_cloud_backup_schedule_migration_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go index 324782e348..9c748d01f3 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go @@ -143,13 +143,12 @@ func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) { ) resource.ParallelTest(t, resource.TestCase{ - PreCheck: mig.PreCheckBasicSleep(t), - ExternalProviders: acc.ExternalProvidersOnlyAWS(), - CheckDestroy: checkDestroy, + PreCheck: mig.PreCheckBasicSleep(t), + CheckDestroy: checkDestroy, Steps: []resource.TestStep{ // Step 1: Apply config with export and auto_export_enabled (old provider) { - ExternalProviders: mig.ExternalProviders(), + ExternalProviders: mig.ExternalProvidersWithAWS(), Config: configWithExport, Check: resource.ComposeAggregateTestCheckFunc( checkExists(resourceName), @@ -160,7 +159,7 @@ func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) { }, // Step 2: Remove export and auto_export_enabled, expect empty plan (old provider) { - ExternalProviders: mig.ExternalProviders(), + ExternalProviders: mig.ExternalProvidersWithAWS(), Config: configWithExport, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ From 5a30622086419de31391b23fc959dfc250c9c792 Mon Sep 17 00:00:00 2001 From: Oriol Arbusi Abadal Date: Thu, 17 Jul 2025 16:33:12 +0200 Subject: [PATCH 8/8] remove todo --- .../resource_cloud_backup_schedule_migration_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go index 9c748d01f3..962d8176e8 100644 --- a/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go +++ b/internal/service/cloudbackupschedule/resource_cloud_backup_schedule_migration_test.go @@ -130,8 +130,7 @@ func TestMigBackupRSCloudBackupSchedule_copySettings(t *testing.T) { } func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) { - // TODO: uncomment before merging this, this is temporary to make sure the test is working - // mig.SkipIfVersionBelow(t, "2.0.0") + mig.SkipIfVersionBelow(t, "2.0.0") // in 2.0.0 we made auto_export_enabled and export fields optional only var ( clusterInfo = acc.GetClusterInfo(t, &acc.ClusterRequest{CloudBackup: true, ResourceDependencyName: "mongodbatlas_cloud_backup_snapshot_export_bucket.test"}) policyName = acc.RandomName()