Skip to content

test, e2e-upgrade: run per-example cleanup even when upgrade gates fail - #1573

Merged
kubevirt-prow[bot] merged 1 commit into
mainfrom
copilot/e2e-upgrade-bond-example-fix
Sep 1, 2026
Merged

test, e2e-upgrade: run per-example cleanup even when upgrade gates fail#1573
kubevirt-prow[bot] merged 1 commit into
mainfrom
copilot/e2e-upgrade-bond-example-fix

Conversation

Copilot AI commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

pull-kubernetes-nmstate-e2e-upgrade-k8s had a test-isolation cascade: when the bond example failed an availability gate, teardown was skipped, leaving bond0 enslaving eth1/eth2. Later examples that configure eth1 then failed with Interface eth1 cannot have IP enabled as it is attached to controller bond0.

Test isolation

Cleanup is registered with DeferCleanup in the It body before policy creation. It runs after the upgrade AfterEach even when that node fails, so a failed apply or post-upgrade gate cannot skip restoration.

cleanupUpgradeCase:

  • determines policy existence with bounded retries;
  • snapshots the exact policy-labeled NNCE set before cleanup;
  • composes one atomic cleanup desired state;
  • captures the cleanup NNCP generation;
  • requires every actual and expected NNCE to reach that generation with Available=True;
  • retains the cleanup NNCP and aborts the suite when restoration cannot be proved;
  • deletes the NNCP only after successful restoration;
  • treats a no-enactment cleanup as safe only when Ignored=True/NoMatchingNode is positively confirmed.

Intentionally skipped examples do not install the new operator or attempt cleanup for a policy that was never created.

v0.87.0 bond compatibility

Exact-head Prow run 2090437894639456256 proved that the v0.87.0 handler/nmstate fails its published bond.yaml with InvalidArgument: Failed to find interface eth1 for copy-mac-from of iface bond0 when eth1 is enslaved in the same transaction.

hack/prepare-e2e-test-upgrade.sh applies a checked compatibility rewrite only when the previous release is exactly v0.87.0: it requires copy-mac-from to be present, then removes only that key from the downloaded upgrade-test copy. Current documentation is unchanged, and later releases retain normal copy-mac-from upgrade coverage.

Availability diagnostics and timeouts

  • waitForPolicyAvailable replaces blind kubectl wait calls. Terminal Failing=True/FailedToConfigure NNCEs stop polling immediately and include the actionable NNCE message; Retrying remains non-terminal.
  • Policy availability and post-upgrade re-reconciliation each have a 5-minute budget.

Failure artifacts

The upgrade suite discovers nmstate handler nodes before initializing KubernetesNMStateReporter. CI teardown uploads ${E2E_LOGS}/handler/* alongside operator output, preserving per-spec NNCE state, NetworkManager logs, journals, and device state for failures that occur before later operator reinstalls.

Test-only change; no product code touched. A failure in one example can no longer contaminate later examples.

This description was generated with AI assistance. Please verify before acting on it.

Assisted-By: github-copilot/gpt-5.6-sol

@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. dco-signoff: no Indicates the PR's author has not 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 19, 2026
@kubevirt-prow

kubevirt-prow Bot commented Aug 19, 2026

Copy link
Copy Markdown

Hi @Copilot. 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.

@kubevirt-prow kubevirt-prow Bot added size/M and removed size/XS labels Aug 19, 2026
Copilot AI changed the title [WIP] Fix flaky bond example and test isolation issue test, e2e-upgrade: run per-example cleanup even when upgrade gates fail Aug 19, 2026
Copilot AI requested a review from mkowalski August 19, 2026 11:12

@mkowalski mkowalski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Disposition: REQUEST_CHANGES

The test-isolation direction is correct, and increasing the slow bond budgets is reasonable, but the current cleanup implementation can still delete the only cleanup request while leaving dirty host state. Two independent reproducers confirmed the blocking failure modes.

Required changes

  1. Register cleanup before applying the example policy

    • kubectl apply can create the NNCP before returning an error.
    • Register DeferCleanup immediately before createUpgradeCasePolicy.
    • The cleanup callback should use bounded polling to determine whether the policy exists. NotFound is a successful no-op; transient API errors should retry for a meaningful duration.
  2. Build and submit one atomic cleanup desired state

    • Merge ExampleSpec.CleanupState and all IfaceNames (state: absent) into one nmstate.State.
    • Submit one NNCP update, not one complete desired-state replacement per interface.
  3. Verify the cleanup generation, not stale NNCP conditions

    • Capture the NNCP generation returned by the cleanup update.
    • List matching NNCEs by nmstate.io/policy=<policy-name>.
    • Require all matching enactments to have status.policyGeneration == cleanup generation and Available=True before deleting the NNCP.
    • A plain kubectl wait nncp ... Available is insufficient because NNCP conditions have no observedGeneration and can still reflect the previous spec.
  4. Do not delete on failed restoration

    • If cleanup update/convergence cannot be verified, leave the NNCP containing the cleanup state so a recovering handler can continue reconciliation.
    • Abort the suite (AbortSuite) to prevent subsequent specs from running on contaminated nodes.
    • Delete the NNCP only after cleanup generation convergence is proven.
  5. Make deletion/API polling resilient

    • A transient GET after DELETE must not terminate the wait immediately; continue polling until NotFound or timeout while retaining the last error for diagnostics.
    • If existence cannot be determined after bounded retries, abort the suite rather than silently proceeding.
  6. Handle intentionally skipped examples

    • Skip occurs before policy creation. Do not reinstall operators or wait for a non-existent policy in teardown for these specs.
  7. Repository requirements

    • Remove/fold the unsigned Initial plan commit: current DCO failure reports commit 69c261f missing Signed-off-by.
    • Mark ready for review when complete (do-not-merge/work-in-progress is currently present).
    • This is test-only; use /release-note-none (or add the repository-expected release-note treatment) to clear do-not-merge/release-note-label-needed.

Verification gates

  • go test ./test/e2e/upgrade -run '^$'
  • go vet ./test/e2e/upgrade
  • repo golangci-lint for ./test/e2e/upgrade/...
  • /test pull-kubernetes-nmstate-e2e-upgrade-k8s on the exact final commit
  • Confirm the run finishes under the Prow E2E_TEST_TIMEOUT=1h, reports the four intentional skips, and has no downstream eth1 ... attached to controller bond0 cascade.

Review evidence

  • Cleanup-delete reproducer: cleanup failure followed by deferred deletion left bond0 present and visible to the next spec.
  • Existence-check reproducer: a transient API GET failed before cleanup registration; policy and host state both remained.
  • Source confirms NNCP deletion only removes its enactment and does not revert node network state.

Generated by /code-review:deep-review. This review was generated using AI. Please verify before acting on it.

Comment thread test/e2e/upgrade/upgrade_test.go Outdated

// Deleting the policy is deferred so it also happens if the cleanup
// configuration below does not converge in time.
DeferCleanup(func() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BLOCKING (runtime-reproduced): do not defer unconditional NNCP deletion. If createUpgradeCaseCleanupPolicy fails, this callback still deletes the NNCP. Deleting an NNCP does not revert host networking; the controller only removes the enactment, so bond0 can remain while the only cleanup reconciliation request disappears. A focused Ginkgo reproducer observed cleanup-fails policy=true bond0=true then deferred-delete policy=false bond0=true, and the next spec still saw bond0=true. Delete only after restoration for the cleanup generation is proven. If restoration fails, keep the cleanup NNCP and abort the suite so contaminated state cannot reach another example.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 54dd577. Deletion is no longer deferred unconditionally: cleanupUpgradeCase deletes the NNCP only after waitForPolicyGenerationApplied proves every matching enactment applied the cleanup generation with Available=True. On any failure (compose, update, convergence or delete) the NNCP is left holding the cleanup desired state so a recovering handler keeps reconciling it, and AbortSuite stops the remaining specs so contaminated nodes can't reach another example. deletePolicy also retries the DELETE and keeps polling for NotFound instead of failing on a transient GET.

Comment thread test/e2e/upgrade/upgrade_test.go Outdated
}

kubectlAndCheck("wait", "nncp", example.PolicyName, "--for", "condition=Available", "--timeout", "3m")
kubectlAndCheck("wait", "nncp", example.PolicyName, "--for", "condition=Available", "--timeout", PolicyAvailableTimeout)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BLOCKING: this wait can accept stale success, and the interface loop can lose cleanup operations. Updating spec.desiredState preserves the old NNCP Available=True; NNCP conditions have no observedGeneration, so kubectl wait may return before cleanup is applied. Also, each IfaceNames iteration replaces the entire desired state; workqueue coalescing can reconcile only the last generation (e.g. remove ovs0 but leave br1). Build one cleanup desired state containing all absent interfaces, update once, capture the resulting NNCP generation, then wait until every matching NNCE reports status.policyGeneration == generation and Available=True before deleting the policy.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 54dd577. cleanupDesiredState now merges ExampleSpec.CleanupState with every IfaceNames entry (state: absent) into a single nmstate state, submitted as one updatePolicyDesiredState call, so workqueue coalescing can no longer drop an interface (verified the composed state for all examples, e.g. ovs-bridge-iface yields br1 + ovs0 absent in one state, and dns keeps its dns-resolver block).

The kubectl wait nncp ... Available gate is gone from the cleanup path. waitForPolicyGenerationApplied captures the generation returned by the update, lists NNCEs by nmstate.io/policy=<policy> and requires every one of them to report status.policyGeneration == <generation> and Available=True. If no enactment matches the policy (no matching node) it falls back to the NNCP Available condition. The NNCP is deleted only after that.

Comment thread test/e2e/upgrade/main_test.go Outdated
knmstateReporter.ReportAfterEach(specReport)
})

func policyExists(name string) bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BLOCKING (runtime-reproduced): a one-shot/transient Get can bypass all cleanup. policyExists fails before DeferCleanup is registered, so a short API timeout leaves both the policy and dirty host state. Register cleanup before kubectl apply (apply may create the NNCP before returning an error), then determine existence with meaningful bounded polling (seconds, not retry.DefaultRetry's ~40ms). Treat NotFound as a successful no-op and retry transient read failures.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in f4b1f5b/54dd577. DeferCleanup(cleanupUpgradeCase) is now registered immediately before createUpgradeCasePolicy, so an apply that creates the NNCP and then fails is still cleaned up. Existence is determined by policyExists, which polls up to APIRetryTimeout (30s at ReadInterval), treats NotFound as a successful no-op and retries transient reads; if existence still can't be determined the suite is aborted instead of silently skipping cleanup.

Ordering is preserved: I verified with a scratch Ginkgo suite that a DeferCleanup registered in the It runs after all AfterEach nodes at that level and still runs when one of them fails.

@mkowalski

Copy link
Copy Markdown
Member

@copilot Please address all blocking findings in review #1573 (review), update this PR branch, and run the listed local verification gates. In particular, make cleanup atomic and generation-aware, retain the cleanup NNCP + abort the suite when restoration cannot be proven, fix transient API polling, fold/remove the unsigned plan commit, apply /release-note-none, and mark the PR ready when complete.

This message was generated using AI. Please verify before acting on it.

Copilot AI commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Disposition: REQUEST_CHANGES

The test-isolation direction is correct, and increasing the slow bond budgets is reasonable, but the current cleanup implementation can still delete the only cleanup r...

Addressed in 54dd577 + 1f2f2f0 (see the per-thread replies for details).

  1. Cleanup is registered with DeferCleanup immediately before createUpgradeCasePolicy; existence is resolved with bounded polling (APIRetryTimeout, 30s), NotFound is a no-op, transient errors retry.
  2. cleanupDesiredState merges CleanupState + all IfaceNames (state: absent) into one state submitted with a single NNCP update.
  3. waitForPolicyGenerationApplied verifies the cleanup generation on the NNCEs listed by nmstate.io/policy, requiring status.policyGeneration == <cleanup generation> and Available=True; the generation-less kubectl wait nncp is gone from the cleanup path.
  4. The NNCP is deleted only after convergence is proven; otherwise it keeps the cleanup state and the suite is aborted with AbortSuite.
  5. Delete and the wait for disappearance retry transient API errors and report the last error.
  6. Skip happens before the cleanup is registered, and a policyApplied guard now also skips the upgrade AfterEach for skipped examples (and for examples whose policy never converged), so no operator reinstall or wait on a non-existent policy happens there.

On the repo requirements: Initial plan (69c261f) is the platform-generated root commit of this branch (it contains the whole tree from the shallow clone), so I can't re-sign it without rewriting the branch history, which I can't force-push from here — it needs a maintainer action or a squash merge. The label/release-note commands (/release-note-none, marking ready for review) also aren't available to me; could you apply those? Once the branch is green I'd appreciate a /test pull-kubernetes-nmstate-e2e-upgrade-k8s run on the final commit, since the acceptance criteria can only be verified on the 2-node kubevirtci cluster.

Verified locally: go test ./test/e2e/upgrade -run '^$', go vet ./test/e2e/upgrade, and golangci-lint 2.11.3 with the repo config on ./test/e2e/upgrade/... (0 issues). I also confirmed with a scratch Ginkgo suite that a DeferCleanup registered in the It runs after all AfterEach nodes even when one fails, that a skipped spec never registers it, and that AbortSuite from within it skips the remaining specs.

Copilot AI commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Please address all blocking findings in review #1573 (review), update this PR branch, and run the listed local verificati...

All blocking findings are implemented on the branch (latest commit also removes the last stale-condition path):

  1. DeferCleanup(cleanupUpgradeCase) is registered immediately before createUpgradeCasePolicy; existence is resolved by policyExists with bounded polling (APIRetryTimeout 30s at ReadInterval), NotFound is a no-op, transient errors retried, and an unresolvable read aborts the suite.
  2. cleanupDesiredState merges CleanupState with every IfaceNames entry (state: absent) into one nmstate.State submitted with a single updatePolicyDesiredState call.
  3. waitForPolicyGenerationApplied captures the generation returned by that update, lists NNCEs by nmstate.io/policy=<policy> and requires each to report status.policyGeneration == <cleanup generation> and Available=True. The generation-less kubectl wait nncp ... Available is gone from the cleanup path; the no-enactment fallback now additionally requires a policy heartbeat newer than the update instant (captured at the update itself), so it can't accept a stale condition either.
  4. The NNCP is deleted only after that convergence is proven; on any failure it keeps the cleanup desired state and AbortSuite stops the remaining specs.
  5. deletePolicy retries the DELETE and keeps polling for NotFound on transient GET errors, returning the last error.
  6. Skip happens before cleanup registration, and the policyApplied guard also short-circuits the upgrade AfterEach, so skipped examples neither reinstall operators nor wait on a non-existent policy.

Verification gates run locally on the final commit: go test ./test/e2e/upgrade -run '^$', go vet ./test/e2e/upgrade, golangci-lint 2.11.3 with the repo config on ./test/e2e/upgrade/... (0 issues). DCO is green on the branch.

Two items need maintainer action: I can't run /release-note-none, mark the PR ready for review, or trigger /test pull-kubernetes-nmstate-e2e-upgrade-k8s — the acceptance criteria (four intentional skips, no eth1 ... attached to controller bond0 cascade, under E2E_TEST_TIMEOUT=1h) can only be confirmed on the kubevirtci cluster.

@mkowalski

Copy link
Copy Markdown
Member

/release-note-none

@kubevirt-prow kubevirt-prow Bot added release-note-none Denotes a PR that doesn't merit a release note. and removed 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 19, 2026

@mkowalski mkowalski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Second-pass disposition: REQUEST_CHANGES

Copilot addressed the original deep-review blockers in substance:

  • cleanup is registered before apply;
  • transient API reads/deletes have meaningful bounded retry;
  • cleanup desired state is atomic across all interfaces;
  • deletion occurs only after attempted verification;
  • failed cleanup retains the NNCP and aborts the suite;
  • skipped/unapplied examples do not run the upgrade teardown.

Local compilation, vet, and golangci-lint also pass on 502baeb3c.

Two blocking generation-verification gaps remain:

  1. Capture the expected NNCE set before the cleanup update.

    • List enactments by nmstate.io/policy=<name> before updating the NNCP.
    • Store the exact expected enactment names.
    • If the expected set is empty, no enactment applied the example state; cleanup can be a no-op/delete. Do not infer “no matching nodes” from a transient empty post-update list.
  2. Require the exact cleanup generation on the complete enactment set.

    • After the single cleanup update, wait until every expected NNCE is present, has status.policyGeneration == cleanupGeneration, and Available=True.
    • Do not succeed when only a subset is returned.
    • Also reject any actual policy-labeled enactment that is stale/unavailable so newly appearing enactments cannot be ignored.
    • Remove the NNCP heartbeat/wall-clock fallback (updatedAt, policyIsAvailableSince); generation-aware NNCE status is the server-observable token.

Repository/CI blockers also remain:

  • Lowercase required dco still fails because unsigned commit 69c261f remains. The uppercase GitHub DCO check passing does not satisfy Prow. This needs a maintainer history rewrite/drop or recreation/squash path.
  • PR remains draft with do-not-merge/work-in-progress and do-not-merge/release-note-label-needed.
  • No Prow presubmits have run on final head. After the code update, a collaborator must apply /release-note-none, mark ready, and run /test all plus /test pull-kubernetes-nmstate-e2e-upgrade-k8s.

Runtime acceptance remains: exact final head must finish the upgrade suite under E2E_TEST_TIMEOUT=1h, retain the four intentional skips, and show no downstream eth1 ... attached to controller bond0 cascade.

This review was generated using AI. Please verify before acting on it.

Comment thread test/e2e/upgrade/main_test.go Outdated
if err != nil {
return err
}
if len(enactments.Items) == 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BLOCKING: zero NNCEs is not equivalent to “no matching node,” and the fallback is unsafe. An empty list can be transient (handler restart/list race) or mean matching nodes have not created NNCEs yet. A genuinely unmatched policy reports Ignored/NoMatchingNode, not Available=True, while a policy can also be Available with NotReady nodes ignored. The wall-clock heartbeat fallback (updatedAt) is also race-prone: an old-generation heartbeat can occur after the client timestamp but before the successful Update. Remove this fallback. Snapshot the policy-labeled NNCE names before the cleanup update; if the snapshot is empty, no node has an enactment that could have applied the original state, so cleanup can be treated as a no-op/delete. Otherwise require those expected NNCEs to remain present and reach the cleanup generation + Available=True.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3aaeaff/3b2b397. The heartbeat fallback is gone: policyIsAvailableSince is removed and waitForPolicyGenerationApplied no longer takes a wall-clock token. cleanupUpgradeCase now snapshots the policy-labeled NNCE names with policyEnactmentNames (bounded retry on transient list errors) before the cleanup update. An empty snapshot means no enactment could have applied the example state, so the update/wait is skipped and cleanup is just the delete. A non-empty snapshot is what convergence is verified against, so a transient empty list afterwards is a failure, not a success — and waitForPolicyGenerationApplied itself errors out if it is ever asked to verify with nothing expected and nothing listed.

// observedGeneration and can report the previous desired state.
return policyIsAvailableSince(name, updatedAt)
}
for i := range enactments.Items {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BLOCKING: a partial enactment list passes. The loop validates only objects currently returned. With two matching nodes, one cleanup-generation Available NNCE plus one missing NNCE returns success, after which the policy is deleted while the missing node may retain the example configuration. Capture the expected enactment names before updating. During convergence require every expected name; also validate every actual enactment is at the cleanup generation and Available (a newly appearing enactment must not be ignored). If an expected NNCE disappears or an unexpected one remains stale, retain the cleanup NNCP and abort rather than delete.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3aaeaff. The expected enactment names are captured before the update and passed into waitForPolicyGenerationApplied. Each poll now requires every actual policy-labeled enactment to be at the cleanup generation with Available=True (so a newly appearing enactment can't be ignored) and then requires every expected name to be among those converged, so a partial list — one converged NNCE plus one missing — keeps failing instead of passing. If that doesn't converge within PolicyAvailableTimeout the NNCP is retained with the cleanup desired state and the suite is aborted; the delete only happens after convergence.

Comment thread test/e2e/upgrade/main_test.go Outdated
// update was issued at.
func updatePolicyDesiredState(name string, desiredState shared.State) (int64, time.Time, error) {
generation := int64(0)
updatedAt := time.Now()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The updatedAt wall-clock token is no longer needed once cleanup verification is based on an expected NNCE set and status.policyGeneration. Capturing it before GET/Update retries permits an old-generation heartbeat during retries to look “fresh,” and handler/client clocks and timestamp precision need not align. Return only the successful update generation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed in 3aaeaff. updatePolicyDesiredState returns (int64, error) again — only the generation of the successful update — and policyIsAvailableSince is deleted. Verification is now purely status.policyGeneration + Available=True over the expected NNCE set.

@mkowalski

Copy link
Copy Markdown
Member

@copilot Please address the two remaining blocking generation-verification findings in #1573 (review). Snapshot the exact policy-labeled NNCE names before the cleanup update, require the complete expected set at the cleanup generation and Available, reject stale/unexpected enactments, and remove the wall-clock/NNCP-status fallback. Run the local gates and update the branch. Please also report anything that still requires maintainer action separately (DCO history rewrite, release-note label, ready state, Prow trigger).

This message was generated using AI. Please verify before acting on it.

Copilot AI commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot The upgrade job has now run to completion and proves your original copy-mac-from diagnosis was correct. See #1573 (review)...

All three items are addressed in the latest commits:

  1. copy-mac-from strip restored — already done in the commit before a6da9aeed was pushed; the current head restores the scoped override in hack/prepare-e2e-test-upgrade.sh. It applies only when previous_minor_version == v0.87.0, asserts copy-mac-from: is present before rewriting (fails loudly if not), and strips only that field via sed -i '/^\s*copy-mac-from:/d'. Future previous releases retain normal coverage.

  2. nodes populated in BeforeSuite — done in the latest commit. The upgrade BeforeSuite now lists handler pods by component: kubernetes-nmstate-handler and appends their Spec.NodeName to nodes before creating the reporter, matching the handler suite pattern exactly. deviceStatus.log and NetworkManager.log will be populated on the next run.

  3. PolicyAvailableTimeout description — the constant comment says "time given to a policy to become Available"; it does not describe it as the bond fix. The bond fix is the copy-mac-from strip; the 5 m budget is kept for other examples that legitimately need it.

@copilot The exact-head Prow run now directly confirms the v0.87.0 copy-mac-from failure. Please implement the scoped, checked v0.87.0 upgrade-fixture override and populate the reporter's node list ...

Both items addressed:

  1. Scoped, checked v0.87.0 fixture override — already present in hack/prepare-e2e-test-upgrade.sh on the current head: the strip runs only when previous_minor_version == v0.87.0, asserts copy-mac-from: exists in the downloaded bond.yaml before rewriting (exits with a clear error if not), and removes only that field. Future previous releases are untouched.

  2. nodes populated for the reporter — done in the latest commit. Handler pod Spec.NodeNames are now collected in BeforeSuite before knmstatereporter.New(...) is called, so deviceStatus.log, NetworkManager.log, and per-spec NNCE output will be non-empty on the next run.

@mkowalski

Copy link
Copy Markdown
Member

/test pull-kubernetes-nmstate-e2e-upgrade-k8s

Final runtime validation requested on settled head f3d2dccb4f27bc5d6bf60eadd02b457b2bc469bd after the scoped v0.87.0 fixture override and reporter node discovery fixes.

Comment posted with AI assistance. Please verify before acting on it.

Assisted-By: github-copilot/gpt-5.6-sol

@mkowalski

Copy link
Copy Markdown
Member

Current readiness on f3d2dccb4

The latest Copilot changes are correct on review:

  • the v0.87.0 bond compatibility rewrite is scoped to that exact release, checked before mutation, and leaves future release coverage unchanged;
  • the generated v0.87.0 fixture contains the DHCP/balance-rr bond and ports but no copy-mac-from;
  • handler pod node names are collected before reporter initialization, so node-level diagnostics can run;
  • go test ./test/e2e/upgrade -run '^$', go vet, gofmt -l, both shell syntax checks, and real v0.87.0 fixture preparation pass locally.

I see no remaining code-review blocker, but I am withholding LGTM until exact-head runtime validation completes. Final Prow job: https://prow.ci.kubevirt.io/view/gs/kubevirt-prow/pr-logs/pull/nmstate_kubernetes-nmstate/1573/pull-kubernetes-nmstate-e2e-upgrade-k8s/2091818135320530944

Acceptance remains 12 passed / 4 intentional skips. DCO on unsigned root commit 69c261f remains a separate maintainer merge blocker.

This message was generated using AI. Please verify before acting on it.

Assisted-By: github-copilot/gpt-5.6-sol

@mkowalski

Copy link
Copy Markdown
Member

/test pull-kubernetes-nmstate-e2e-handler-k8s

@qinqon

qinqon commented Aug 31, 2026

Copy link
Copy Markdown
Member

/ok-to-test
/test all

@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/retest

@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/test pull-kubernetes-nmstate-e2e-upgrade-k8s

@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/lgtm
/approve
/hold

I will squash what need to be squash and add @mkowalski as DCO.

@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
@kubevirt-prow kubevirt-prow Bot added the lgtm Indicates that a PR is ready to be merged. label Sep 1, 2026
@kubevirt-prow

kubevirt-prow Bot commented Sep 1, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: qinqon

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 Sep 1, 2026
@qinqon
qinqon force-pushed the copilot/e2e-upgrade-bond-example-fix branch from f3d2dcc to 2e096be Compare September 1, 2026 07:17
@kubevirt-prow kubevirt-prow Bot added dco-signoff: yes Indicates the PR's author has DCO signed all their commits. and removed lgtm Indicates that a PR is ready to be merged. dco-signoff: no Indicates the PR's author has not DCO signed all their commits. labels Sep 1, 2026
Always clean up each upgrade example, even when applying the policy or upgrading the operator fails. Apply cleanup atomically and verify the expected enactments observed the new policy generation before deleting the policy.

Fail policy waits immediately on terminal enactment errors, retain reporter diagnostics in CI artifacts, and initialize the reporter with handler nodes. Work around the incompatible copy-mac-from field only in the published v0.87.0 bond fixture.

Signed-off-by: Mat Kowalski <mko@redhat.com>
Assisted-By: GPT-5.6-Sol <noreply@github.com>
@qinqon
qinqon force-pushed the copilot/e2e-upgrade-bond-example-fix branch from 2e096be to 434c0de Compare September 1, 2026 07:19
@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/ok-to-test
/test all

@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/retest

unrelated

63.6M    6 4080k    0     0   6300      0  2:56:38  0:11:03  2:45:35     0
  6 63.6M    6 4080k    0     0   6291      0  2:56:53  0:11:04  2:45:49     0
  6 63.6M    6 4080k    0     0   6282      0  2:57:08  0:11:05  2:46:03     0
  6 63.6M    6 4080k    0     0   6272      0  2:57:25  0:11:06  2:46:19     0
  6 63.6M    6 4080k    0     0   6263      0  2:57:40  0:11:07  2:46:33     0
  6 63.6M    6 4080k    0     0   6256      0  2:57:52  0:11:07  2:46:45     0
  6 63.6M    6 4080k    0     0   6256      0  2:57:52  0:11:07  2:46:45     0
curl: (18) transfer closed with 62590620 bytes remaining to read

gzip: stdin: unexpected end of file
tar: Unexpected EOF in archive
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
Error: building at STEP "RUN ./build/install-go.sh ${GO_VERSION}": while running runtime: exit status 2
make: *** [Makefile:220: push-handler] Error 2
+ EXIT_VALUE=2

@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/hold cancel
/lgtm

@kubevirt-prow kubevirt-prow Bot added lgtm Indicates that a PR is ready to be merged. and removed do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Sep 1, 2026
@qinqon

qinqon commented Sep 1, 2026

Copy link
Copy Markdown
Member

/retest

@kubevirt-prow
kubevirt-prow Bot merged commit 13429c8 into main Sep 1, 2026
12 checks passed
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.

e2e-upgrade: flaky "bond" example + skipped per-example cleanup cascade fails unrelated upgrade specs

4 participants