Skip to content

ext install: probe the rpm database, not the directory, before skipping (ENG-2757) - #302

Open
nicksinas wants to merge 4 commits into
mainfrom
nsinas/ext-install-rpmdb-probe
Open

nicksinas wants to merge 4 commits into
mainfrom
nsinas/ext-install-rpmdb-probe

Conversation

@nicksinas

Copy link
Copy Markdown
Contributor

Summary

ENG-2757. In a project with runtime rt-a installed, add runtime rt-b and run avocado build -r rt-b before avocado install -r rt-b (or any plain avocado build out of habit). The build creates the empty rt-b extension sysroots with mkdir -p, then avocado install -r rt-b says every extension "is up to date" and leaves them empty, and the next avocado build -r rt-b ships empty extension images with exit 0. On the QEMU fixture, avocado-ext-dev-0.1.0.raw went from 4,026,368 bytes to 8,192 and avocado-ext-tunnels-0.1.0.raw from 4,370,432 to 1,605,632. Nothing in the log said so.

Three things line up to cause it. The install stamp is per extension, not per runtime, so rt-a's stamp satisfies rt-b. The fast path's sysroot probe tests only that the directory exists. And ext build only needs the stamp, so it builds an empty tree and creates the directory the probe then accepts.

A second path reaches the same state: the first install -r rt-b seeds the rpm database and then dnf fails (feed down, package missing). The seeded database stays, the retry passes the probe, and the sysroot never gets its packages.

Plain avocado install and avocado build on a multi-runtime project with no -r run the extension steps through the legacy $AVOCADO_PREFIX/extensions link. That is a known limitation tracked in ENG-2691 and is not changed here. Multi-runtime projects pass -r to install and build.

Changes

  • ext install: the fast path and the seed decision probe <sysroot>/var/lib/rpm, not the directory (ext_sysroot_seeded_test, sysroot_probe_line). The rpm database is written by the seed step and by nothing else, so its presence means an install reached dnf. Same rule as the runtime install's rpmdb_seeded_check. A directory with no database is also seeded now instead of handed to dnf as is, which would have resolved the whole dependency closure into the extension.
  • ext install: a failed dnf transaction on a sysroot this call seeded removes the seeded var/lib/rpm (drop_seeded_rpmdb_command), so the retry seeds and installs again. A sysroot that existed before the call keeps what it had.
  • ext build: a package extension whose sysroot has no rpm database is refused before anything is written: Extension '<ext>' declares packages, but its sysroot for runtime '<rt>' has no package database. Run 'avocado install -r <rt>' first. The probe rides in the existing stamp batch read, so there is no extra container round trip. Skipped under --no-stamps, like the rest of that block. Overlay-only extensions are not affected.
  • Scheduler: every task in the graph is registered on the renderer before it runs. Without a TTY, install and build hand the scheduler a fresh passthrough renderer with no task entries, and set_error keeps nothing for a task it has never seen, so a failed task printed only <id> failed. register_task is idempotent, so the TTY renderer keeps its entries and order. Passthrough success lines now show elapsed time, as TTY mode already did.
  • Renderer: passthrough mode prints a failed task's error message before its captured output, in the same order as the TTY summary. A task that fails in a precondition check has no captured output, so the message is all there is.

Testing

Unit tests, all new:

  • sysroot_probe_reports_yes_only_for_a_seeded_sysroot and a_failed_first_install_drops_only_the_seeded_rpmdb run the generated shell under sh against a tempdir.
  • declares_packages_needs_a_non_empty_packages_map, packages_not_installed_message_names_the_install_command.
  • a_failing_task_keeps_its_error_on_an_unregistered_renderer (scheduler), passthrough_failed_task_prints_its_error_message (renderer).

cargo test --no-fail-fast: 1986 passed, 5 failed. The same 5 fail on main at b796364 on macOS (BSD sed -i, no sha256sum): 4 sysroot digest tests in stamps.rs and ext::build::tests::install_section_from_a_dropin_enables_the_unit. All 136 integration tests pass. Clippy reports nothing in the touched files.

End to end, on macOS with the avocado-vm, a qemu-quickstart copy with two runtimes that share every extension, 2024/edge, qemux86-64. Same script and fixture against main and this branch.

Step main this branch
build -r dev-b before install exits 1 on sshd.socket, creates empty sysroots refused with the message above, nothing written
install -r dev-b after that "is up to date", no rpm db, 0 packages installs, rpm db present, 161 packages like dev
build -r dev-b, image sizes vs. the dev build ext-dev 4,026,368 to 8,192 unchanged
first install -r dev-b with dnf forced to fail seeded rpm db left behind rpm db removed
retry install -r dev-b "is up to date", 143 packages (the seed only) installs, 161 packages
install twice on a one-runtime project second says "is up to date" same

Final run on this branch: rpmdb-probe 13 of 13 checks pass, smoke 3 of 3, fast-path 1 of 1 (the second install still says "is up to date"). On main the same rpmdb-probe run fails 8 of 13. Fixture and script: wip/cli-rc6-fixtures/rpmdb-probe/ and local-scripts/cli-rc6-validate.sh in the workspace, not in this repo.

Follow-up (not in this PR)

  • ENG-2691: per-runtime stamp key, per-runtime images, and the legacy extensions link, which is what plain multi-runtime install and build still go through.
  • avocado build -r <rt> -e <ext> does not pass the runtime to the single-extension build, so the refusal there says Run 'avocado install' first without -r. Pre-existing.
  • Docs: one line that a project with more than one runtime passes -r to install and build.

…ng (ENG-2757)

A project with runtime rt-a installed adds rt-b. `avocado build -r rt-b`
before `avocado install -r rt-b` creates the empty rt-b sysroots with
`mkdir -p`; `install -r rt-b` then reads them as installed (directory
exists, pins from rt-a, the per-extension stamp from rt-a matches) and
skips; the next build ships empty extension images with exit 0.

- ext install: the fast path and the seed decision test
  <sysroot>/var/lib/rpm, which only the seed step writes. A failed first
  dnf transaction removes the seeded database so the retry installs.
- ext build: refuse a package extension whose sysroot has no rpm database,
  naming `avocado install -r <rt>`.
- scheduler: register every graph task on the renderer it was given. The
  fallback passthrough renderer used without a TTY had no entries, so
  set_error kept nothing and a failed task printed only "<id> failed".
- renderer: passthrough prints a failed task's error message before its
  captured output, as the TTY summary does.

Plain multi-runtime install and build without -r still go through the
legacy extensions link; that is ENG-2691.
Copilot AI balanced review requested due to automatic review settings October 16, 2026 21:34

Copilot AI 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.

🟡 Changes recommended

Override-only packages and interrupted installs bypass safeguards, and the recovery command can target the wrong runtime.

3 open issues
What changed in this PR

This PR hardens extension installation and builds against empty runtime sysroots, and improves failure reporting in non-interactive output.

Changes:

  • Probe the RPM database before skipping installation or building package extensions.
  • Remove newly seeded databases after failed package transactions.
  • Register scheduler tasks and display their errors, with regression tests.
File Description
src/​utils/​tui/​renderer.rs Prints task errors in passthrough mode.
src/​utils/​scheduler/​executor.rs Registers tasks before execution.
src/​commands/​ext/​install.rs Adds database probes and failed-install cleanup.
src/​commands/​ext/​build.rs Rejects package builds without a database.

Review effort: Balanced

Comment thread src/commands/ext/build.rs Outdated
Comment thread src/commands/ext/install.rs
Comment thread src/commands/ext/install.rs Outdated
…ope the clean hint

Review follow-ups on #302. declares_packages now sees packages declared
only inside target-* / kernel-* override blocks. The seeded rpm database
is removed when the dnf transaction returns Err (Ctrl-C), not only on a
failed exit. The recovery hint passes -r <runtime> when one is set.
Lockfile only. Clears the nine cargo audit findings that fail the
Security Audit job on every PR: RUSTSEC-2026-0338 to 0342 (quinn-proto,
fixed in 0.11.18) and RUSTSEC-2026-0346 to 0349 (rustls, fixed in 0.23.46).
Both crates are transitive, pulled in through reqwest.

(cherry picked from commit 0cd54a7)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants