Skip to content

generate config new algo - #1292

Closed
ansgarm wants to merge 11 commits into
mainfrom
generate-config-new-algo
Closed

generate config new algo#1292
ansgarm wants to merge 11 commits into
mainfrom
generate-config-new-algo

Conversation

@ansgarm

@ansgarm ansgarm commented Mar 23, 2026

Copy link
Copy Markdown
Member

What this does

This improves the quality of generated resource config.

It now:

  • clears top-level id and timeouts
  • clears computed-only values
  • clears empty optional values
  • handles validator groups better for ConflictsWith, ExactlyOneOf, and AlsoRequires

For the validator group handling to work, validators need to implement the three new interfaces that expose the paths they validate. The terraform-plugin-framework-validators package will be updated to support that, so updating that package will be one way to pick this up.

Why

The old behavior was what Terraform Core can do on its own.

This change improves the generated config using schema information that the provider has, but Terraform Core does not. That gives us better output during import and makes the generated config closer to something a user can actually keep instead of having to clean up by hand.

Notes

I kept the normal Framework default behavior instead of writing defaults straight into generated config across the board.

The one special case is ExactlyOneOf, where using a default can help generate config that makes sense.

Rollback Plan

  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

@ansgarm
ansgarm force-pushed the generate-config-new-algo branch from 7f7a8b0 to 902e90f Compare March 23, 2026 09:47
ansgarm added 3 commits March 23, 2026 11:02
GenerateResourceConfig now resolves ExactlyOneOf and AlsoRequires groups and shares validator-group extraction helpers so generated config better reflects schema constraints.
@ansgarm
ansgarm force-pushed the generate-config-new-algo branch from 3a592fa to 99ded31 Compare March 23, 2026 10:03
ansgarm added 8 commits March 23, 2026 16:20
Rename the new path-based validator methods so GenerateResourceConfig can resolve validator groups by kind without ambiguous interface matches, and extract default-value helpers into a dedicated fwserver module.
Surface unexpected GenerateResourceConfig transform errors in diagnostics so import config generation fails with actionable provider-facing messages instead of silently ignoring internal issues.
Add black-box coverage for validator groups, timeouts, and optional numeric zero handling so GenerateResourceConfig behavior stays constrained end to end. Fix number decoding in empty optional normalization so zero values are correctly nulled instead of raising internal errors.
Ignore expected transform-path lookups inside atomic attributes and blocks while still propagating real schema lookup failures. This keeps empty optional normalization lint-clean without regressing GenerateResourceConfig behavior.
Comment on lines -186 to -190
// stateToConfig returns a *tfsdk.Config with a copied value from a tfsdk.State.
func stateToConfig(state tfsdk.State) *tfsdk.Config {
return &tfsdk.Config{
Raw: state.Raw.Copy(),
Schema: state.Schema,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this was inlined

Comment on lines +67 to +78
// smarter algorithm steps:
// 1) Set top level properties named id and timeouts to null
idPath := tftypes.NewAttributePath().WithAttributeName("id")

// id
idAttribute, err := req.State.Schema.AttributeAtTerraformPath(ctx, idPath)
if err == nil && idAttribute.IsComputed() && idAttribute.IsOptional() {
config = nullValueAtPath(config, idPath)
} // else: no id attribute, ignoring

// timeouts
timeoutPath := tftypes.NewAttributePath().WithAttributeName("timeouts")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it would be better if steps 1 and 2 were handled inside of the same tftypes.Transform func.

Comment on lines +354 to +396
// nulls the value at the given path in the value and returns the modified value. If the path does not exist, the original value is returned unmodified.
func nullValueAtPath(value tftypes.Value, path *tftypes.AttributePath) tftypes.Value {
currentValue, ok := valueAtPath(value, path)
if !ok {
return value
}

newValue, err := replaceValueAtPath(value, path, tftypes.NewValue(currentValue.Type(), nil))

if err != nil {
return value
}

return newValue
}

func replaceValueAtPath(value tftypes.Value, path *tftypes.AttributePath, replaceWith tftypes.Value) (tftypes.Value, error) {
steps := path.Steps()

// Top-level attribute replacement needs special handling. During transform the
// root object is visited at the empty path, so replacing a single-step path
// means rebuilding that root object with one field swapped out.
if len(steps) == 1 {
if attributeName, ok := steps[0].(tftypes.AttributeName); ok {
var objectValue map[string]tftypes.Value
if err := value.As(&objectValue); err != nil {
return value, err
}

copiedObjectValue := maps.Clone(objectValue)
copiedObjectValue[string(attributeName)] = replaceWith

return tftypes.NewValue(value.Type(), copiedObjectValue), nil
}
}

return tftypes.Transform(value, func(p *tftypes.AttributePath, v tftypes.Value) (tftypes.Value, error) {
if p.Equal(path) {
return replaceWith, nil
}

return v, nil
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think these helper methods are necessary, tfsdk.State should have a SetAttribute() method that you can use to set an attribute value to null at a specific path.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This file is very difficult to read/understand conceptually. There are a lot of tiny helper functions that require me to jump around in the code and breaks my reading flow. It might be better to inline the logic of a lot of these functions back into their calling functions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should also have test coverage for the different nested block/attribute combinations (list, set, map nested attributes/blocks).

@ansgarm

ansgarm commented May 12, 2026

Copy link
Copy Markdown
Member Author

superseded by #1297 which we're manually fixing :)

@ansgarm ansgarm closed this May 12, 2026
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Jun 11, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants