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

makeDetailedDiff distorts the plan incorrectly deciding whether there are changes or not #1501

Closed
t0yv0 opened this issue Nov 1, 2023 · 6 comments · Fixed by #1893
Closed
Assignees
Labels
bug/diff Bugs in computing Diffs and planning resource changes kind/bug Some behavior is incorrect or out of spec resolution/fixed This issue was fixed

Comments

@t0yv0
Copy link
Member

t0yv0 commented Nov 1, 2023

What happened?

It appears that there are significant corner cases where makeDetailedDiff incorrectly decides pulumirpc.DiffResponse_DiffChanges, where incorrectly means that it does not agree with the underlying upstream provider, on whether there are changes (DiffResponse_DIFF_NONE) or there are no changes (DiffResponse_DIFF_SOME).

Example

Output of pulumi about

N/A

Additional context

We have been trying to reconstruct why this is happening and the current best guess is this block of code:

	// Check both the old state and the new config for diffs and report them as necessary.
	//
	// There is a minor complication here: Terraform has no concept of an "add" diff. Instead, adds are recorded as
	// updates with an old property value of the empty string. In order to detect adds--and to ensure that all diffs
	// in the InstanceDiff are reflected in the resulting Pulumi property diff--we first call this function with
	// each property in a resource's state, then with each property in its config. Any diffs that only appear in the
	// config are treated as adds; diffs that appear in both the state and config are treated as updates.

	forceDiff := new(bool)
	diff := map[string]*pulumirpc.PropertyDiff{}
	for k, v := range olds {
		en, etf, eps := getInfoFromPulumiName(k, tfs, ps, false)
		makePropertyDiff(ctx, en, string(k), v, tfDiff, diff, forceDiff, etf, eps, false, useRawNames(etf))
	}
	for k, v := range news {
		en, etf, eps := getInfoFromPulumiName(k, tfs, ps, false)
		makePropertyDiff(ctx, en, string(k), v, tfDiff, diff, forceDiff, etf, eps, false, useRawNames(etf))
	}
	for k, v := range olds {
		en, etf, eps := getInfoFromPulumiName(k, tfs, ps, false)
		makePropertyDiff(ctx, en, string(k), v, tfDiff, diff, forceDiff, etf, eps, true, useRawNames(etf))
	}

The intention here is to walk Pulumi olds and news values, and translate Pulumi paths to TF diff paths in the process, checking if there is a diff or not. This has worked historically for diffs that originate from the user changing the inputs in a program. HOWEVER, bridged providers allow a degree of flexibility to provider authors to inject diff customizer functions that edit the results of a diff and can suppress or introduce diffs at will. When these changes are happening over values that are not present in Pulumi, the algorithm fails to take them into account.

  sequenceDiagram
      participant Program
      participant Bridge
      participant TFProvider
      Program->>Bridge: Diff(olds={tags={}},news={tags={}})
      Bridge->>TFProvider: SimpleDiff(tr(olds), tr(news))
      TFProvider->>Bridge: terraform.ResourceAttrDiff with "tags.n" added
      Bridge->>Bridge:     makeDetailedDiff traverses olds.tags, news.tags, did not see "tags.n"
      Bridge->>Program:    NO CHANGES (incorrect)
Loading

Contributing

Vote on this issue by adding a 👍 reaction.
To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

@t0yv0 t0yv0 added needs-triage Needs attention from the triage team kind/bug Some behavior is incorrect or out of spec labels Nov 1, 2023
@t0yv0
Copy link
Member Author

t0yv0 commented Nov 1, 2023

What if we introduced a change, under a flag, to always respect TF's diff result in what we emit to Pulumi, moving makeDetailedDiff function to be purely concerned with matters of presentation of the diff's details (which are part of UX but no e2e correctness). And as follow up we'd refactor makeDetailedDiff to be accurate in all circumstances (under heavy test).

@mikhailshilkov mikhailshilkov added bug/diff Bugs in computing Diffs and planning resource changes and removed needs-triage Needs attention from the triage team labels Nov 2, 2023
guineveresaenger added a commit to pulumi/pulumi-gcp that referenced this issue Nov 2, 2023
On top of #1238

The new release of GCP adds a DefaultLabels feature.

This change ports a test matrix from a similar feature of AWS provider.
The matrix tests that for
all interesting label combinations (empty, non-empty, 0, 1, or two
labels, at provider DefaultLabels
or resource Labels level), Pulumi provider can transition a sample
resource from one combination to
another, and the actual effective set of labels is what you would
expect.

What is currently not tested here but may need scrutiny based on similar
issues in AWS:

- passing unknowns into Labels or DefaultLabels
- passing secrets into Labels and making sure this avoids secrets leaks
- EffectiveLabels feature of the GCP provider that detects drift and
pulls labels from the cloud
  into management under GCP; this is not tested here
- working with labels in Plugin Framework based resources
  
The tests are currently failing likely due to a bridge issue:
pulumi/pulumi-terraform-bridge#1501
@t0yv0
Copy link
Member Author

t0yv0 commented Nov 2, 2023

I believe #1491 conclusively fixed it but remains under flag. Once we roll out to AWS and GCP and wait a cycle we can probably remove the flag and adopt the new behavior and close this bug. Open to other rollout plans here.

t0yv0 added a commit that referenced this issue Feb 23, 2024
Fixes pulumi/pulumi-aws#3439

makeDetailedDiff does not report collection changes. It instead hopes
that elements of the collection will produce diff entries. When changes
involve collections all the way down and there are no element entries,
makeDetailedDiff produces no records.

However we have some workarounds now that produce a DIFF_SOME even when
there are no entries per
#1501

```
	if p.info.XSkipDetailedDiffForChanges && len(diff.Attributes()) > 0 {
		changes = pulumirpc.DiffResponse_DIFF_SOME
```

The change in this PR embellishes this case with collection-level diffs
so there is at least something to show.
guineveresaenger added a commit that referenced this issue Apr 23, 2024
Removes the flag option `XSkipDetailedDiffForChanges` and rolls out
behavior to all providers.

This change will break the next bridge release for pulumi-gcp and
pulumi-aws. When updating those providers to these changes, the
`XSkipDetailedDiffForChanges` provider info option must be removed.

Note that the maxItemsOne migration tests needed to be updated to show
that a change of `[]` to `""` reflects a diff on the field in question
now. This makes sense to me, since a nil slice is different from an
empty string, but this may actually not be desired behavior, so I'd
appreciate scrutiny here. Either way, the functionality under test there
requires a diff to happen on MaxItemsOne migrations and that does not
change.

Fixes #1501.
@pulumi-bot pulumi-bot added the resolution/fixed This issue was fixed label Apr 23, 2024
@t0yv0 t0yv0 reopened this Apr 23, 2024
@t0yv0 t0yv0 removed the resolution/fixed This issue was fixed label Apr 23, 2024
@t0yv0
Copy link
Member Author

t0yv0 commented Apr 23, 2024

I'm reopening per recent PR discussion - we had some situations around this and got called out by customers therefore I think more is needed here (possibly #1895 ). The initial "fix" which is really a workaround introduced situations where Pulumi is making a change but the detailed diff does not explain it, which was not acceptable. This led to #1696 to provide an answer in pulumi/pulumi-aws#3439 - this works in the happy case but is not a comprehensive fix.

@t0yv0
Copy link
Member Author

t0yv0 commented Jul 23, 2024

Found a reference on how OpenTOFU decides what kind of plan to undertake based on the PlanResourceChange response from a provider:

https://github.com/opentofu/opentofu/blob/main/internal/tofu/node_resource_abstract_instance.go#L1019

This can likely inform our canonical implementation, with some caveats for pulumi-level features such as precise secrets.

@mjeffryes mjeffryes modified the milestones: 0.108, 0.107 Jul 24, 2024
@VenelinMartinov
Copy link
Contributor

Hit this in pulumi-azure rolling out PRC: pulumi/pulumi-azure#2322 (comment)

@mjeffryes mjeffryes removed this from the 0.108 milestone Aug 19, 2024
VenelinMartinov added a commit that referenced this issue Sep 20, 2024
Adds a `DiffEqualDecisionOverride` to the shim layer which allows
provider implementations to specify a diff decision instead of relying
on the shim layer to do that.

Also adds a `DiffEqualDecisionOverride` to the PRC sdkv2 implementation
which opentofu does.

Also adds a feature flag `EnableAccurateBridgePreview` which guards this
feature.

will fix once rolled out:
#2293
will fix once rolled out:
#1501
will undo once rolled out:
#1502 as the
underlying issue was fixed during the PRC work.
Stacked on #2380
@VenelinMartinov VenelinMartinov self-assigned this Oct 1, 2024
@VenelinMartinov VenelinMartinov added the resolution/fixed This issue was fixed label Oct 1, 2024
@VenelinMartinov
Copy link
Contributor

fixed in #2379 and #2405 and is now behind a feature flag in the bridge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/diff Bugs in computing Diffs and planning resource changes kind/bug Some behavior is incorrect or out of spec resolution/fixed This issue was fixed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants