Skip to content

feat: Changes export and auto_export_enabled to Optional only in mongodbatlas_cloud_backup_schedule resource #3500

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

Merged
merged 8 commits into from
Jul 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/3500.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:breaking-change
resource/mongodbatlas_cloud_backup_schedule: Changes `export` and `auto_export_enabled` to Optional only
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we going to have an entry in the 2.0.0 upgrade guide about this explaining why and what's going to happen ? I am wondering if you are tracking that work to be done with some CLOUD? easy to forget considering we're going to have a lot of open conversations

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have created CLOUDP-332342 to track that work

```
4 changes: 2 additions & 2 deletions docs/resources/cloud_backup_schedule.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` - (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).
* `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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we remove the line about the auto_export_enabled?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because "auto_export_enabled must be set to true when defining this attribute." is no longer true. It's not necessary to set auto_export_enabled to true when setting export

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh so you can have a policy, but still have the export as disabled. I see. Still a bit confusing, but at least consistent with the other change.

### 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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": {
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -127,3 +128,55 @@ func TestMigBackupRSCloudBackupSchedule_copySettings(t *testing.T) {
},
})
}

func TestMigBackupRSCloudBackupSchedule_export(t *testing.T) {
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()
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.ExternalProvidersWithAWS(),
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.ExternalProvidersWithAWS(),
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"),
),
},
},
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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"),
),
},
},
})
}
Expand Down Expand Up @@ -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
Expand All @@ -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" {
Expand Down Expand Up @@ -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 {
Expand Down