-
Notifications
You must be signed in to change notification settings - Fork 43
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
Remove custom code for computing planned state #1276
Conversation
Diff for pulumi-random with merge commit 5cb3634 |
Diff for pulumi-azuread with merge commit 5cb3634 |
@@ -38,7 +38,7 @@ outputs: | |||
testOptionalString__expect: |- | |||
input2 | |||
testSetOptionals__actual: ${set.setOptionals} | |||
testSetOptionals__expect: [ "${r.requiredInputStringCopy}", a, b ] | |||
testSetOptionals__expect: [ a, b, "${r.requiredInputStringCopy}" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change caused set elements to be reordered in the list projection to Pulumi. While this should theoretically be alright, as the subsequent Diff recognizes that sets are sets and should not be sensitive to element order, perhaps there are some unintended consequences?
Should the bridge define some guarantees on the canonical set ordering when projecting elements to Pulumi array property values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the bridge needs to define a constant ordering since we expose this data as a list. We shouldn't need to guarantee anything about the ordering, except consistency.
Its not unreasonable to assume that new Resource("one", opt=set[0]); new Resource("two", opt=set[1])
is safe between updates, where a re-order would break this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I grok the example, could you expand.
Since bridged providers customize Diff method sending re-ordered versions of the set should result in a no-changes diff. But I have a hunch somewhere we run into trouble anyway. Would be good to file an issue figuring out where.
Perhaps with ignoreChanges paths is one place.
FWIW this PR seems to move us from "user-defined" ordering to "TF-defined" consistent ordering, indirectly, based on the example changes. There's some subtleties with this. It probably is affected by TF hashing functions and when they change upstream this is likely to reorder sets.
There are also some serious issues with sets on the SDKV2 based providers. I was recently looking at this one:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#1276 (review) has a better example. Basically, external users can rely on the ordering of pulumi lists (and tf sets) such that re-ordering will always cause problems, no matter what the bridge does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we believe that TF-defined sets are better (more consistent, easier to maintain) then I'm ok moving to them as long as we (1) recognize it is a breaking change and (2) put tests and documentation locking that ordering in.
Diff for pulumi-random with merge commit 8124203 |
Diff for pulumi-azuread with merge commit 8124203 |
OK not ready for review quite yet, there's some more edge cases caught by the integration test suite. |
Diff for pulumi-random with merge commit 2bfc532 |
Diff for pulumi-azuread with merge commit 2bfc532 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general this looks good. I'm scared of the set re-ordering though. That seams like a meaningful breaking change that could cause replaces. The obvious example is:
const resource = new Resource("parent")
resource.setProperty.apply(set => {
// Create resources inside an apply,
// each resource is name associated with its ordering
set.map((i, v) => new Child(`child-${i}`, {
needsReplaceOnChanges: v,
}))
}
Here a change in order would cause all children to be replaced.
@@ -45,32 +48,41 @@ type Schema interface { | |||
// | |||
// [State Upgrade]: https://developer.hashicorp.com/terraform/plugin/framework/resources/state-upgrade | |||
ResourceSchemaVersion() int64 | |||
|
|||
Proto() *tfprotov6.Schema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proto() *tfprotov6.Schema | |
// The tfprotov6.Schema associated with `Schema`. If nil, then ... | |
Proto() *tfprotov6.Schema |
} | ||
|
||
func FromProviderSchema(x pschema.Schema) Schema { | ||
attrs := convertMap(FromProviderAttribute, x.Attributes) | ||
blocks := convertMap(FromProviderBlock, x.Blocks) | ||
// Provider schemas cannot be versioned, see also x.GetVersion() always returning 0. | ||
version := int64(0) | ||
return newSchemaAdapter(x, x.Type(), x.DeprecationMessage, attrs, blocks, x.AttributeAtPath, version) | ||
proto, err := schemav6.ProviderSchema(x) | ||
contract.AssertNoError(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why this is safe?
contract.AssertNoError(err) | |
contract.AssertNoErrorf(err, "Will not error because...") |
func (r *schemaExtractingResource) Create(context.Context, resource.CreateRequest, *resource.CreateResponse) { | ||
} | ||
|
||
func (r *schemaExtractingResource) Read(context.Context, resource.ReadRequest, *resource.ReadResponse) { | ||
} | ||
|
||
func (r *schemaExtractingResource) Update(context.Context, resource.UpdateRequest, *resource.UpdateResponse) { | ||
} | ||
|
||
func (r *schemaExtractingResource) Delete(context.Context, resource.DeleteRequest, *resource.DeleteResponse) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we assert that these methods will not be called (and then panic)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this would reduce branch coverage :)
@@ -0,0 +1,81 @@ | |||
// Copyright 2016-2023, Pulumi Corporation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is called testbridge_resource_compopt.go
If compopt
is "component options", can we just say that? Otherwise, can we say what it is?
@@ -38,7 +38,7 @@ outputs: | |||
testOptionalString__expect: |- | |||
input2 | |||
testSetOptionals__actual: ${set.setOptionals} | |||
testSetOptionals__expect: [ "${r.requiredInputStringCopy}", a, b ] | |||
testSetOptionals__expect: [ a, b, "${r.requiredInputStringCopy}" ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the bridge needs to define a constant ordering since we expose this data as a list. We shouldn't need to guarantee anything about the ordering, except consistency.
Its not unreasonable to assume that new Resource("one", opt=set[0]); new Resource("two", opt=set[1])
is safe between updates, where a re-order would break this.
|
||
prov := &schema.Provider{ | ||
ResourcesMap: map[string]*schema.Resource{ | ||
"xres": res, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"xres": res, | |
resourceName: res, |
ctypack "github.com/zclconf/go-cty/cty/msgpack" | ||
) | ||
|
||
func ProposedNew( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the public entry point for this package. Can we add a comment explaining why it exists and what it does.
If we don't believe another repository could consume this function, we should mark it as unstable for consumption. We should be clear on when we adopt a backwards compatibility requirement.
Obsolete now, the objective is met without this PR. |
Factors out ProposedNew into its own package so both Plugin Framework providers and SDKv2-based providers that opt into DiffStrategy=PlanState call the exact same logical implementation that is linked from TF CLI sources (objchange.ProposedNew).
Previously, PF-based providers used a homegrown implementation that was likely diverging from TF implementation in some of the edge cases. The PR trades off maintaining that implementation (which is no longer necessary) to maintaining some adapter boilerplate code.