Skip to content

CNV-94727: fix bad conversion on upgrade - #4493

Merged
kubevirt-prow[bot] merged 1 commit into
kubevirt:mainfrom
nunnatsa:fix-CNV-94727
Aug 11, 2026
Merged

kubevirt-prow[bot] merged 1 commit into
kubevirt:mainfrom
nunnatsa:fix-CNV-94727

Conversation

@nunnatsa

Copy link
Copy Markdown
Collaborator

What this PR does / why we need it:

For some unknown reasons, sometimes during an upgrade from v1.18, the featureGates field becomes an empty object instead of an empty array.

Trying to recover from this edge case by removing the featureGates field.

Jira Ticket:

https://redhat.atlassian.net/browse/CNV-94727

Release note:

None

@kubevirt-prow kubevirt-prow Bot added release-note-none Denotes a PR that doesn't merit a release note. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. labels Aug 11, 2026
@kubevirt-prow
kubevirt-prow Bot requested review from avlitman and sradco August 11, 2026 07:55
@kubevirt-prow kubevirt-prow Bot added the size/L label Aug 11, 2026
@coderabbitai

coderabbitai Bot commented Aug 11, 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: d6b863ee-8c9b-4608-90bb-6ae019957f40

📥 Commits

Reviewing files that changed from the base of the PR and between 513f9ee and 6ae39d1.

📒 Files selected for processing (1)
  • pkg/webhooks/mutator/hyperConvergedMutator.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)

📝 Walkthrough

Walkthrough

The update webhook now recovers old HyperConverged objects with an empty-object spec.featureGates representation. Recovery validates and repairs the unstructured object, adds a removal patch when needed, and preserves valid new feature gates. Tests cover these cases and replace ptr.To fixture construction with new.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Warning

Review ran into problems

🔥 Problems

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/webhooks/mutator/hyperConvergedMutator.go (1)

397-417: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use descriptive feature-gate variable names.

Rename fgs, fgsObj, and fgsBytes to names such as featureGates, featureGatesObject, and featureGatesBytes. This avoids lowercase acronyms in new code.

As per path instructions, “use fully upper-cased acronyms in names.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/webhooks/mutator/hyperConvergedMutator.go` around lines 397 - 417, Rename
the local variables fgs, fgsObj, and fgsBytes in the feature-gates handling
logic to descriptive names such as featureGates, featureGatesObject, and
featureGatesBytes, updating all references while preserving the existing
behavior.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/webhooks/mutator/hyperConvergedMutator_test.go`:
- Around line 592-630: Add a negative update test alongside the existing bad
feature-gate recovery cases that corrupts a field outside spec.featureGates in
the old object, causing DecodeRaw to fail. Invoke mutator.Handle and assert the
response is rejected with HTTP 400, ensuring unrelated decode errors are not
recovered from.

In `@pkg/webhooks/mutator/hyperConvergedMutator.go`:
- Around line 412-417: Update the error-reporting branch in the featureGates
handling to stop logging req.OldObject.Raw and the serialized fgsBytes values.
Replace both concatenated messages with a safe static message describing the
unexpected featureGates format, while preserving the existing err-dependent
branching.

---

Nitpick comments:
In `@pkg/webhooks/mutator/hyperConvergedMutator.go`:
- Around line 397-417: Rename the local variables fgs, fgsObj, and fgsBytes in
the feature-gates handling logic to descriptive names such as featureGates,
featureGatesObject, and featureGatesBytes, updating all references while
preserving the existing behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a01eea01-aa05-4b00-829e-6141457b2008

📥 Commits

Reviewing files that changed from the base of the PR and between 4b4481f and 513f9ee.

📒 Files selected for processing (2)
  • pkg/webhooks/mutator/hyperConvergedMutator.go
  • pkg/webhooks/mutator/hyperConvergedMutator_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)

Comment on lines +592 to +630
It("should recover from a bad featureGate format", func(ctx context.Context) {
origCR := cr.DeepCopy()

req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)}

unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&origCR)
Expect(err).NotTo(HaveOccurred())
unstructuredObj["spec"].(map[string]any)["featureGates"] = map[string]any{}
badOrigHC, err := json.Marshal(unstructuredObj)
Expect(err).NotTo(HaveOccurred())

req.OldObject.Raw = badOrigHC

res := mutator.Handle(ctx, req)
Expect(res.Allowed).To(BeTrue())

Expect(res.Patches).ToNot(BeEmpty())
Expect(res.Patches).To(ContainElement(jsonpatch.JsonPatchOperation{Operation: "remove", Path: featureGatesPath}))
})

It("should recover from a bad featureGate format, if new HC contains FGs", func(ctx context.Context) {
origCR := cr.DeepCopy()
cr.Spec.FeatureGates.Enable("some-fake-fg")

req := admission.Request{AdmissionRequest: newUpdateRequest(origCR, cr, testCodec)}

unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&origCR)
Expect(err).NotTo(HaveOccurred())
unstructuredObj["spec"].(map[string]any)["featureGates"] = map[string]any{}
badOrigHC, err := json.Marshal(unstructuredObj)
Expect(err).NotTo(HaveOccurred())

req.OldObject.Raw = badOrigHC

res := mutator.Handle(ctx, req)
Expect(res.Allowed).To(BeTrue())

Expect(res.Patches).ToNot(ContainElement(jsonpatch.JsonPatchOperation{Operation: "remove", Path: featureGatesPath}))
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline pkg/webhooks/mutator/hyperConvergedMutator_test.go --items all

rg -n -C 6 \
  'OldObject\.Raw|featureGates|failed to parse the old HyperConverged|StatusBadRequest|Allowed\)\.To\(BeFalse' \
  pkg/webhooks/mutator/hyperConvergedMutator_test.go

Repository: kubevirt/hyperconverged-cluster-operator

Length of output: 3320


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- DecodeRaw and rejection paths ---'
rg -n -C 10 'DecodeRaw|featureGates|Allowed: false|StatusBadRequest|failed to parse|bad feature' pkg/webhooks/mutator pkg/webhooks --glob '*.go' || true

printf '%s\n' '--- Test assertions across mutator tests ---'
rg -n -C 5 'Allowed\)\.To\(BeFalse|Allowed.*BeFalse|StatusBadRequest|DecodeRaw|OldObject\.Raw' pkg --glob '*_test.go' || true

printf '%s\n' '--- Mutator file map ---'
fd -i 'mutator' pkg/webhooks

Repository: kubevirt/hyperconverged-cluster-operator

Length of output: 50397


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

roots = [Path("pkg/webhooks/mutator"), Path("pkg/webhooks")]
for path in sorted({p for root in roots if root.exists() for p in root.rglob("*.go")}):
    text = path.read_text()
    if "DecodeRaw" in text or "OldObject.Raw" in text or "Allowed: false" in text:
        print(f"\n--- {path} ---")
        for i, line in enumerate(text.splitlines(), 1):
            if any(token in line for token in ("DecodeRaw", "OldObject.Raw", "Allowed: false", "StatusBadRequest")):
                lo, hi = max(1, i-8), min(len(text.splitlines()), i+12)
                lines = text.splitlines()
                for n in range(lo, hi+1):
                    print(f"{n}: {lines[n-1]}")
                print()
PY

Repository: kubevirt/hyperconverged-cluster-operator

Length of output: 25602


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

for path in sorted(Path("pkg/webhooks").rglob("*.go")):
    lines = path.read_text().splitlines()
    hits = [i for i, line in enumerate(lines, 1)
            if any(token in line for token in
                   ("DecodeRaw", "OldObject.Raw", "Allowed: false", "StatusBadRequest"))]
    if hits:
        print(f"\n--- {path} ---")
        for i in hits:
            for n in range(max(1, i - 8), min(len(lines), i + 12) + 1):
                print(f"{n}: {lines[n-1]}")
            print()
PY

Repository: kubevirt/hyperconverged-cluster-operator

Length of output: 26795


Add a negative test for unrelated decode errors.

Add an update case with a malformed old object that triggers a DecodeRaw error outside spec.featureGates. Assert that the response is rejected with HTTP 400.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/webhooks/mutator/hyperConvergedMutator_test.go` around lines 592 - 630,
Add a negative update test alongside the existing bad feature-gate recovery
cases that corrupts a field outside spec.featureGates in the old object, causing
DecodeRaw to fail. Invoke mutator.Handle and assert the response is rejected
with HTTP 400, ensuring unrelated decode errors are not recovered from.

Source: Path instructions

Comment thread pkg/webhooks/mutator/hyperConvergedMutator.go
@hco-bot

hco-bot commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

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

@kubevirt-prow

kubevirt-prow Bot commented Aug 11, 2026

Copy link
Copy Markdown

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

Details

In response to this:

hco-e2e-upgrade-operator-sdk-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-operator-sdk-aws
hco-e2e-upgrade-prev-operator-sdk-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-prev-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.

For some unknown reasons, sometimes during an upgrade from v1.18, the featureGates
field becomes an empty object instead of an empty array.

Trying to recover from this edge case by removing the featureGates field.

Signed-off-by: Nahshon Unna Tsameret <nunnatsa@redhat.com>
@sonarqubecloud

Copy link
Copy Markdown

@coveralls

coveralls commented Aug 11, 2026 •

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 31486248985

Coverage decreased (-0.09%) to 85.512%

Details

  • Coverage decreased (-0.09%) from the base build.
  • Patch coverage: 22 uncovered changes across 1 file (27 of 49 lines covered, 55.1%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
pkg/webhooks/mutator/hyperConvergedMutator.go 49 27 55.1%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 14005
Covered Lines: 11976
Line Coverage: 85.51%
Coverage Strength: 2.31 hits per line

💛 - Coveralls

@orenc1 orenc1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

/approve

@kubevirt-prow kubevirt-prow Bot added the lgtm Indicates that a PR is ready to be merged. label Aug 11, 2026
@kubevirt-prow

kubevirt-prow Bot commented Aug 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: orenc1

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

The pull request process is described 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 added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 11, 2026
@hco-bot

hco-bot commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

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

@kubevirt-prow

kubevirt-prow Bot commented Aug 11, 2026

Copy link
Copy Markdown

@hco-bot: Overrode contexts on behalf of hco-bot: ci/prow/hco-e2e-operator-sdk-sno-aws

Details

In response to this:

hco-e2e-operator-sdk-sno-azure lane succeeded.
/override ci/prow/hco-e2e-operator-sdk-sno-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.

@openshift-ci

openshift-ci Bot commented Aug 11, 2026

Copy link
Copy Markdown

@nunnatsa: 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-operator-sdk-sno-aws 6ae39d1 link false /test hco-e2e-operator-sdk-sno-aws
ci/prow/hco-e2e-operator-sdk-azure 6ae39d1 link true /test hco-e2e-operator-sdk-azure
ci/prow/hco-e2e-upgrade-operator-sdk-aws 6ae39d1 link true /test hco-e2e-upgrade-operator-sdk-aws
ci/prow/hco-e2e-upgrade-prev-operator-sdk-sno-aws 6ae39d1 link false /test hco-e2e-upgrade-prev-operator-sdk-sno-aws
ci/prow/hco-e2e-upgrade-prev-operator-sdk-aws 6ae39d1 link true /test hco-e2e-upgrade-prev-operator-sdk-aws

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 11, 2026

Copy link
Copy Markdown
Collaborator

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

@kubevirt-prow

kubevirt-prow Bot commented Aug 11, 2026

Copy link
Copy Markdown

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

Details

In response to this:

hco-e2e-upgrade-prev-operator-sdk-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-prev-operator-sdk-aws
hco-e2e-upgrade-prev-operator-sdk-sno-azure lane succeeded.
/override ci/prow/hco-e2e-upgrade-prev-operator-sdk-sno-aws
hco-e2e-operator-sdk-gcp, hco-e2e-operator-sdk-aws lanes succeeded.
/override ci/prow/hco-e2e-operator-sdk-azure
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.

@kubevirt-prow
kubevirt-prow Bot merged commit 38f4b30 into kubevirt:main Aug 11, 2026
32 checks passed
@nunnatsa
nunnatsa deleted the fix-CNV-94727 branch August 11, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has DCO signed all their commits. lgtm Indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants