Skip to content

Commit 69b953c

Browse files
committed
xtask: Add Anaconda liveimg installation test
Add 'cargo xtask anaconda' command that validates bootc containers can be installed via Anaconda's liveimg kickstart directive. This is an end-to-end integration test that: - Exports a bootc container to tar format using 'bootc container export' - Downloads and caches Anaconda installer ISOs (CentOS Stream 10, Fedora) - Generates kickstart files with liveimg --url=file:// directive - Uses virtiofs to share the tar with the VM (avoids HTTP server complexity) - Boots VM in UEFI mode with proper BLS boot entry generation - Monitors installation via Anaconda's virtio serial progress channel - Verifies installation using bcvk (disk inspection) and optionally SSH The test handles several tricky aspects of bootc + Anaconda integration: 1. BLS entry generation: bootc tar exports don't include Boot Loader Specification entries (they need root partition UUID). We generate these in the kickstart %post script. 2. SSH in chroot: The %post script runs in a chroot where services can't be started, only enabled. We configure sshd to start on first boot rather than trying to start it during installation. 3. Bootloader installation: Uses bootupctl to install the bootloader in the Anaconda %post environment. Usage: cargo xtask anaconda [--ssh] [--installer-type=centos-stream-10] \ <container-image> <output-disk> Assisted-by: OpenCode (Claude Sonnet 4)
1 parent c9691e3 commit 69b953c

File tree

9 files changed

+3722
-34
lines changed

9 files changed

+3722
-34
lines changed

.github/workflows/ci.yml

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,49 @@ jobs:
267267
name: tmt-log-PR-${{ github.event.number }}-fedora-43-coreos-${{ env.ARCH }}
268268
path: /var/tmp/tmt
269269

270+
# Test Anaconda installation with SSH verification
271+
# Tests the complete Anaconda workflow including SSH access to installed systems
272+
test-anaconda:
273+
needs: package
274+
runs-on: ubuntu-24.04
275+
276+
strategy:
277+
fail-fast: false
278+
matrix:
279+
test_os: [fedora-43, centos-9]
280+
281+
steps:
282+
- uses: actions/checkout@v6
283+
- name: Bootc Ubuntu Setup
284+
uses: bootc-dev/actions/bootc-ubuntu-setup@main
285+
with:
286+
libvirt: true
287+
288+
- name: Setup env
289+
run: |
290+
BASE=$(just pullspec-for-os base ${{ matrix.test_os }})
291+
echo "BOOTC_base=${BASE}" >> $GITHUB_ENV
292+
echo "BOOTC_variant=ostree" >> $GITHUB_ENV
293+
294+
- name: Download package artifacts
295+
uses: actions/download-artifact@v7
296+
with:
297+
name: packages-${{ matrix.test_os }}
298+
path: target/packages/
299+
300+
- name: Build container and run Anaconda SSH test
301+
run: |
302+
BOOTC_SKIP_PACKAGE=1 just build
303+
# Run Anaconda test with SSH verification directly
304+
just test-anaconda localhost/bootc /tmp/bootc-anaconda-${{ matrix.test_os }}.raw --ssh -- bootc status
305+
just clean-local-images
306+
307+
308+
270309
# Sentinel job for required checks - configure this job name in repository settings
271310
required-checks:
272311
if: always()
273-
needs: [cargo-deny, validate, package, test-integration, test-coreos]
312+
needs: [cargo-deny, validate, package, test-integration, test-coreos, test-anaconda]
274313
runs-on: ubuntu-latest
275314
steps:
276315
- run: exit 1
@@ -279,4 +318,5 @@ jobs:
279318
needs.validate.result != 'success' ||
280319
needs.package.result != 'success' ||
281320
needs.test-integration.result != 'success' ||
282-
needs.test-coreos.result != 'success'
321+
needs.test-coreos.result != 'success' ||
322+
needs.test-anaconda.result != 'success'

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Justfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,21 @@ test-tmt-on-coreos *ARGS:
132132
run-container-external-tests:
133133
./tests/container/run {{base_img}}
134134

135+
# Run end-to-end Anaconda installation test
136+
[group('testing')]
137+
test-anaconda IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
138+
cargo xtask anaconda {{IMAGE}} {{OUTPUT}} {{ARGS}}
139+
140+
# Test with auto-detected installer
141+
[group('testing')]
142+
test-anaconda-auto IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
143+
cargo xtask anaconda --installer-type auto {{IMAGE}} {{OUTPUT}} {{ARGS}}
144+
145+
# Test with CentOS Stream installer
146+
[group('testing')]
147+
test-anaconda-centos IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
148+
cargo xtask anaconda --installer-type centos-stream {{IMAGE}} {{OUTPUT}} {{ARGS}}
149+
135150
# Remove all test VMs created by tmt tests
136151
[group('testing')]
137152
tmt-vm-cleanup:

crates/lib/src/cli.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,13 @@ pub(crate) enum ContainerOpts {
421421
/// SELinux labeling. The output is written to stdout by default or to a specified file.
422422
///
423423
/// Example:
424-
/// bootc container export /target > output.tar
424+
/// bootc container export --experimental /target > output.tar
425+
#[clap(hide = true)]
425426
Export {
427+
/// Acknowledge that this is an experimental command that may change or be removed.
428+
#[clap(long)]
429+
experimental: bool,
430+
426431
/// Format for export output
427432
#[clap(long, default_value = "tar")]
428433
format: ExportFormat,
@@ -1661,12 +1666,16 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
16611666
args,
16621667
} => crate::ukify::build_ukify(&rootfs, &kargs, &args),
16631668
ContainerOpts::Export {
1669+
experimental,
16641670
format,
16651671
target,
16661672
output,
16671673
kernel_in_boot,
16681674
disable_selinux,
16691675
} => {
1676+
if !experimental {
1677+
anyhow::bail!("This command requires --experimental");
1678+
}
16701679
crate::container_export::export(
16711680
&format,
16721681
&target,

crates/xtask/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ xshell = { workspace = true }
2828

2929
# Crate-specific dependencies
3030
cargo_metadata = "0.23"
31+
tokio = { version = "1", features = ["process", "time", "rt-multi-thread", "macros", "io-util", "net"] }
3132
mandown = "1.1.0"
3233
rand = "0.9"
3334
serde_yaml = "0.9"
3435
tar = "0.4"
3536
itertools = "0.14.0"
37+
shlex = { workspace = true }
3638

3739
[lints]
3840
workspace = true

0 commit comments

Comments
 (0)