Skip to content
Draft
Changes from 3 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
61 changes: 44 additions & 17 deletions internal/service/advancedcluster/plan_modifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package advancedcluster

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand Down Expand Up @@ -56,10 +58,37 @@ func handleModifyPlan(ctx context.Context, diags *diag.Diagnostics, state, plan
attributeChanges := schemafunc.NewAttributeChanges(ctx, state, plan)
keepUnknown := []string{"connection_strings", "state_name", "mongo_db_version", "config_server_type"} // Volatile attributes, should not be copied from state
keepUnknown = append(keepUnknown, attributeChanges.KeepUnknown(attributeRootChangeMapping)...)
keepUnknown = append(keepUnknown, determineKeepUnknownsAutoScaling(ctx, diags, state, plan)...)
autoScalingFields := determineKeepUnknownsAutoScaling(ctx, diags, state, plan)
keepUnknown = append(keepUnknown, autoScalingFields...)
emitWarningIfSpecChangedWithAutoScaling(ctx, diags, plan, attributeChanges)
schemafunc.CopyUnknowns(ctx, state, plan, keepUnknown, nil)
Comment on lines +64 to 67
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

This PR introduces new user-facing behavior (a warning when use_effective_fields=true, auto-scaling is enabled, and spec fields change), but there’s no automated coverage asserting when the warning should/shouldn’t be emitted. Adding a focused unit test around emitWarningIfSpecChangedWithAutoScaling (or exercising it via an existing plan modifier test harness) would help prevent regressions and false positives.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

There's not a way of asserting warnings into the test framework. The code path is exercised by the existing TestAccAdvancedCluster_effectiveComputeAutoScalingInstanceSize test, which runs the exact scenario. A panic or logic error would be caught there.

Behaviour of the warning is documented and manual tests are done in the PR description.

}

// emitWarningIfSpecChangedWithAutoScaling warns when use_effective_fields=true and auto-scaling is enabled but the user
// changed instance_size, disk_size_gb, or disk_iops. Atlas silently ignores these changes in that combination
func emitWarningIfSpecChangedWithAutoScaling(ctx context.Context, diags *diag.Diagnostics, plan *TFModel, attributeChanges schemafunc.AttributeChanges) {
if !plan.UseEffectiveFields.ValueBool() || !autoScalingUsed(ctx, diags, plan) {
return
}
var changedFields []string
for _, field := range []string{"instance_size", "disk_size_gb", "disk_iops"} {
if attributeChanges.AttributeChanged(field) {
changedFields = append(changedFields, field)
Comment thread
marcabreracast marked this conversation as resolved.
}
}
if len(changedFields) == 0 {
return
}
diags.AddWarning(
"Spec change ignored due to auto-scaling",
fmt.Sprintf("The change to %s will be stored in Terraform state but will not modify the actual cluster in Atlas. "+
"When use_effective_fields is true and auto-scaling is enabled, Atlas controls instance_size, disk_size_gb, and disk_iops values. "+
"To apply this change, temporarily disable auto-scaling. "+
"See: https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/advanced_cluster#manually-updating-specs-with-use_effective_fields",
strings.Join(changedFields, ", ")),
)
}

// adjustRegionConfigsChildren modifies the planned values of region configs based on the current state.
// This ensures proper handling of removing auto scaling and specs attributes by preserving state values.
func adjustRegionConfigsChildren(ctx context.Context, diags *diag.Diagnostics, state, plan *TFModel) {
Expand Down Expand Up @@ -164,28 +193,26 @@ func findDefinedElectableSpecInReplicationSpec(ctx context.Context, regionConfig
}

func determineKeepUnknownsAutoScaling(ctx context.Context, diags *diag.Diagnostics, state, plan *TFModel) []string {
if !autoScalingUsed(ctx, diags, state, plan) {
if !autoScalingUsed(ctx, diags, state) && !autoScalingUsed(ctx, diags, plan) {
return nil
}
// When either compute or disk auto-scaling is enabled, all three fields may be adjusted by Atlas
return []string{"instance_size", "disk_size_gb", "disk_iops"}
}

// autoScalingUsed checks if auto-scaling was enabled (state) or will be enabled (plan).
func autoScalingUsed(ctx context.Context, diags *diag.Diagnostics, state, plan *TFModel) bool {
for _, model := range []*TFModel{state, plan} {
repSpecsTF := TFModelList[TFReplicationSpecsModel](ctx, diags, model.ReplicationSpecs)
for i := range repSpecsTF {
regiongConfigsTF := TFModelList[TFRegionConfigsModel](ctx, diags, repSpecsTF[i].RegionConfigs)
for j := range regiongConfigsTF {
for _, autoScalingTF := range []types.Object{regiongConfigsTF[j].AutoScaling, regiongConfigsTF[j].AnalyticsAutoScaling} {
autoscaling := TFModelObject[TFAutoScalingModel](ctx, autoScalingTF)
if autoscaling == nil {
continue
}
if autoscaling.ComputeEnabled.ValueBool() || autoscaling.DiskGBEnabled.ValueBool() {
return true
}
// autoScalingUsed checks if auto-scaling is enabled in the given cluster model.
func autoScalingUsed(ctx context.Context, diags *diag.Diagnostics, model *TFModel) bool {
repSpecsTF := TFModelList[TFReplicationSpecsModel](ctx, diags, model.ReplicationSpecs)
for i := range repSpecsTF {
regiongConfigsTF := TFModelList[TFRegionConfigsModel](ctx, diags, repSpecsTF[i].RegionConfigs)
for j := range regiongConfigsTF {
for _, autoScalingTF := range []types.Object{regiongConfigsTF[j].AutoScaling, regiongConfigsTF[j].AnalyticsAutoScaling} {
autoscaling := TFModelObject[TFAutoScalingModel](ctx, autoScalingTF)
if autoscaling == nil {
continue
}
if autoscaling.ComputeEnabled.ValueBool() || autoscaling.DiskGBEnabled.ValueBool() {
return true
}
}
}
Expand Down
Loading