-
Notifications
You must be signed in to change notification settings - Fork 183
[WIP] evetest: kvm→k boot-disk conversion tests + volverify app #6267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
eriknordmark
wants to merge
26
commits into
lf-edge:master
Choose a base branch
from
eriknordmark:appvol-verify
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
7cb9a80
evetest: add volverify data-volume test app
eriknordmark 1c5bd5f
evetest: support blank data volumes on apps
eriknordmark 1c38ba8
evetest: add app-volume shrink corruption test
eriknordmark 9e89899
evetest: add kvm→k resize app-volume test
eriknordmark 02c8a33
volverify: treat a full volume as a clean stop
eriknordmark b5fc822
evetest: fold appvol shrink test into resize
eriknordmark c84b96a
evetest: capture whether the resize was interrupted
eriknordmark 892c6ad
evetest: let the chipset watchdog reset the guest
eriknordmark 7c5a638
evetest: let a test widen the upgrade budget
eriknordmark 123c4a4
evetest: assert the guest has a watchdog device
eriknordmark 53414e9
evetest: check the watchdog driver, not the node
eriknordmark 3c1cc78
evetest: recover the app PVC wedge in the shrink test
eriknordmark d90dae0
evetest: gate the shrink test on the app, not the commit
eriknordmark 8a7bcf3
evetest: place the app volume where the shrink will move it
eriknordmark b807790
evetest: read the resizer JSON key as emitted
eriknordmark c49c170
evetest: fix two untested paths in the shrink test
eriknordmark 11af068
evetest: record the fsck verdict beside the content verify
eriknordmark bb10b8c
evetest: check the volume again with the journal replayed
eriknordmark 7f433ff
evetest: judge volume damage by findings, not exit status
eriknordmark a6abcc4
evetest: capture wedge diags when app never runs
eriknordmark 5448260
evetest: search all of newlog, not just collect/
eriknordmark a7a3a7b
evetest: take the volume verdict without the app
eriknordmark 57e4f5d
evetest: wait for the volume relocation, don't race it
eriknordmark 8a37929
evetest: wait for volverify too, not just the volume
eriknordmark 2c87d08
evetest: make a shrink iteration measure something
eriknordmark c1388e0
evetest: capture the stalling CDI upload server
eriknordmark File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Copyright (c) 2026 Zededa, Inc. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| ARG GOLANG_VERSION=1.25 | ||
|
|
||
| # hadolint ignore=DL3029 | ||
| FROM --platform=$BUILDPLATFORM golang:${GOLANG_VERSION} AS build | ||
|
|
||
| ARG TARGETOS | ||
| ARG TARGETARCH | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| COPY go.mod ./ | ||
| RUN go mod download | ||
|
|
||
| COPY . . | ||
| RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /volverify ./cmd/volverify | ||
|
|
||
| FROM ubuntu:24.04 | ||
|
|
||
| SHELL ["/bin/bash", "-o", "pipefail", "-c"] | ||
|
|
||
| # hadolint ignore=DL3008 | ||
| RUN apt-get update && \ | ||
| apt-get install -y --no-install-recommends openssh-server e2fsprogs && \ | ||
| rm -rf /var/lib/apt/lists/* && \ | ||
| mkdir /run/sshd | ||
|
|
||
| RUN echo 'root:testpassword' | chpasswd | ||
| RUN sed -i 's/#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config && \ | ||
| sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config | ||
| EXPOSE 22 | ||
|
|
||
| COPY --from=build /volverify /usr/local/bin/volverify | ||
| COPY init.sh / | ||
|
|
||
| CMD ["/bin/bash", "/init.sh"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Copyright (c) 2026 Zededa, Inc. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| EVETEST_ORG ?= lfedge | ||
| IMAGE = $(EVETEST_ORG)/evetest-volverify | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rene FYI: we will need a new dockerhub repo |
||
| # Update VERSION whenever there is a change made to this app. | ||
| VERSION ?= 1.0 | ||
|
|
||
| DOCKER_TARGET ?= load | ||
| DOCKER_PLATFORM ?= $(shell uname -s | tr '[A-Z]' '[a-z]')/$(subst aarch64,arm64,$(subst x86_64,amd64,$(shell uname -m))) | ||
|
|
||
| build: | ||
| docker buildx build \ | ||
| --$(DOCKER_TARGET) \ | ||
| --platform $(DOCKER_PLATFORM) \ | ||
| -t $(IMAGE):$(VERSION) . | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # volverify — application-volume corruption verifier | ||
|
|
||
| A test-app tool that writes a deterministic, self-verifying fill/delete pattern to | ||
| an application volume and later checks it, to detect corruption caused by a | ||
| watchdog-interrupted EVE-kvm→EVE-k offline filesystem shrink. It is the ground | ||
| truth the soak harness pairs with the resize fsck marker. | ||
|
|
||
| Design: `~/notes/kvm-to-k-appvol-shrink-soak-design.md` (§4). Deployed inside the | ||
| evetest ubuntu app and driven over SSH via `RunShellScriptInsideApp`. | ||
|
|
||
| ## What it does | ||
|
|
||
| - **Layer 1** — every 4 KiB block is `AES-CTR(key=derive(fileID), iv=blockIndex)` | ||
| plus a header carrying the *logical* identity `(fileID, blockIndex)` and CRCs. | ||
| The identity is logical (file offset ÷ block size), never physical disk | ||
| placement — placement changes by design when the shrink relocates the P3 tail, | ||
| and the verifier checks that each logical read still yields the identity's | ||
| bytes. Reproducible, incompressible, non-zero, so a zeroed/torn/misplaced block | ||
| is unambiguous. | ||
| - **Layer 2** — a `masterSeed`-seeded PRNG drives a deterministic | ||
| create/delete/mkdir/rmdir op stream; the writer fsyncs and advances a 2-slot | ||
| ping-pong committed-index every `--commit-every` ops. The verifier replays the | ||
| stream to the committed index and classifies each expected file: | ||
| `ok / present-corrupt / orphaned (in lost+found) / lost / resurrected`. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```sh | ||
| volverify write --dir /mnt/data --seed 42 --ops 100000 # crash-safe, resumable | ||
| volverify verify --dir /mnt/data --seed 42 --ops 100000 # exits non-zero on any anomaly | ||
| ``` | ||
|
|
||
| Both invocations must use the same `--seed` and size flags. `write` is idempotent | ||
| across reboots (it resumes from the committed index). | ||
|
|
||
| `verify --expect-committed <N>` supplies an off-volume floor on the committed op | ||
| index. The on-volume commit slots live on the same volume being shrunk, so fsck can | ||
| clear them along with the last files' data — which would make the verifier expect | ||
| nothing and mask the loss. Since the soak harness runs `write` to completion before | ||
| the shrink, it knows the true high-water mark and passes it here, so the last work is | ||
| still expected (and its loss flagged). | ||
|
|
||
| ## Build | ||
|
|
||
| ```sh | ||
| make build # docker image lfedge/evetest-volverify:1.0 | ||
| GOWORK=off go test ./... # unit tests (fault-injection classification) | ||
| sudo ./scripts/loopback-ext4-test.sh # on-fs fidelity check (real ext4 + e2fsck) | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| // Copyright (c) 2026 Zededa, Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Command volverify writes and later verifies a deterministic, self-describing | ||
| // fill/delete pattern on an application volume, to detect corruption caused by a | ||
| // watchdog-interrupted EVE-kvm→EVE-k offline filesystem shrink. | ||
| // | ||
| // It is deployed inside the evetest test app and driven over SSH: | ||
| // | ||
| // volverify write --dir /mnt/data --seed 42 --ops 100000 | ||
| // volverify verify --dir /mnt/data --seed 42 --ops 100000 | ||
| // | ||
| // write is crash-safe and resumable: run it repeatedly across reboots. verify | ||
| // exits non-zero when it finds any anomaly and prints a machine-readable summary. | ||
| package main | ||
|
|
||
| import ( | ||
| "flag" | ||
| "fmt" | ||
| "os" | ||
|
|
||
| "github.com/lf-edge/eve/evetest/testapps/volverify/internal/verify" | ||
| ) | ||
|
|
||
| func main() { | ||
| if len(os.Args) < 2 { | ||
| usage() | ||
| os.Exit(2) | ||
| } | ||
| cmd := os.Args[1] | ||
| fs := flag.NewFlagSet(cmd, flag.ExitOnError) | ||
| dir := fs.String("dir", "", "volume mount point to operate on (required)") | ||
| def := verify.DefaultConfig() | ||
| seed := fs.Uint64("seed", def.Seed, "master seed for the op stream") | ||
| ops := fs.Uint64("ops", def.Ops, "number of ops to apply / expect") | ||
| commitEvery := fs.Uint64("commit-every", def.CommitEvery, "fsync + commit cadence in ops") | ||
| blockSize := fs.Int("block-size", def.BlockSize, "on-disk block size in bytes") | ||
| dirFanout := fs.Int("dir-fanout", def.DirFanout, "per-level file-tree fan-out") | ||
| smallBlocks := fs.Int("small-blocks", def.SmallBlocks, "max blocks for a small file") | ||
| medBlocks := fs.Int("med-blocks", def.MedBlocks, "max blocks for a medium file") | ||
| maxBlocks := fs.Int("max-blocks", def.MaxBlocks, "max blocks for a large file") | ||
| expectCommitted := fs.Int64("expect-committed", def.ExpectCommitted, | ||
| "verify: floor on the committed op index (harness high-water mark); -1 = trust on-volume commit only") | ||
| _ = fs.Parse(os.Args[2:]) | ||
|
|
||
| if *dir == "" { | ||
| fmt.Fprintln(os.Stderr, "error: --dir is required") | ||
| os.Exit(2) | ||
| } | ||
| cfg := verify.Config{ | ||
| Seed: *seed, | ||
| BlockSize: *blockSize, | ||
| Ops: *ops, | ||
| CommitEvery: *commitEvery, | ||
| DirFanout: *dirFanout, | ||
| SmallBlocks: *smallBlocks, | ||
| MedBlocks: *medBlocks, | ||
| MaxBlocks: *maxBlocks, | ||
| ExpectCommitted: *expectCommitted, | ||
| } | ||
|
|
||
| switch cmd { | ||
| case "write": | ||
| w, err := verify.NewWriter(*dir, cfg) | ||
| if err != nil { | ||
| fatal(err) | ||
| } | ||
| committed, err := w.Run() | ||
| if err != nil { | ||
| fatal(err) | ||
| } | ||
| fmt.Printf("write: complete committed=%d\n", committed) | ||
| case "verify": | ||
| rep, err := verify.Verify(*dir, cfg) | ||
| if err != nil { | ||
| fatal(err) | ||
| } | ||
| fmt.Println(rep.String()) | ||
| for _, a := range rep.Anomalies { | ||
| fmt.Printf(" ANOMALY file=%d verdict=%s path=%s expBlocks=%d sizeMismatch=%v blocks=%v\n", | ||
| a.FileID, a.Verdict, a.Path, a.ExpectBlocks, a.SizeMismatch, blockCountsString(a.BlockCounts)) | ||
| } | ||
| for _, id := range rep.Resurrected { | ||
| fmt.Printf(" ANOMALY resurrected file=%d\n", id) | ||
| } | ||
| if !rep.Clean() { | ||
| os.Exit(1) | ||
| } | ||
| fmt.Println("verify: clean") | ||
| default: | ||
| usage() | ||
| os.Exit(2) | ||
| } | ||
| } | ||
|
|
||
| func blockCountsString(m map[verify.BlockStatus]int) string { | ||
| out := "" | ||
| for s, n := range m { | ||
| if s == verify.BlockOK { | ||
| continue | ||
| } | ||
| out += fmt.Sprintf("%s=%d ", s, n) | ||
| } | ||
| if out == "" { | ||
| return "-" | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| func fatal(err error) { | ||
| fmt.Fprintln(os.Stderr, "error:", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| func usage() { | ||
| fmt.Fprintln(os.Stderr, "usage: volverify <write|verify> --dir <mount> [--seed N --ops N ...]") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| module github.com/lf-edge/eve/evetest/testapps/volverify | ||
|
|
||
| go 1.25 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Copyright (c) 2026 Zededa, Inc. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| # The volverify binary is not a daemon: the test drives it on demand over SSH | ||
| # (RunShellScriptInsideApp). Start sshd and keep the container alive. | ||
|
|
||
| /usr/sbin/sshd | ||
| exec sleep infinity |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps additional expected reboots and upgrade timeout can be just optional arguments for EdgeDevice.UpgradeEVE()?