Skip to content

test(vmi): modernize the VMInstance/VMDisk backup/restore e2e to the BackupClass flow - #3427

Open
Andrey Kolkov (androndo) wants to merge 4 commits into
mainfrom
test/vm-backup-restore-e2e
Open

test(vmi): modernize the VMInstance/VMDisk backup/restore e2e to the BackupClass flow#3427
Andrey Kolkov (androndo) wants to merge 4 commits into
mainfrom
test/vm-backup-restore-e2e

Conversation

@androndo

@androndo Andrey Kolkov (androndo) commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Closes the uncovered VM backup path called out in #3236. hack/e2e-chainsaw/backup/ held only a disabled Chainsaw port of the old backup.bats, still written against the retired API (kind: VirtualMachine, BackupJob.storageRef/strategyRef, velero-strategy-default) — it no longer matches the CRDs on main, so it guarded nothing. This removes it and replaces it with a real round-trip.

The new coverage mirrors the etcd/postgres/mariadb precedent: a second Test doc in the vminstance suite, vminstance-2-backup-roundtrip, that drives the validated example scripts (examples/backups/vmi/run-all.sh) so the documented demo and the automated test can never drift. The flow exercises the current API end to end — Velero strategies → BackupClass → a booted Ubuntu VMInstance → ad-hoc BackupJob (backupClassName, waits Succeeded) → in-place RestoreJob (waits Succeeded, then waits for the restored VM to boot again) → cross-namespace to-copy RestoreJob. A VM has no in-guest sentinel the host can read, so the round-trip proof is that the VM boots from the restored disk.

It runs in tenant-root (Velero's CSI data mover reaches tenant-root's seaweedfs over same-tenant egress, which a tenant-test Pod cannot — same reasoning as the postgres suite), with skipDelete plus an explicit finally that prunes the cluster-scoped BackupClass and strategies and the cozy-velero Velero Backup/Restore. Like etcd-2-backup-roundtrip it is gated out of CI (VMI_E2E_S3_ROUNDTRIP=1): the in-cluster S3 endpoint serves a self-signed cert kind cannot trust and the platform BackupStorageLocation TLS/checksum defaults do not complete the flow in the sandbox (#3236). Opt in on a real backups-enabled cluster.

It also adds the other cozy-default Velero path — standalone VMDisk (cozy-default-velero-vmdisk), previously covered only for creation — and this one runs un-gated, as a real backup/restore in CI. vmdisk-2-backup-roundtrip drives a self-contained examples/backups/vmdisk flow (Velero strategy → BackupClass → an imported 5Gi VMDisk → ad-hoc BackupJob → in-place RestoreJob). A standalone disk captures only the HelmRelease + PVC (no VirtualMachine/VMI/launcher pod), so it is a distinct, lighter path than the VMInstance round-trip: no nested VM boot, no guest-agent freeze, no 20Gi image — fast and reliable enough for the kind sandbox. It exercises the full Velero machinery for real: a CSI VolumeSnapshot of the LINSTOR replicated block disk → data mover (kopia) upload to S3 → RestoreJob → the disk restored back to a Bound, Ready PVC (in-guest data is exercised by the gated VMInstance round-trip, which boots the VM).

To make that reachable in CI, the harness stands up a throwaway BSL cozy-e2e-vmdisk pointing at the in-cluster seaweedfs-s3.tenant-root:8333 with insecureSkipTLSVerify + checksumAlgorithm: "" — the #3236 fixes applied at the BSL — reusing the platform bucket + cozy-backups-creds under a distinct prefix. This is necessary because the platform cozy-default BSL derives the external S3 ingress endpoint, which is an unroutable placeholder inside kind (the same reason the postgres round-trip targets the in-cluster endpoint). The example scripts stay generic and just consume BACKUP_STORAGE_LOCATION. Runs in tenant-root, skipDelete, with a finally that tears down the throwaway BSL alongside the example cleanup.

Made the vmi example CI-drivable and more correct while here:

  • run-all.sh / cleanup.sh are now non-interactive, matching every sibling example, so the harness can drive them; cleanup uses --ignore-not-found (idempotent, but does not mask a stuck delete).
  • 04-create-vminstance.sh now waits for the VM to boot before backup, as the etcd/postgres source steps do — backing up a half-imported disk is useless.
  • 06-restore-in-place.sh waits for the restored VM to boot again.
  • BackupJob/RestoreJob waits fail fast on a terminal Failed phase and get a 1800s budget (a 20Gi VM disk to S3 is far heavier than a DB dump).
  • Drop volumeSnapshotLocations from the demo strategies: snapshotMoveData routes volume data through the BSL, so a same-named VSL is not required and referencing a missing one fails the backup — the platform's own cozy-default-velero-vminstance strategy omits it too.
  • Default BACKUP_STORAGE_LOCATION to cozy-default, the platform BSL, so the demo works out of the box on a backups-enabled cluster.

Verified in CI: vmdisk-2-backup-roundtrip ran the real flow green (BSL cozy-e2e-vmdisk validated Available, BackupJobSucceeded, RestoreJobSucceeded, restored disk Bound + Ready, ~244s), while vminstance-2-backup-roundtrip stayed correctly gated (fast no-op). The VMInstance round-trip is kept gated because a nested-VM boot + guest freeze + 20Gi CSI snapshot + two restores is too heavy/flaky for the kind sandbox; run it on a real backups-enabled cluster with VMI_E2E_S3_ROUNDTRIP=1.

Screenshots

N/A — no UI changes.

Downstream repositories

Walked the trigger map in docs/agents/contributing.md against the diff (shell scripts under examples/backups/vmi/, one Chainsaw test, a deleted stale suite dir): no packages/apps|extra add/rename, no values.schema.json/enum/default changes, no CRD/ApplicationDefinition/label/annotation/namespace/metric changes. cozystack/examples holds Terraform for bare nodes and is unrelated to the in-repo examples/ tree. Nothing is reached.

Release note

test(vmi): add Chainsaw backup/restore round-trips for VMInstance and standalone VMDisk (driving examples/backups/vmi and examples/backups/vmdisk); the VMDisk round-trip runs a real Velero backup/restore in CI, the heavier VMInstance one is gated behind VMI_E2E_S3_ROUNDTRIP=1

Summary by CodeRabbit

  • New Features

    • Added a complete standalone VMDisk backup and restore demonstration, including setup, backup, in-place restore, cleanup, and an all-in-one runner.
    • Added automated end-to-end backup and restore coverage for VM instances and VMDisk resources.
    • Added configurable VM image URLs and disk sizes for VM instance demonstrations.
  • Bug Fixes

    • Improved readiness checks and failure detection during backup and restore operations.
    • Increased operation timeouts for more reliable long-running workflows.
  • Chores

    • Made demo runners and cleanup scripts non-interactive and repeatable.
    • Removed the obsolete backup test configuration and documentation.

…lass flow

The VM backup path was uncovered: hack/e2e-chainsaw/backup/ held only a
disabled Chainsaw port of the old backup.bats, still written against the
retired API (kind: VirtualMachine, BackupJob.storageRef/strategyRef,
velero-strategy-default) — it no longer matches the CRDs on main, so it
guarded nothing (#3236).

Replace it with a real round-trip that mirrors the etcd/postgres/mariadb
precedent: a second Test doc in the vminstance suite,
vminstance-2-backup-roundtrip, that drives the validated example scripts
(examples/backups/vmi/run-all.sh) so the documented demo and the automated
test can never drift. The flow exercises the current API end to end —
Velero strategies -> BackupClass -> a booted Ubuntu VMInstance -> ad-hoc
BackupJob (backupClassName, waits Succeeded) -> in-place RestoreJob (waits
Succeeded, then waits for the restored VM to boot again) -> cross-namespace
to-copy RestoreJob. A VM has no in-guest sentinel the host can read, so the
proof is that the VM boots from the restored disk.

It runs in tenant-root (Velero's CSI data mover reaches tenant-root's
seaweedfs over same-tenant egress, which a tenant-test Pod cannot), with
skipDelete + an explicit finally that prunes the cluster-scoped BackupClass
and strategies and the cozy-velero Velero Backup/Restore. Like
etcd-2-backup-roundtrip it is gated out of CI (VMI_E2E_S3_ROUNDTRIP=1): the
in-cluster S3 endpoint serves a self-signed cert kind cannot trust and the
platform BSL TLS/checksum defaults do not complete the flow in the sandbox
(#3236); opt in on a real backups-enabled cluster.

Make the vmi example CI-drivable and more correct while here:
- run-all.sh / cleanup.sh are now non-interactive, matching every sibling
  example, so the harness can drive them; cleanup uses --ignore-not-found
  (idempotent, but does not mask a stuck delete).
- 04-create-vminstance.sh now waits for the VM to boot before backup, as
  the etcd/postgres source steps do — backing up a half-imported disk is
  useless.
- 06-restore-in-place.sh waits for the restored VM to boot again.
- BackupJob/RestoreJob waits fail fast on a terminal Failed phase and get a
  1800s budget (a 20Gi VM disk to S3 is far heavier than a DB dump).
- Drop volumeSnapshotLocations from the demo strategies: snapshotMoveData
  routes volume data through the BSL, so a same-named VSL is not required
  and referencing a missing one fails the backup — the platform's own
  cozy-default-velero-vminstance strategy omits it too.
- Default BACKUP_STORAGE_LOCATION to cozy-default, the platform BSL, so the
  demo works out of the box on a backups-enabled cluster.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds scripted VMDisk backup/restore automation, strengthens VMInstance readiness and failure handling, makes demo runners and cleanup non-interactive, and adds Chainsaw round-trip tests with Velero log collection and teardown.

Changes

Backup round-trip automation

Layer / File(s) Summary
Shared backup configuration and polling
examples/backups/vmdisk/00-helpers.sh, examples/backups/vmi/00-helpers.sh, examples/backups/vmi/01-create-strategies.sh
Adds VMDisk defaults and logging, supports terminal polling failures, changes the backup storage default, and removes unnecessary volume snapshot locations.
VMDisk backup and restore flow
examples/backups/vmdisk/*
Adds scripts to provision the strategy, BackupClass, VMDisk, BackupJob, and RestoreJob, verify readiness, run the workflow, and clean up resources.
VMInstance readiness and harness behavior
examples/backups/vmi/03-create-vmdisk.sh, examples/backups/vmi/04-create-vminstance.sh, examples/backups/vmi/05-create-backupjob.sh, examples/backups/vmi/06-restore-in-place.sh, examples/backups/vmi/07-restore-to-copy.sh, examples/backups/vmi/cleanup.sh, examples/backups/vmi/run-all.sh
Adds configurable VM inputs, VM boot and restore readiness checks, longer job waits with failure detection, and non-interactive execution and cleanup.
Chainsaw round-trip test integration
hack/e2e-chainsaw/vminstance/chainsaw-test.yaml
Adds VMInstance and VMDisk round-trip tests that provision temporary storage locations, run the harnesses, collect Velero logs, and clean up resources.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Chainsaw
  participant RunAll
  participant Kubernetes
  participant Velero
  Chainsaw->>RunAll: Run VMInstance or VMDisk round-trip
  RunAll->>Kubernetes: Create source and backup/restore resources
  Kubernetes->>Velero: Process backup and restore operations
  Velero-->>Kubernetes: Update job and backup statuses
  RunAll->>Kubernetes: Verify readiness and delete test resources
  Chainsaw-->>Chainsaw: Collect Velero logs and run finally cleanup
Loading

Suggested labels: kind/feature

Suggested reviewers: lexfrei, kvaps, lllamnyp

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: modernizing the VMInstance/VMDisk backup-restore e2e around the BackupClass flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/vm-backup-restore-e2e

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
hack/e2e-chainsaw/vminstance/chainsaw-test.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

@github-actions github-actions Bot added area/virtualization Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import) size/XL This PR changes 500-999 lines, ignoring generated files labels Jul 22, 2026
cozy-default binds VMDisk to a Velero strategy (cozy-default-velero-vmdisk)
just as it does VMInstance, but that path was never exercised: the
vminstance suite only tested standalone VMDisk creation, and the VMInstance
round-trip backs up a disk attached to a running VM, not a standalone one.
A standalone VMDisk is a distinct path — the strategy captures only the
HelmRelease + PVC (+ configmaps), with no VirtualMachine / VMI / launcher
pod.

Add a self-contained example (examples/backups/vmdisk, mirroring the
etcd/postgres harness style) driven by a new gated Chainsaw Test,
vmdisk-2-backup-roundtrip, in the vminstance suite: Velero strategy ->
BackupClass -> an imported 5Gi VMDisk -> ad-hoc BackupJob (waits Succeeded)
-> in-place RestoreJob (waits Succeeded, then waits for the restored disk to
be Bound + Ready). A standalone disk is not mounted anywhere, so the
round-trip proof is that the restored VMDisk reconciles back to a Ready
HelmRelease + Bound PVC; in-guest data is exercised by
vminstance-2-backup-roundtrip, which boots the VM from its restored disk.

Runs in tenant-root and reuses the VMI_E2E_S3_ROUNDTRIP=1 gate (same
self-signed-S3 / BSL-defaults blocker as the VMInstance round-trip,
#3236), with skipDelete + an explicit finally that prunes
the cluster-scoped BackupClass and strategy, the cozy-velero Velero
Backup/Restore, the VMDisk and any renamed original PVC.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
@github-actions github-actions Bot added size/XXL This PR changes 1000+ lines, ignoring generated files and removed size/XL This PR changes 500-999 lines, ignoring generated files labels Jul 22, 2026
@androndo Andrey Kolkov (androndo) changed the title test(vmi): modernize the VMInstance backup/restore e2e to the BackupClass flow test(vmi): modernize the VMInstance/VMDisk backup/restore e2e to the BackupClass flow Jul 22, 2026
@androndo
Andrey Kolkov (androndo) marked this pull request as ready for review July 23, 2026 11:09
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@dosubot dosubot Bot added the area/testing Issues or PRs related to testing (e2e, bats, unit tests) label Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@examples/backups/vmdisk/03-create-vmdisk.sh`:
- Around line 33-37: Add the documented event-driven backstop immediately before
the HelmRelease readiness wait in examples/backups/vmdisk/03-create-vmdisk.sh
lines 33-37, using the existing wait flow around kubectl and wait_for_field.
Apply the same backstop immediately before the restored VMDisk HelmRelease
readiness wait in examples/backups/vmdisk/05-restore-in-place.sh lines 41-43;
both sites must fail fast on HelmRelease readiness failures.
- Around line 35-36: Update the wait_for_field invocation for vm-disk-backup-src
to provide the DataVolume’s terminal failure phase as its fail value, so imports
stop immediately on failure while retaining Succeeded as the success value and
the existing namespace and timeout.

In `@examples/backups/vmi/04-create-vminstance.sh`:
- Around line 42-47: Add the documented event-driven readiness backstop before
each raw kubectl wait in examples/backups/vmi/04-create-vminstance.sh (lines
42-47) and before the restored-VM wait in
examples/backups/vmi/06-restore-in-place.sh (lines 51-54). In the HelmRelease
wait path of 04-create-vminstance.sh, also detect Ready=False and fail
immediately instead of waiting for the full timeout; preserve the existing VM
readiness wait behavior.
🪄 Autofix (Beta)

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: a4fbc20c-1841-4c5e-931c-87dc289ef805

📥 Commits

Reviewing files that changed from the base of the PR and between 706c3f0 and d3359d5.

📒 Files selected for processing (19)
  • examples/backups/vmdisk/00-helpers.sh
  • examples/backups/vmdisk/01-create-strategy.sh
  • examples/backups/vmdisk/02-create-backupclass.sh
  • examples/backups/vmdisk/03-create-vmdisk.sh
  • examples/backups/vmdisk/04-create-backupjob.sh
  • examples/backups/vmdisk/05-restore-in-place.sh
  • examples/backups/vmdisk/cleanup.sh
  • examples/backups/vmdisk/run-all.sh
  • examples/backups/vmi/00-helpers.sh
  • examples/backups/vmi/01-create-strategies.sh
  • examples/backups/vmi/04-create-vminstance.sh
  • examples/backups/vmi/05-create-backupjob.sh
  • examples/backups/vmi/06-restore-in-place.sh
  • examples/backups/vmi/07-restore-to-copy.sh
  • examples/backups/vmi/cleanup.sh
  • examples/backups/vmi/run-all.sh
  • hack/e2e-chainsaw/backup/README.md
  • hack/e2e-chainsaw/backup/chainsaw-test.yaml.disabled
  • hack/e2e-chainsaw/vminstance/chainsaw-test.yaml
💤 Files with no reviewable changes (2)
  • hack/e2e-chainsaw/backup/README.md
  • hack/e2e-chainsaw/backup/chainsaw-test.yaml.disabled

Comment on lines +33 to +37
log_step "Waiting for the VMDisk to import (HelmRelease Ready, DataVolume Ready, PVC Bound)..."
kubectl -n "$NAMESPACE" wait hr vm-disk-backup-src --for=condition=ready --timeout=600s
wait_for_field datavolume.cdi.kubevirt.io vm-disk-backup-src \
'{.status.phase}' Succeeded "$NAMESPACE" 600
wait_for_field pvc vm-disk-backup-src '{.status.phase}' Bound "$NAMESPACE" 300

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add the required event-driven backstop before each HelmRelease wait. Both workflows call kubectl wait directly, which can consume the full timeout after reconciliation has already emitted a failure event.

  • examples/backups/vmdisk/03-create-vmdisk.sh#L33-L37: add the documented event-driven backstop immediately before the VMDisk HelmRelease readiness wait.
  • examples/backups/vmdisk/05-restore-in-place.sh#L41-L43: add the same backstop immediately before the restored VMDisk HelmRelease readiness wait.

As per coding guidelines, “add event-driven backstops before every kubectl wait” and “fail fast on HelmRelease readiness.”

📍 Affects 2 files
  • examples/backups/vmdisk/03-create-vmdisk.sh#L33-L37 (this comment)
  • examples/backups/vmdisk/05-restore-in-place.sh#L41-L43
🤖 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 `@examples/backups/vmdisk/03-create-vmdisk.sh` around lines 33 - 37, Add the
documented event-driven backstop immediately before the HelmRelease readiness
wait in examples/backups/vmdisk/03-create-vmdisk.sh lines 33-37, using the
existing wait flow around kubectl and wait_for_field. Apply the same backstop
immediately before the restored VMDisk HelmRelease readiness wait in
examples/backups/vmdisk/05-restore-in-place.sh lines 41-43; both sites must fail
fast on HelmRelease readiness failures.

Source: Coding guidelines

Comment on lines +35 to +36
wait_for_field datavolume.cdi.kubevirt.io vm-disk-backup-src \
'{.status.phase}' Succeeded "$NAMESPACE" 600

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For the Containerized Data Importer version used by this repository, what exact .status.phase value is reported for a failed DataVolume import?

💡 Result:

For a failed DataVolume import in the Containerized Data Importer (CDI), the exact.status.phase value reported is Failed [1][2][3]. This status is documented in official CDI resources as one of the possible status phases for a DataVolume [1][2]. When an import operation encounters a failure, such as checksum validation issues [1][2] or after exhausted retries [3], the DataVolume transitions to this state. It is important to distinguish the.status.phase, which indicates the high-level state (e.g., Failed), from the DataVolume conditions or Pod logs, which provide further detail regarding the specific reason for the failure [2][3].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Locate relevant files and wait_for_field definition"
git ls-files | rg '(^|/)examples/backups/vmdisk/03-create-vmdisk\.sh$|wait_for_field|e2e-testing\.md|contributing\.md' || true

echo
echo "File excerpt:"
if [ -f examples/backups/vmdisk/03-create-vmdisk.sh ]; then
  nl -ba examples/backups/vmdisk/03-create-vmdisk.sh | sed -n '1,90p'
else
  echo "missing examples/backups/vmdisk/03-create-vmdisk.sh"
fi

echo
echo "Find wait_for_field definitions/usages:"
rg -n "function wait_for_field|wait_for_field|wait_for" -S --glob '!**/.git/**' . | sed -n '1,220p'

Repository: cozystack/cozystack

Length of output: 364


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "Script excerpt"
sed -n '1,90p' examples/backups/vmdisk/03-create-vmdisk.sh || true

echo
echo "wait_for_field definitions/usages"
rg -n "function wait_for_field|wait_for_field|wait_for" -S --glob '!**/.git/**' . | sed -n '1,240p' || true

echo
echo "Relevant docs excerpt"
sed -n '1,180p' docs/agents/e2e-testing.md | sed -n '1,220p' || true

Repository: cozystack/cozystack

Length of output: 28972


Fail immediately when the DataVolume import reaches its terminal failure phase. Line 35 omits wait_for_field’s fail value, so a failed image import waits the full 600-second budget despite never becoming Succeeded.

Proposed fix
 wait_for_field datavolume.cdi.kubevirt.io vm-disk-backup-src \
-    '{.status.phase}' Succeeded "$NAMESPACE" 600
+    '{.status.phase}' Succeeded "$NAMESPACE" 600 Failed
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
wait_for_field datavolume.cdi.kubevirt.io vm-disk-backup-src \
'{.status.phase}' Succeeded "$NAMESPACE" 600
wait_for_field datavolume.cdi.kubevirt.io vm-disk-backup-src \
'{.status.phase}' Succeeded "$NAMESPACE" 600 Failed
🤖 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 `@examples/backups/vmdisk/03-create-vmdisk.sh` around lines 35 - 36, Update the
wait_for_field invocation for vm-disk-backup-src to provide the DataVolume’s
terminal failure phase as its fail value, so imports stop immediately on failure
while retaining Succeeded as the success value and the existing namespace and
timeout.

Comment on lines +42 to +47
log_step "Waiting for the VMInstance to boot (HelmRelease + VirtualMachine Ready)..."
log_command "kubectl -n $NAMESPACE wait hr vm-instance-test --for=condition=ready"
kubectl -n "$NAMESPACE" wait hr vm-instance-test --for=condition=ready --timeout=900s
log_command "kubectl -n $NAMESPACE wait virtualmachine.kubevirt.io/vm-instance-test --for=condition=Ready"
kubectl -n "$NAMESPACE" wait virtualmachine.kubevirt.io/vm-instance-test \
--for=condition=Ready --timeout=600s

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add the required E2E readiness backstops.

The new raw kubectl wait calls omit the mandated event-driven backstop; additionally, the HelmRelease wait at Line 44 waits through Ready=False until its full timeout. Use the documented readiness wrapper/backstop and fail immediately on HelmRelease failure.

  • examples/backups/vmi/04-create-vminstance.sh#L42-L47: add the backstop before both waits and a terminal HelmRelease failure path.
  • examples/backups/vmi/06-restore-in-place.sh#L51-L54: add the backstop before the restored-VM wait.

As per coding guidelines: “add event-driven backstops before every kubectl wait” and “fail fast on HelmRelease readiness.”

📍 Affects 2 files
  • examples/backups/vmi/04-create-vminstance.sh#L42-L47 (this comment)
  • examples/backups/vmi/06-restore-in-place.sh#L51-L54
🤖 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 `@examples/backups/vmi/04-create-vminstance.sh` around lines 42 - 47, Add the
documented event-driven readiness backstop before each raw kubectl wait in
examples/backups/vmi/04-create-vminstance.sh (lines 42-47) and before the
restored-VM wait in examples/backups/vmi/06-restore-in-place.sh (lines 51-54).
In the HelmRelease wait path of 04-create-vminstance.sh, also detect Ready=False
and fail immediately instead of waiting for the full timeout; preserve the
existing VM readiness wait behavior.

Source: Coding guidelines

Make vmdisk-2-backup-roundtrip actually exercise a Velero backup/restore in
CI instead of exiting on the gate. It is the in-CI proof that the
cozy-default-velero-vmdisk path works end to end: a CSI VolumeSnapshot of
the LINSTOR `replicated` block disk, moved to S3 by Velero's data mover
(kopia), then restored back to a Bound, Ready disk. The platform ships a
default VolumeSnapshotClass for linstor.csi.linbit.com and runs Velero with
features: EnableCSI + deployNodeAgent, so the machinery is present in the
sandbox.

VMDisk (not VMInstance) is the un-gated CI case on purpose: it drives the
same Velero + CSI-data-mover + S3 path but captures only HelmRelease + PVC
(+ configmaps) — no nested VM boot, no guest-agent freeze, no 20Gi image —
so it is fast and reliable enough for kind. The heavier VMInstance
round-trip stays gated behind VMI_E2E_S3_ROUNDTRIP=1.

The platform cozy-default BSL derives the EXTERNAL S3 ingress endpoint,
which is unroutable inside kind (the same reason the postgres round-trip
targets the in-cluster endpoint). So the harness stands up a throwaway BSL
cozy-e2e-vmdisk pointing at the in-cluster seaweedfs endpoint with
insecureSkipTLSVerify (kind cannot trust the self-signed SeaweedFS CA) and
checksumAlgorithm="" (the velero-plugin-for-aws v1.14 / AWS-SDK-v2 vs
SeaweedFS incompatibility) — the #3236 fixes applied at
the BSL — reusing the platform bucket + cozy-backups-creds under a distinct
prefix. The example scripts stay generic and just consume
BACKUP_STORAGE_LOCATION. Runs in tenant-root so the data-mover DataUpload
Pods reach seaweedfs over same-tenant egress; the finally tears down the
throwaway BSL alongside the example cleanup.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
hack/e2e-chainsaw/vminstance/chainsaw-test.yaml (1)

356-369: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Teardown can leak the throwaway BSL when cleanup.sh fails.

The finally runs cleanup and BSL deletion in a single set -eu script. If examples/backups/vmdisk/cleanup.sh exits non-zero, set -e aborts before Line 369, so cozy-e2e-vmdisk is never deleted — a leak precisely in the failure path this teardown is meant to harden. Capture cleanup's status but always delete the BSL, then propagate the failure so the step still has teeth.

♻️ Always delete the BSL, still fail on cleanup error
         content: |
-          set -eu
-          cd ../../..
-          NAMESPACE="$NAMESPACE" examples/backups/vmdisk/cleanup.sh
-          kubectl -n cozy-velero delete bsl cozy-e2e-vmdisk --ignore-not-found
+          set -u
+          cd ../../..
+          rc=0
+          NAMESPACE="$NAMESPACE" examples/backups/vmdisk/cleanup.sh || rc=$?
+          kubectl -n cozy-velero delete bsl cozy-e2e-vmdisk --ignore-not-found
+          exit "$rc"
🤖 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 `@hack/e2e-chainsaw/vminstance/chainsaw-test.yaml` around lines 356 - 369,
Update the vmdisk backup-flow cleanup script around
examples/backups/vmdisk/cleanup.sh to capture its exit status without aborting,
always execute the cozy-e2e-vmdisk BSL deletion, then return the captured
cleanup status so teardown failures still fail the step.
🤖 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.

Nitpick comments:
In `@hack/e2e-chainsaw/vminstance/chainsaw-test.yaml`:
- Around line 356-369: Update the vmdisk backup-flow cleanup script around
examples/backups/vmdisk/cleanup.sh to capture its exit status without aborting,
always execute the cozy-e2e-vmdisk BSL deletion, then return the captured
cleanup status so teardown failures still fail the step.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f4e94f41-75c8-4738-9452-5a8e92b44272

📥 Commits

Reviewing files that changed from the base of the PR and between d3359d5 and 0d04bcc.

📒 Files selected for processing (1)
  • hack/e2e-chainsaw/vminstance/chainsaw-test.yaml

… tiny VM

Drop the VMI_E2E_S3_ROUNDTRIP gate on vminstance-2-backup-roundtrip so a real
Velero backup/restore of a booted VMInstance runs in CI, kept affordable by
shrinking the VM to the minimum: a cirros guest (~20MB image,
instanceProfile cirros) on the smallest instance type (u1.nano, 1 vCPU /
512Mi) with a 2Gi disk, and SKIP_RESTORE_TO_COPY=1 so only the in-place
restore runs (the cross-namespace to-copy restore stands up a second full VM
— too heavy for kind and redundant for proving the round-trip). cirros has
no qemu-guest-agent, so Velero takes a crash-consistent snapshot without a
filesystem freeze, which is fine for exercising the mechanics.

To keep the example a faithful demo while letting CI run it cheaply, the vmi
scripts gained overrides (all defaulting to the existing ubuntu demo):
VMI_IMAGE_URL + VMI_DISK_STORAGE (03-create-vmdisk), VMI_INSTANCE_PROFILE +
VMI_INSTANCE_TYPE (04-create-vminstance), and SKIP_RESTORE_TO_COPY (run-all).

Like vmdisk-2-backup-roundtrip, the harness stands up a throwaway in-cluster
BSL cozy-e2e-vmi (seaweedfs endpoint + insecureSkipTLSVerify +
checksumAlgorithm="", the #3236 fixes) reusing the platform bucket +
cozy-backups-creds, and the finally tears it down alongside the example
cleanup. Both VM backup round-trips now run un-gated in CI.

Assisted-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrey Kolkov <androndo@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@hack/e2e-chainsaw/vminstance/chainsaw-test.yaml`:
- Around line 243-245: Update both BSL validation loops for cozy-e2e-vmi (lines
243-245) and cozy-e2e-vmdisk (lines 373-378) to inspect the phase each
iteration, stop successfully on Available, and immediately print the BSL and
exit with failure on Unavailable; retain the 180-second timeout for other
phases.
🪄 Autofix (Beta)

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: 4bbed627-31c3-44d0-8b8d-344711c060d3

📥 Commits

Reviewing files that changed from the base of the PR and between 0d04bcc and ae05c87.

📒 Files selected for processing (4)
  • examples/backups/vmi/03-create-vmdisk.sh
  • examples/backups/vmi/04-create-vminstance.sh
  • examples/backups/vmi/run-all.sh
  • hack/e2e-chainsaw/vminstance/chainsaw-test.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/backups/vmi/04-create-vminstance.sh
  • examples/backups/vmi/run-all.sh

Comment on lines +243 to +245
echo "Waiting for BSL cozy-e2e-vmi to validate Available..."
timeout 180 sh -ec 'until [ "$(kubectl -n cozy-velero get bsl cozy-e2e-vmi -o jsonpath="{.status.phase}" 2>/dev/null)" = "Available" ]; do sleep 5; done'
kubectl -n cozy-velero get bsl cozy-e2e-vmi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== docs guideline files existence ==="
ls -l docs/agents/contributing.md docs/agents/changelog.md docs/agents/releasing.md docs/release.md docs/agents/overview.md docs/agents/e2e-testing.md 2>&1 || true

echo "=== target file outline/sections ==="
wc -l hack/e2e-chainsaw/vminstance/chainsaw-test.yaml
sed -n '220,260p' hack/e2e-chainsaw/vminstance/chainsaw-test.yaml
sed -n '350,390p' hack/e2e-chainsaw/vminstance/chainsaw-test.yaml

echo "=== BSL phase references in repository ==="
rg -n "status\.phase|phase: Unavailable|Unavailable|Available" hack/e2e-chainsaw/vminstance/chainsaw-test.yaml docs . --glob '!vendor/**' --glob '!**/.git/**' | head -n 200

Repository: cozystack/cozystack

Length of output: 36223


Fail immediately when the BSL becomes Unavailable.

The current loops keep sleeping until the 180s timeout once the BSL reports Unavailable, then only print the BSL. Inspect the phase each iteration; break when Available, and print the BSL then exit on Unavailable for both cozy-e2e-vmi and cozy-e2e-vmdisk.

📍 Affects 1 file
  • hack/e2e-chainsaw/vminstance/chainsaw-test.yaml#L243-L245 (this comment)
  • hack/e2e-chainsaw/vminstance/chainsaw-test.yaml#L373-L378
🤖 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 `@hack/e2e-chainsaw/vminstance/chainsaw-test.yaml` around lines 243 - 245,
Update both BSL validation loops for cozy-e2e-vmi (lines 243-245) and
cozy-e2e-vmdisk (lines 373-378) to inspect the phase each iteration, stop
successfully on Available, and immediately print the BSL and exit with failure
on Unavailable; retain the 180-second timeout for other phases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/testing Issues or PRs related to testing (e2e, bats, unit tests) area/virtualization Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import) size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant