Skip to content

update webhooks: handle resourceVersion conflicts properly#2009

Open
multi-io wants to merge 1 commit intokubermatic:mainfrom
syseleven:admission_handle_version_conflicts
Open

update webhooks: handle resourceVersion conflicts properly#2009
multi-io wants to merge 1 commit intokubermatic:mainfrom
syseleven:admission_handle_version_conflicts

Conversation

@multi-io
Copy link
Copy Markdown
Contributor

@multi-io multi-io commented Mar 31, 2026

This changes the mutating webhook handler's behaviour in case of version conflicts.

If an update had a metadata.resourceVersion conflict, it makes no sense to perform the webhook's normal checks, e.g. for .spec immutability, as those checks might fail just because the base resourceVersion isn't the same.

For example, if the client is trying to update based on an outdated version of the resource, the .spec might be different from the in-cluster version just because of that, triggering the corresponding webhook check and responding with a 400, even though 409 would be the correct response that allows the client to perform proper conflict handling.

So in case of a resourceVersion conflict the webhook now just returns success, which causes the API server to fall back to its default handling, which will detect the resourceVersion conflict and return the 409 itself.

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes #

What type of PR is this?

/kind design

Special notes for your reviewer:

Does this PR introduce a user-facing change? Then add your Release Note here:


Documentation:

NONE

…'s default handling

If the update had a resourceVersion conflict, it makes no sense to
perform the webhook's normal checks, e.g. for .spec immutability, as
those checks might fail just because the base resourceVersion isn't the
same.

For example, if the client is trying to update based on an outdated
version of the resource, the .spec might be different just because of
that, triggering the corresponding webhook check and reponding with a
400, even though 409 would be the correct response that allows the
client to perform proper conflict handling.

So in case of a resourceVersion conflict the webhook now just returns
success, which causes the API server to fall back to its default
handling, which will detect the resourceVersion conflict and return the
409 itself.

Signed-off-by: Olaf Klischat <olaf.klischat@gmail.com>
@kubermatic-bot kubermatic-bot added the kind/design Categorizes issue or PR as related to design. label Mar 31, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubermatic-bot kubermatic-bot added do-not-merge/docs-needed Indicates that a PR should not merge because it's missing one of the documentation labels. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. labels Mar 31, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign julioc-p for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubermatic-bot kubermatic-bot added sig/cluster-management Denotes a PR or issue as being assigned to SIG Cluster Management. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Mar 31, 2026
@kubermatic-bot
Copy link
Copy Markdown
Contributor

Hi @multi-io. Thanks for your PR.

I'm waiting for a kubermatic member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubermatic-bot kubermatic-bot added the size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. label Mar 31, 2026
@multi-io multi-io changed the title update webhooks: hand resourceVersion conflicts properly update webhooks: handle resourceVersion conflicts properly Mar 31, 2026
@kron4eg kron4eg requested a review from Copilot March 31, 2026 23:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts the mutating admission webhook behavior for Machine and MachineDeployment updates so that metadata.resourceVersion conflicts don’t get masked by webhook validation errors, allowing the Kubernetes API server to return the correct 409 Conflict.

Changes:

  • Add a resourceVersion mismatch shortcut on Machine updates to immediately allow the request.
  • Add a similar resourceVersion mismatch shortcut on MachineDeployment updates to immediately allow the request.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
pkg/admission/machines.go Adds an early return on Update when OldObject/Object resourceVersion differs to avoid webhook immutability checks masking 409 conflicts.
pkg/admission/machinedeployments.go Adds a resourceVersion mismatch bypass on Update, but currently placed after validation/mutation logic and includes a formatting issue.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +58 to +61
if oldMachineDeployment.ResourceVersion != machineDeployment.ResourceVersion {
// resource version conflict. Return success to fall back to the API server's default handler, which will respond with a proper 409
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

In the conflict branch, the handler currently reaches this resourceVersion check only after running defaulting/mutations and validateMachineDeployment earlier in the function. That means an update with an outdated resourceVersion can still be rejected by the webhook with a 400 before the API server returns the intended 409. Consider moving the resourceVersion mismatch check to the very start of the Update path (before any mutation/validation) and returning Allowed=true with no patch when it mismatches.

Copilot uses AI. Check for mistakes.
}
if oldMachineDeployment.ResourceVersion != machineDeployment.ResourceVersion {
// resource version conflict. Return success to fall back to the API server's default handler, which will respond with a proper 409
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This line has inconsistent indentation (spaces instead of tabs) and will be rewritten by gofmt; it may also fail formatting/lint checks in CI. Please run gofmt (or fix indentation) so the return statement is properly aligned with the surrounding block.

Suggested change
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +60
// resource version conflict. Return success to fall back to the API server's default handler, which will respond with a proper 409
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This new resourceVersion-conflict bypass is a behavior change that is currently untested. Please add a unit test that constructs an Update AdmissionRequest where OldObject.resourceVersion != Object.resourceVersion and asserts the mutator returns Allowed=true (and does not fail validation / does not return a patch).

Suggested change
// resource version conflict. Return success to fall back to the API server's default handler, which will respond with a proper 409
return createAdmissionResponse(log, machineDeploymentOriginal, &machineDeployment)
// Resource version conflict. Return success without a patch so the API server can respond with a proper 409.
return &admissionv1.AdmissionResponse{Allowed: true}, nil

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +68
if oldMachine.ResourceVersion != machine.ResourceVersion {
// resource version conflict. Return success to fall back to the API server's default handler, which will respond with a proper 409
return createAdmissionResponse(log, machineOriginal, &machine)
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This new resourceVersion-conflict bypass is a behavior change that is currently untested. Please add a unit test that constructs an Update AdmissionRequest where OldObject.resourceVersion != Object.resourceVersion and asserts the mutator returns Allowed=true (and does not run the immutability checks / does not return a patch).

Copilot uses AI. Check for mistakes.
@kubermatic-bot kubermatic-bot added docs/none Denotes a PR that doesn't need documentation (changes). and removed do-not-merge/docs-needed Indicates that a PR should not merge because it's missing one of the documentation labels. labels Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Denotes that all commits in the pull request have the valid DCO signoff message. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. docs/none Denotes a PR that doesn't need documentation (changes). kind/design Categorizes issue or PR as related to design. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. sig/cluster-management Denotes a PR or issue as being assigned to SIG Cluster Management. size/XS Denotes a PR that changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants