Skip to content

Fix conversion webhook crash on legacy featureGates empty-object shape - #4552

Closed
kaovilai wants to merge 1 commit into
kubevirt:mainfrom
kaovilai:fix-4549-featuregates-conversion-webhook
Closed

kaovilai wants to merge 1 commit into
kubevirt:mainfrom
kaovilai:fix-4549-featuregates-conversion-webhook

Conversation

@kaovilai

Copy link
Copy Markdown

Summary

Root cause of #4549: some objects persisted before v1.19 have spec.featureGates stored as an empty JSON object ({}) instead of an empty array — a legacy artifact of an older, struct-based representation.

The mutating webhook already has a narrow recovery for this shape (recoverBadFeatureGates in pkg/webhooks/mutator/hyperConvergedMutator.go), but only when it hits an old-object decode failure during an Update admission request.

The CRD conversion webhook has no equivalent safety net: controller-runtime decodes the raw stored (hub, v1) bytes into hcov1.HyperConverged before ConvertFrom/ConvertTo ever run (see vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go's handleConvertRequest), so any HyperConverged object with this legacy shape becomes permanently unreadable via the v1beta1 API — reproducing the exact error from the issue on every read.

Fix

Give HyperConvergedFeatureGates (api/v1/featuregates/feature_gates.go) a custom UnmarshalJSON that treats an empty JSON object as an empty list, and returns a real error for a non-empty object (so genuine corruption isn't silently swallowed). Since this is a method on the type itself, it fixes every decode path uniformly (conversion webhook, mutating webhook, reconciler, apiserver) instead of only the one admission-webhook code path that already had a workaround.

Testing

  • api/v1/featuregates/feature_gates_test.go: unmarshal of {} (bare and nested in a struct field, mirroring the webhook decode) now succeeds as an empty list; a non-empty object is still rejected.
  • api/v1beta1/conversion_test.go: reproduces the exact issue scenario — json.Unmarshal of raw hub-version bytes with "featureGates":{}" now succeeds, and the object converts via ConvertFrom cleanly.
  • Verified both new tests fail with the exact quoted error from the issue on main, and pass with this fix.

Fixes #4549

Note

Responses generated with Claude

Some objects persisted before v1.19 have spec.featureGates stored as an
empty JSON object ("{}") instead of an empty array. The mutating webhook
already has a narrow recovery for this shape (recoverBadFeatureGates),
but only when it hits an old-object decode failure during an Update
admission request.

The CRD conversion webhook has no such safety net: controller-runtime
decodes the raw stored (hub) bytes into hcov1.HyperConverged before our
ConvertFrom/ConvertTo ever run, so any HyperConverged with this legacy
shape becomes permanently unreadable via the v1beta1 API.

Give HyperConvergedFeatureGates a custom UnmarshalJSON that treats an
empty JSON object as an empty list, fixing every decode path uniformly
instead of just the admission-webhook update path.

Fixes kubevirt#4549

> [!Note]
> Responses generated with Claude

Signed-off-by: Tiger Kaovilai <passawit.kaovilai@gmail.com>
@kubevirt-prow

kubevirt-prow Bot commented Aug 30, 2026

Copy link
Copy Markdown

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.

@kubevirt-prow kubevirt-prow Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit message. labels Aug 30, 2026
@kubevirt-prow

kubevirt-prow Bot commented Aug 30, 2026

Copy link
Copy Markdown

Invalid commit message issues detected

Invalid commit messages

Keywords which can automatically close issues and hashtag(#) mentions are not allowed.

  • 410aafe Fix conversion webhook crash on legacy featureGates empty-object shape

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. I understand the commands that are listed here.

@kubevirt-prow kubevirt-prow Bot added dco-signoff: yes Indicates the PR's author has DCO signed all their commits. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Aug 30, 2026
@kubevirt-prow

kubevirt-prow Bot commented Aug 30, 2026

Copy link
Copy Markdown

[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 sradco 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

@kubevirt-prow

kubevirt-prow Bot commented Aug 30, 2026

Copy link
Copy Markdown

Hi @kaovilai. Thanks for your PR.

PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test all.

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.

@openshift-ci openshift-ci Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Aug 30, 2026
@openshift-ci

openshift-ci Bot commented Aug 30, 2026

Copy link
Copy Markdown

Hi @kaovilai. Thanks for your PR.

I'm waiting for a kubevirt 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.

Tip

We noticed you've done this a few times! Consider joining the org to skip this step and gain /lgtm and other bot rights. We recommend asking approvers on your previous PRs to sponsor you.

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.

@kubevirt-prow kubevirt-prow Bot added the size/M label Aug 30, 2026
@sonarqubecloud

Copy link
Copy Markdown

@kaovilai
kaovilai marked this pull request as ready for review August 30, 2026 15:01
@kubevirt-prow kubevirt-prow Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 30, 2026
@kubevirt-prow
kubevirt-prow Bot requested review from orenc1 and sradco August 30, 2026 15:01
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 934f2421-b454-4e40-941c-28bc725e9ad2

📥 Commits

Reviewing files that changed from the base of the PR and between c3dcc65 and 410aafe.

📒 Files selected for processing (3)
  • api/v1/featuregates/feature_gates.go
  • api/v1/featuregates/feature_gates_test.go
  • api/v1beta1/conversion_test.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • kubevirt/kubevirt (manual)
  • kubevirt/hyperconverged-cluster-operator (manual)
  • kubevirt/monitoring (manual)

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The change adds custom JSON decoding for HyperConvergedFeatureGates. Empty legacy objects decode as empty lists, while non-empty objects return errors. Tests cover direct decoding, nested spec.featureGates decoding, and conversion from v1 to v1beta1.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: 🟡 Moderate · up to 410aa

The change safely restores decoding of legacy empty feature-gate objects while continuing to reject non-empty malformed objects, reducing conversion failures for affected resources without broadening feature-gate behavior. The PR is not currently merge-ready because required release-note, commit-message, and test-approval gates remain outstanding.

Assessment against linked issues

Objective Addressed Explanation
Support v1beta1-to-v1 conversion when spec.featureGates contains a legacy empty object [#4549] ✅
Preserve rejection of invalid non-empty object shapes [#4549] ✅

Warning

Linked repositories: Your configuration references 13 linked repositories, but your current plan allows 10. Analyzed kubevirt/kubevirt, kubevirt/containerized-data-importer, kubevirt/ssp-operator, kubevirt/cluster-network-addons-operator, kubevirt/hostpath-provisioner-operator, kubevirt/application-aware-quota, kubevirt/managed-tenant-quota, kubevirt/hyperconverged-cluster-operator, kubevirt/monitoring, kubevirt/community, skipped kubevirt/enhancements, kubevirt/project-infra, kubevirt/kubevirtci.


Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. Analyzed kubevirt/kubevirt, kubevirt/hyperconverged-cluster-operator, kubevirt/monitoring, skipped kubevirt/containerized-data-importer, kubevirt/ssp-operator, kubevirt/cluster-network-addons-operator, kubevirt/hostpath-provisioner-operator, kubevirt/application-aware-quota, kubevirt/managed-tenant-quota, kubevirt/community.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nunnatsa

Copy link
Copy Markdown
Collaborator

/ok-to-test

Thanks you very much for this PR @kaovilai !

I'm hunting this issue for a long time now. I couldn't find the root cause. I mean - yes, somehow the stored v1 object is with spec.featureGates of and empty object, but what caused it? I prefer to find the actual root cause before applying your fix, which makes sense, but it does not solve the actual issue, that I'm still looking for. For now, I couldn't find the root cause in release-1.18 not in release-1.19 branches. If the root cause is in some other component that somehow bypasses the conversion logic, then I'll merge this PR.

In the meantime, please fix the commit message and add the missing release-notes to the PR description, because currently the PR is blocked.

@openshift-ci openshift-ci Bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Aug 31, 2026
@nunnatsa

Copy link
Copy Markdown
Collaborator

@kaovilai - it seems that the fix in #4493 is not needed after your fix, and that fails the unit tests. we need to check if we can fully remove the logic added in #4493.

@kubevirt-prow

kubevirt-prow Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

@kaovilai: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-hyperconverged-cluster-operator-unit-test-s390x 410aafe link true /test pull-hyperconverged-cluster-operator-unit-test-s390x
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. I understand the commands that are listed here.

@nunnatsa

Copy link
Copy Markdown
Collaborator

@kaovilai - it seems that the fix in #4493 is not needed after your fix, and that fails the unit tests. we need to check if we can fully remove the logic added in #4493.

OK, the logic added to pkg/webhooks/mutator/hyperConvergedMutator.go in #4493 is now redundant and should be removed.

However, let's keep the "should recover from a bad featureGate format" unit test in pkg/webhooks/mutator/hyperConvergedMutator_test.go, but change it to expect res.Patches to be empty; i.e.
modify pkg/webhooks/mutator/hyperConvergedMutator_test.go lines 608 to Expect(res.Patches).To(BeEmpty()), and delete line 609.

@openshift-ci

openshift-ci Bot commented Aug 31, 2026

Copy link
Copy Markdown

@kaovilai: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/hco-e2e-kv-smoke-gcp 410aafe link true /test hco-e2e-kv-smoke-gcp
ci/prow/hco-e2e-operator-sdk-gcp 410aafe link true /test hco-e2e-operator-sdk-gcp
ci/prow/hco-e2e-consecutive-operator-sdk-upgrades-azure 410aafe link true /test hco-e2e-consecutive-operator-sdk-upgrades-azure
ci/prow/hco-e2e-upgrade-operator-sdk-aws 410aafe link true /test hco-e2e-upgrade-operator-sdk-aws
ci/prow/hco-e2e-upgrade-prev-operator-sdk-azure 410aafe link true /test hco-e2e-upgrade-prev-operator-sdk-azure

Full PR test history. Your PR dashboard.

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. I understand the commands that are listed here.

@hco-bot

hco-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

hco-e2e-consecutive-operator-sdk-upgrades-aws lane succeeded.
/override ci/prow/hco-e2e-consecutive-operator-sdk-upgrades-azure
hco-e2e-operator-sdk-aws, hco-e2e-operator-sdk-azure lanes succeeded.
/override ci/prow/hco-e2e-operator-sdk-gcp
hco-e2e-upgrade-operator-sdk-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-operator-sdk-aws

@kubevirt-prow

kubevirt-prow Bot commented Aug 31, 2026

Copy link
Copy Markdown

@hco-bot: Overrode contexts on behalf of hco-bot: ci/prow/hco-e2e-consecutive-operator-sdk-upgrades-azure, ci/prow/hco-e2e-operator-sdk-gcp, ci/prow/hco-e2e-upgrade-operator-sdk-aws

Details

In response to this:

hco-e2e-consecutive-operator-sdk-upgrades-aws lane succeeded.
/override ci/prow/hco-e2e-consecutive-operator-sdk-upgrades-azure
hco-e2e-operator-sdk-aws, hco-e2e-operator-sdk-azure lanes succeeded.
/override ci/prow/hco-e2e-operator-sdk-gcp
hco-e2e-upgrade-operator-sdk-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-operator-sdk-aws

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.

@hco-bot

hco-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

hco-e2e-upgrade-prev-operator-sdk-aws lane succeeded.
/override ci/prow/hco-e2e-upgrade-prev-operator-sdk-azure

@kubevirt-prow

kubevirt-prow Bot commented Aug 31, 2026

Copy link
Copy Markdown

@hco-bot: Overrode contexts on behalf of hco-bot: ci/prow/hco-e2e-upgrade-prev-operator-sdk-azure

Details

In response to this:

hco-e2e-upgrade-prev-operator-sdk-aws lane succeeded.
/override ci/prow/hco-e2e-upgrade-prev-operator-sdk-azure

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.

@hco-bot

hco-bot commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

hco-e2e-kv-smoke-azure lane succeeded.
/override ci/prow/hco-e2e-kv-smoke-gcp

@kubevirt-prow

kubevirt-prow Bot commented Aug 31, 2026

Copy link
Copy Markdown

@hco-bot: Overrode contexts on behalf of hco-bot: ci/prow/hco-e2e-kv-smoke-gcp

Details

In response to this:

hco-e2e-kv-smoke-azure lane succeeded.
/override ci/prow/hco-e2e-kv-smoke-gcp

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.

@nunnatsa

nunnatsa commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

I found the actual root cause. Details are here: #4549 (comment)

Giving this new information, the fix here is not enough, and will hide other issues.

@nunnatsa

nunnatsa commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

/hold

@kubevirt-prow kubevirt-prow Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Sep 1, 2026
@nunnatsa

nunnatsa commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Opened #4557 to try to solve this issue.

@kaovilai

kaovilai commented Sep 2, 2026

Copy link
Copy Markdown
Author

Ok. thanks for review.

@kaovilai

kaovilai commented Sep 3, 2026

Copy link
Copy Markdown
Author

Superceded by 4557

@kaovilai kaovilai closed this Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has DCO signed all their commits. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. do-not-merge/invalid-commit-message Indicates that a PR should not merge because it has an invalid commit 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. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v1beta1→v1 conversion webhook fails on spec.featureGates: "cannot unmarshal object into Go struct field HyperConvergedSpec.spec.featureGates"

3 participants