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

Gracefully handle ignoreChanges without user needing to refresh a stack #2566

Merged
merged 10 commits into from
Sep 22, 2023

Conversation

rquitales
Copy link
Contributor

@rquitales rquitales commented Sep 13, 2023

Note: this is stacked on top of #2570

This PR updates the logic for handling fields added to ignoreChanges. Previously, to accurately ignore a field without hitting an SSA conflict error, the Pulumi user would need to run a refresh BEFORE running pulumi up or pulumi preview. This is due to the provider using the last known value of the ignored field stored in state when computing what should be set in the ignored field when the resource is sent to the k8s API. If drift has occurred on that field and is not reflected in the Pulumi state as it is out of date, then the provider sends old information to the API server resulting in a field conflict error.

As we hit the live server to obtain the resources' up to date resourceVersion, we can also use this API result to gracefully handle fields marked within ignoreChanges. This PR uses the fieldpath package from upstream k8s libraries to parse the serialized json managed fields entries and compares it to a normalized version of the Pulumi program's ignoreFields value.

Fixes: #2542

@github-actions
Copy link

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

@codecov-commenter
Copy link

codecov-commenter commented Sep 13, 2023

Codecov Report

Merging #2566 (3a915cd) into master (d2a3b8c) will decrease coverage by 0.20%.
Report is 1 commits behind head on master.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##           master    #2566      +/-   ##
==========================================
- Coverage   18.64%   18.45%   -0.20%     
==========================================
  Files          47       47              
  Lines        9434     9523      +89     
==========================================
- Hits         1759     1757       -2     
- Misses       7576     7667      +91     
  Partials       99       99              
Files Changed Coverage Δ
provider/pkg/await/await.go 0.00% <0.00%> (ø)
provider/pkg/provider/provider.go 7.37% <0.00%> (-0.03%) ⬇️

... and 1 file with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@rquitales rquitales marked this pull request as ready for review September 19, 2023 21:37
@rquitales rquitales changed the title Test ignore_changes conflict Gracefully handle ignoreChanges without user needing to refresh a stack Sep 19, 2023
@rquitales rquitales requested review from EronWright and a team September 19, 2023 21:52
Copy link
Member

@iwahbe iwahbe left a comment

Choose a reason for hiding this comment

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

I don't have the context to review on the feature change, but I left some local comments.

provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
tests/sdk/nodejs/nodejs_test.go Outdated Show resolved Hide resolved
tests/sdk/nodejs/nodejs_test.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
provider/pkg/await/await.go Outdated Show resolved Hide resolved
Copy link
Contributor

@EronWright EronWright left a comment

Choose a reason for hiding this comment

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

Good job adding the CSA support!

@@ -498,13 +502,43 @@ func ssaUpdate(c *UpdateConfig, liveOldObj *unstructured.Unstructured, client dy
return currentOutputs, nil
}

// handleCSAIgnoreFields handles updating the inputs to use the last known value applied to the cluster. If the value is not present,
// then we use what is declared in state as per the specs of Pulumi's ignoreChanges.
func handleCSAIgnoreFields(c *UpdateConfig, liveOldObj *unstructured.Unstructured) error {
Copy link
Member

Choose a reason for hiding this comment

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

I've not a good intuition around liveOldObj *unstructured.Unstructur and *UpdateConfig but this looks kind of similar to what I've seen bridged providers have to do for ignoreChanges.. It makes sense with he comment 👍

return fmt.Errorf("unable to parse ignoreField path %q: %w", ignorePath, err)
}

pathComponents := strings.Split(ipParsed.String(), ".")
Copy link
Member

Choose a reason for hiding this comment

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

Are we not worried here, this conversion would just work? ipParsed will have strings or integers (to drill down arrays), for example:

"foo", 0, "barProperty"

Does strings.Split(ipParsed.String(), ".") give you what you expect for the numbers?

Copy link
Member

Choose a reason for hiding this comment

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

Will this ever receive '*' as a path fragment? Pulumi docs permit patterns like this one:

foo.*

But we're lacking great SDK API to make it easy to implement. I wonder if the user specifies that will it hit this code or be resolved higher up the stack.


pathComponents := strings.Split(ipParsed.String(), ".")

lastLiveVal, found, err := unstructured.NestedFieldCopy(liveOldObj.Object, pathComponents...)
Copy link
Member

Choose a reason for hiding this comment

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

Do paths expected by unstructured.NestedFieldCopy map 1:1 to pulumi property paths? No "foo_bar=>fooBar" renaming? No off-by-1 errors? (those may be specific to TF where pulumi paths are shorter than TF paths sometimes).

@@ -527,6 +561,7 @@ func handleSSAIgnoreFields(c *UpdateConfig, liveOldObj *unstructured.Unstructure
return fmt.Errorf("unable to parse ignoreField path %q: %w", ignorePath, err)
}

// TODO: Enhance support for ignoreField path to support nested arrays.
Copy link
Member

Choose a reason for hiding this comment

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

Ah here we go again. Might be worth lifting this comment and the split logic into one helper function so it's in one place.

@t0yv0 t0yv0 self-requested a review September 22, 2023 15:55
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.

This LGTM, I left some comments per Pulumi side but I lack a good intuition yet around this provider.

@rquitales rquitales merged commit 8f21952 into master Sep 22, 2023
18 checks passed
@rquitales rquitales deleted the rquitales/fix-ignore-changes branch September 22, 2023 19:59
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.

Change to unrelated deployment spec property causes ignore_changes to fail
5 participants