Skip to content
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

Fix schema path elem traversal #1757

Merged
merged 2 commits into from
Mar 14, 2024
Merged

Conversation

iwahbe
Copy link
Member

@iwahbe iwahbe commented Mar 13, 2024

Fixes pulumi/pulumi-gcp#1794

This is the second attempt at fixing pulumi/pulumi-gcp#1794, so strict scrutiny would be appreciated.

The core of the issue is correctly interpreting this block:

// s.Elem() may return a nil, a Schema value, or a Resource value.
//
// The design of Elem() follows Terraform Plugin SDK directly. Case analysis:
//
// Case 1: s represents a compound type (s.Type() is one of TypeList, TypeSet or TypeMap), and s.Elem()
// represents the element of this type as a Schema value. That is, if s ~ List[String] then s.Elem() ~ String.
//
// Case 2: s represents a single-nested Terraform block. Logically this is like s having an anonymous object
// type such as s ~ {"x": Int, "y": String}. In this case s.Type() == TypeMap and s.Elem() is a Resource value.
// This value is not a real Resource and only implements the Schema field to enable inspecting s.Elem().Schema()
// to find out the names ("x", "y") and types (Int, String) of the block properties.
//
// Case 3: s represents a list or set-nested Terraform block. That is, s ~ List[{"x": Int, "y": String}]. In
// this case s.Type() is one of TypeList, TypeSet, and s.Elem() is a Resource that encodes the object type
// similarly to Case 2.
//
// Case 4: s.Elem() is nil and s.Type() is a scalar type (none of TypeList, TypeSet, TypeMap).
//
// Case 5: s.Elem() is nil but s.Type() is one of TypeList, TypeSet, TypeMap. The element type is unknown.
//
// This encoding cannot support map-nested blocks or object types as it would introduce confusion with Case 2,
// because Map[String, {"x": Int}] and {"x": Int} both have s.Type() = TypeMap and s.Elem() being a Resource.
// Following the Terraform design, only set and list-nested blocks are supported.
//
// See also: https://github.com/hashicorp/terraform-plugin-sdk/blob/main/helper/schema/schema.go#L231
Elem() interface{}

From what I can tell, both propertyPathToSchemaPathInner and schemaPathToPropertyPathInner confuse case 3 for case 2:

propertyPathToSchemaPathInner and schemaPathToPropertyPathInner correctly handle case 2 ((schema, ps) ~ {x: T}), traversing (schema.Elem().(shim.Resource).Schema(), ps.Fields). This is correct, as the .Elem() in the shim path is a fiction of representation. ps.Fields correctly represents that (schema, ps) is the object ({x: T}) in question.

Currently, both functions incorrectly handle case 3 ((schema, ps) ~ List[{x: T}], (schema.Elem(), ps.Elem) ~ {x: T}), treating it identically to case 2. The correct traversal for the nested object is (schema.Elem().(shim.Resource).Schema(), ps.Elem.Fields) (note the additional .Elem after ps). This PR makes that change, and adds a test case to lock it in.

Copy link

codecov bot commented Mar 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 59.30%. Comparing base (54802d5) to head (07b2c1c).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1757      +/-   ##
==========================================
- Coverage   59.79%   59.30%   -0.50%     
==========================================
  Files         300      307       +7     
  Lines       42025    42418     +393     
==========================================
+ Hits        25129    25154      +25     
- Misses      15474    15840     +366     
- Partials     1422     1424       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@VenelinMartinov VenelinMartinov left a comment

Choose a reason for hiding this comment

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

Looks sensible but do we have enough coverage here given the previous regressions? I don't want to block on this if you are certain of the fix but it'd seem prudent to add some coverage if we missed this last time.

case shim.Resource: // object element type
return schemaPathToPropertyPath(basePath, schemaPath[1:], e.Schema(), schemaInfo.Fields)
elem := schemaInfo.Elem
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this also need a test? Looks like the tests only cover the other direction.

Copy link
Member Author

Choose a reason for hiding this comment

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

The test is bi-directional. Both changes are covered.


I actually only noticed that this needed to be fixed because the test I added was still failing.

pkg/tfbridge/walk.go Show resolved Hide resolved
@iwahbe
Copy link
Member Author

iwahbe commented Mar 13, 2024

Looks sensible but do we have enough coverage here given the previous regressions? I don't want to block on this if you are certain of the fix but it'd seem prudent to add some coverage if we missed this last time.

We have coverage over the material that this PR changed. In terms of general coverage of makeTerraformInputs (last regression), more coverage would help, but I'm comfortable merging since the issue was caught by provider tests and didn't make it into a release.

I expect that closing #1282 will give us lots of coverage over makeTerraformInputs.

case shim.Resource: // object element type
return propertyPathToSchemaPath(basePath.Element(), elemPP, e.Schema(), schemaInfo.Fields)
elem := schemaInfo.Elem
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, very annoying omission. For this case schemaInfo.Elem.Fields makes so much more sense.

Copy link
Member

@t0yv0 t0yv0 left a comment

Choose a reason for hiding this comment

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

Thank you!

@iwahbe iwahbe merged commit 0d7f807 into master Mar 14, 2024
9 checks passed
@iwahbe iwahbe deleted the iwahbe/fix-schemaPath-elem-traversal branch March 14, 2024 15:09
VenelinMartinov added a commit to pulumi/pulumi-gcp that referenced this pull request Mar 21, 2024
iwahbe added a commit that referenced this pull request Mar 27, 2024
While discussing #1757, there was some uncertainty on how to align
`*SchemaInfo` with the underlying `shim.Schema`. This PR clarifies by
introducing a user error during `make tfgen` time if the user provides a
misaligned or nonsensical `*SchemaInfo`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

node: pulumiLabels uniqueness error for a Cloud Run service in version 7.12.0
3 participants