Skip to content

Conversation

EspenAlbert
Copy link
Collaborator

@EspenAlbert EspenAlbert commented Sep 8, 2025

Description

Uses the new create-only plan modifier in flex cluster.
Also splits the plan modifier into two different structs:

  • one for bool (with default support)
  • one for string (no default support, since it is not used yet)

Additional changes:

  • shortened the plan modifier function names since they live in the customplanmodifier package
  • A follow-up PR will be done to use the CreateOnlyBoolWithDefault for the other resources

Link to any related issue(s): CLOUDP-343190

Type of change:

  • Bug fix (non-breaking change which fixes an issue). Please, add the "bug" label to the PR.
  • New feature (non-breaking change which adds functionality). Please, add the "enhancement" label to the PR. A migration guide must be created or updated if the new feature will go in a major version.
  • Breaking change (fix or feature that would cause existing functionality to not work as expected). Please, add the "breaking change" label to the PR. A migration guide must be created or updated.
  • This change requires a documentation update
  • Documentation fix/enhancement

Required Checklist:

  • I have signed the MongoDB CLA
  • I have read the contributing guides
  • I have checked that this change does not generate any credentials and that they are NOT accidentally logged anywhere.
  • I have added tests that prove my fix is effective or that my feature works per HashiCorp requirements
  • I have added any necessary documentation (if appropriate)
  • I have run make fmt and formatted my code
  • If changes include deprecations or removals I have added appropriate changelog entries.
  • If changes include removal or addition of 3rd party GitHub actions, I updated our internal document. Reach out to the APIx Integration slack channel to get access to the internal document.

Further comments

// Handle timeout with cleanup logic
deleteOnCreateTimeout := cleanup.ResolveDeleteOnCreateTimeout(tfModel.DeleteOnCreateTimeout)
err = cleanup.HandleCreateTimeout(deleteOnCreateTimeout, err, func(ctxCleanup context.Context) error {
err = cleanup.HandleCreateTimeout(tfModel.DeleteOnCreateTimeout.ValueBool(), err, func(ctxCleanup context.Context) error {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed logic

Computed: true,
PlanModifiers: []planmodifier.Bool{
customplanmodifier.CreateOnlyBoolPlanModifier(),
customplanmodifier.CreateOnlyBoolWithDefault(true),
Copy link
Collaborator Author

@EspenAlbert EspenAlbert Sep 8, 2025

Choose a reason for hiding this comment

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

This change will be applied to the other resources in a follow up PR:

  • encryptionatrestprivateendpoint
  • pushbasedlogexport
  • streamprocessor

@EspenAlbert EspenAlbert marked this pull request as ready for review September 8, 2025 07:48
@Copilot Copilot AI review requested due to automatic review settings September 8, 2025 07:48
@EspenAlbert EspenAlbert requested a review from a team as a code owner September 8, 2025 07:48
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the plan modifier system to use new create-only plan modifiers with improved organization and functionality. The change splits the plan modifier functionality into separate type-specific structs and enables default value support for boolean attributes.

  • Replaces old unified plan modifier functions with new type-specific ones (CreateOnlyBool/CreateOnlyString)
  • Adds default value support for boolean plan modifiers through CreateOnlyBoolWithDefault
  • Updates flex cluster resource to use the new plan modifier with default value functionality

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/common/customplanmodifier/create_only.go Removes old unified plan modifier implementation
internal/common/customplanmodifier/create_only_bool.go Adds new boolean-specific plan modifier with default value support
internal/common/customplanmodifier/create_only_string.go Adds new string-specific plan modifier implementation
internal/service/flexcluster/resource_schema.go Updates to use new CreateOnlyBoolWithDefault modifier and adds Computed attribute
internal/service/flexcluster/resource.go Simplifies timeout handling by using boolean value directly
internal/service/flexcluster/resource_test.go Adds ImportStateVerifyIgnore for delete_on_create_timeout
internal/service/project/resource_project_schema.go Updates function calls to use new plan modifier names
internal/service/streamprocessor/resource_schema.go Updates function calls to use new plan modifier names
internal/service/pushbasedlogexport/resource_schema.go Updates function calls to use new plan modifier names
internal/service/encryptionatrestprivateendpoint/resource_schema.go Updates function calls to use new plan modifier names

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Member

@AgustinBettati AgustinBettati left a comment

Choose a reason for hiding this comment

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

LGTM, lets just make sure to clean up the boolean plan modifier implementing PlanModifyString.
Like the approach of splitting by type and clear functions for supporting default value.

// It shows a helpful error message helping the user to update their config to match the state.
// Never use a schema.Default for create only attributes, instead use `WithDefault`, the default will lead to plan changes that are not expected after import.
// No default value implemented for string until we have a use case.
// Implement CopyFromPlan if the attribute is not in the API Response.
Copy link
Member

Choose a reason for hiding this comment

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

What is this exactly referring to? Not sure how relevant this guidance is, it applies for any attribute which is not present in API response.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated, WDYT?

@@ -0,0 +1,95 @@
package customplanmodifier
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't we unit test these plan modifiers?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These are tested by the acceptance tests for project & flex resources:
From project:

  • TestAccProject_withFalseDefaultSettings
  • TestMigProject_withFalseDefaultAlertSettings
  • TestMigProject_withTrueDefaultAlertSettings

It is not straightforward to unit test them as they are called in a specific context.

Optional: true,
PlanModifiers: []planmodifier.Bool{
customplanmodifier.CreateOnlyBoolPlanModifier(),
customplanmodifier.CreateOnlyBool(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Double checking here: will this also be usable for SDKv2? just remembered of this comment.

Feel free to correct me if I am saying something incorrect - I guess it won't, which means that I am wondering if the "import" use case needs to be handled also for the SDKv2 resources? cc @oarbusi

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a good point.
https://developer.hashicorp.com/terraform/plugin/framework/migrating/resources/plan-modification#migration-notes
We could investigate using DiffSuppress function for this, will have to do another investigation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The DiffSuppress is on the resource level:
https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/[email protected]/helper/schema#CustomizeDiffFunc
So, I don't think it is worth changing the logic for the SDKv2 resources.

The behavior of a non-empty plan after import for these resources when an explicit config value is set, I think, is ok to keep for now; otherwise, we would need to add the check of Null to defined-value in all Resources.Update methods.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Problem I see is not being consistent between SDKv2 and TPF resources. If we do this only in the TPF resources and not in SDKv2, we are not consistent and we might cause more confusion than clarity

Copy link
Collaborator Author

@EspenAlbert EspenAlbert Sep 8, 2025

Choose a reason for hiding this comment

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

Update: true,
Delete: true,
}),
"delete_on_create_timeout": schema.BoolAttribute{
Copy link
Collaborator

Choose a reason for hiding this comment

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

@EspenAlbert @AgustinBettati chatting more with @oarbusi , I reflected on one detail I missed during the explanation. The plan change during the import would only occur if delete_on_create_timeout is explicitly set in the configuration used for the import. If not, there is no issue with the existing logic.

That means: if in the import this value is not specified by the practitioner (like it really should be, as there's no reason why it should be set), the current code doesn't have any limitation. Considered that, I can still figure there's a value in improving the overall experience, but I see less urgency in making this change.

Is there any other consideration I missed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

ok, I was of the impression that it was something that was "always" going to happen when an import was made. My take then is that this is not worth it a refactoring now that we are very close to the release.

As it comes down to best practices, I still see the value but I would postpone this change to perhaps a minor release. This will help us focusing in getting 2.0.0 out with less moving pieces.

@AgustinBettati @EspenAlbert @lantoli @maastha @marcabreracast @oarbusi looking for feedback here, I'd like to make a call together.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thinking on this more, I think that if we can't provide the same experience in SDKv2 and TPF, I would maybe hold this off until we can, because not having the same UX across resources can be confusing for customers

Copy link
Collaborator

@oarbusi oarbusi Sep 8, 2025

Choose a reason for hiding this comment

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

Agree on postponing this and including it in a minor release instead of 2.0.0

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 am leaning towards merging. The plan behavior is more explicit, and we are following hashicorp best practices with this refactor (using computed for an attribute with a default value)

Since this plan modifier is already released now in 1.41 we would need to keep both implementations which adds tech debt.

Copy link
Member

Choose a reason for hiding this comment

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

I'm ok to merge this PR if it's ready

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is ready, but I think the team is not convinced. @marcosuma @AgustinBettati @oarbusi

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lantoli @EspenAlbert maybe I was misunderstood - I am not saying we shouldn't merge. I am saying we shouldn't link this to 2.0.0 as there's really no strong reason to do so.

if we merge just this PR, we'll have:

  • this resource (TPF) using this version of plan modifier
  • other resources (TPF) using the other approach but they can be updated
  • other resources (SDKv2) which would stay with a different behavior.

What is the plan to align all of those? Why do you want to link this to 2.0.0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok. Allthough no blocker for 2.0.0 I think we should merge it.
Some clarifications If we merge:

  • flex cluster resource (TPF) using this version of plan modifier for delete_on_create_timeout with default=true
  • other resources (TPF) using the plan modifier for delete_on_create_timeout but without a default (set in create handler instead) --> I expect to follow up with using default instead after merging.
  • other resources (SDKv2) with delete_on_create_timeout which would stay with an allowed plan update after import (when the attribute is changed). --> I can look into updating this today.

@EspenAlbert EspenAlbert changed the base branch from CLOUDP-320243-dev-2.0.0 to master September 9, 2025 09:57
@EspenAlbert EspenAlbert requested a review from a team as a code owner September 9, 2025 09:57
@EspenAlbert EspenAlbert force-pushed the CLOUDP-343190_flex_delete_on_create_timeout branch from 75e97a7 to 674b795 Compare September 9, 2025 10:02
Copy link
Member

@lantoli lantoli left a comment

Choose a reason for hiding this comment

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

after offline discussion, let's wait until 2.0.0 is released

@EspenAlbert EspenAlbert added the not_stale Not stale issue or PR label Sep 9, 2025
@lantoli
Copy link
Member

lantoli commented Sep 29, 2025

we're good to go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
not_stale Not stale issue or PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants