1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

tests: Drop internal-testing-api, move to tests-integration

Previous work started moving our tests into an external binary;
this is just cleaner because it can test things how a user
would test.  Also, we started using `libtest-mimic` to
have a "real" test scaffolding that e.g. allows selecting
individual tests to run, etc.

Complete the picture here by moving the remaining bits into
the tests-integration binary.  We now run the `tests-integration`
binary in two ways in e.g. Github Actions:

- It's compiled directly on the Ubuntu runner, and orchestrates
  things itself
- It's built in our default container image (Fedora) but as an external
  `/usr/bin/bootc-integration-tests` binary

Also while we're here, drop the kola tests.

Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
Colin Walters
2024-05-31 16:01:41 -04:00
parent f152bfe8da
commit 9be6b5a0b0
16 changed files with 183 additions and 371 deletions

View File

@@ -57,9 +57,7 @@ jobs:
- name: Build container (fedora)
run: sudo podman build --build-arg=base=quay.io/fedora/fedora-bootc:40 -t localhost/bootc -f hack/Containerfile .
- name: Container integration
run: sudo podman run --rm localhost/bootc bootc internal-tests run-container-integration
- name: Privileged tests
run: sudo podman run --rm --privileged -v /run/systemd:/run/systemd -v /:/run/host --pid=host localhost/bootc bootc internal-tests run-privileged-integration
run: sudo podman run --rm localhost/bootc bootc-integration-tests container
cargo-deny:
runs-on: ubuntu-latest
steps:
@@ -78,14 +76,22 @@ jobs:
uses: actions/checkout@v4
- name: Ensure host skopeo is disabled
run: sudo rm -f /bin/skopeo /usr/bin/skopeo
- name: Free up disk space on runner
run: sudo ./ci/clean-gha-runner.sh
- name: Integration tests
run: |
set -xeu
sudo podman build -t localhost/bootc -f hack/Containerfile .
export CARGO_INCREMENTAL=0 # because we aren't caching the test runner bits
cargo build --release -p tests-integration
df -h /
sudo install -m 0755 target/release/tests-integration /usr/bin/bootc-integration-tests
rm target -rf
df -h /
# Nondestructive but privileged tests
cargo run -p tests-integration host-privileged localhost/bootc
sudo bootc-integration-tests host-privileged localhost/bootc
# Finally the install-alongside suite
cargo run -p tests-integration install-alongside localhost/bootc
sudo bootc-integration-tests install-alongside localhost/bootc
docs:
if: ${{ contains(github.event.pull_request.labels.*.name, 'documentation') }}
runs-on: ubuntu-latest

3
Cargo.lock generated
View File

@@ -2016,6 +2016,9 @@ dependencies = [
"clap",
"fn-error-context",
"libtest-mimic",
"rustix",
"serde",
"serde_json",
"tempfile",
"xshell",
]

View File

@@ -3,9 +3,6 @@ prefix ?= /usr
all:
cargo build --release
all-test:
cargo build --release --all-features
install:
install -D -m 0755 -t $(DESTDIR)$(prefix)/bin target/release/bootc
install -d -m 0755 $(DESTDIR)$(prefix)/lib/systemd/system-generators/
@@ -22,11 +19,14 @@ install:
done
install -D -m 0644 -t $(DESTDIR)/$(prefix)/lib/systemd/system systemd/*.service systemd/*.timer
install-with-tests: install
install -D -m 0755 target/release/tests-integration $(DESTDIR)$(prefix)/bin/bootc-integration-tests
bin-archive: all
$(MAKE) install DESTDIR=tmp-install && tar --zstd -C tmp-install -cf target/bootc.tar.zst . && rm tmp-install -rf
test-bin-archive: all-test
$(MAKE) install DESTDIR=tmp-install && tar --zstd -C tmp-install -cf target/bootc.tar.zst . && rm tmp-install -rf
test-bin-archive: all
$(MAKE) install-with-tests DESTDIR=tmp-install && tar --zstd -C tmp-install -cf target/bootc.tar.zst . && rm tmp-install -rf
install-kola-tests:
install -D -t $(DESTDIR)$(prefix)/lib/coreos-assembler/tests/kola/bootc tests/kolainst/*

13
ci/clean-gha-runner.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
set -xeuo pipefail
df -h
docker image prune --all --force > /dev/null
rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android
apt-get remove -y '^aspnetcore-.*' > /dev/null
apt-get remove -y '^dotnet-.*' > /dev/null
apt-get remove -y '^llvm-.*' > /dev/null
apt-get remove -y 'php.*' > /dev/null
apt-get remove -y '^mongodb-.*' > /dev/null
apt-get remove -y '^mysql-.*' > /dev/null1
apt-get remove -y azure-cli google-chrome-stable firefox mono-devel >/dev/null
df -h

View File

@@ -54,5 +54,4 @@ default = ["install"]
install = []
# Implementation detail of man page generation.
docgen = ["clap_mangen"]
# This feature should only be enabled in CI environments.
internal-testing-api = ["xshell"]

View File

@@ -161,28 +161,6 @@ impl InternalsOpts {
const GENERATOR_BIN: &'static str = "bootc-systemd-generator";
}
/// Options for internal testing
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
pub(crate) enum TestingOpts {
/// Execute integration tests that require a privileged container
RunPrivilegedIntegration {},
/// Execute integration tests that target a not-privileged ostree container
RunContainerIntegration {},
/// Block device setup for testing
PrepTestInstallFilesystem { blockdev: Utf8PathBuf },
/// e2e test of install to-filesystem
TestInstallFilesystem {
image: String,
blockdev: Utf8PathBuf,
},
#[clap(name = "verify-selinux")]
VerifySELinux {
root: String,
#[clap(long)]
warn: bool,
},
}
/// Deploy and transactionally in-place with bootable container images.
///
/// The `bootc` project currently uses ostree-containers as a backend
@@ -302,10 +280,6 @@ pub(crate) enum Opt {
#[clap(subcommand)]
#[clap(hide = true)]
Internals(InternalsOpts),
/// Internal integration testing helpers.
#[clap(hide(true), subcommand)]
#[cfg(feature = "internal-testing-api")]
InternalTests(TestingOpts),
#[clap(hide(true))]
#[cfg(feature = "docgen")]
Man(ManOpts),
@@ -689,8 +663,6 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
}
InternalsOpts::FixupEtcFstab => crate::deploy::fixup_etc_fstab(&root),
},
#[cfg(feature = "internal-testing-api")]
Opt::InternalTests(opts) => crate::privtests::run(opts).await,
#[cfg(feature = "docgen")]
Opt::Man(manopts) => crate::docgen::generate_manpages(&manopts.directory),
}

View File

@@ -29,9 +29,6 @@ mod status;
mod task;
mod utils;
#[cfg(feature = "internal-testing-api")]
mod privtests;
#[cfg(feature = "install")]
mod blockdev;
#[cfg(feature = "install")]

View File

@@ -1,212 +0,0 @@
use std::os::fd::AsRawFd;
use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::{Context, Result};
use camino::Utf8Path;
use cap_std_ext::cap_std;
use cap_std_ext::cap_std::fs::Dir;
use fn_error_context::context;
use rustix::fd::AsFd;
use xshell::{cmd, Shell};
use crate::blockdev::LoopbackDevice;
use crate::install::config::InstallConfiguration;
use super::cli::TestingOpts;
use super::spec::Host;
const IMGSIZE: u64 = 20 * 1024 * 1024 * 1024;
fn init_ostree(sh: &Shell, rootfs: &Utf8Path) -> Result<()> {
cmd!(sh, "ostree admin init-fs --modern {rootfs}").run()?;
Ok(())
}
#[context("bootc status")]
fn run_bootc_status() -> Result<()> {
let sh = Shell::new()?;
let mut tmpdisk = tempfile::NamedTempFile::new_in("/var/tmp")?;
rustix::fs::ftruncate(tmpdisk.as_file_mut().as_fd(), IMGSIZE)?;
let loopdev = LoopbackDevice::new(tmpdisk.path())?;
let devpath = loopdev.path();
println!("Using {devpath:?}");
let td = tempfile::tempdir()?;
let td = td.path();
let td: &Utf8Path = td.try_into()?;
cmd!(sh, "mkfs.xfs {devpath}").run()?;
cmd!(sh, "mount {devpath} {td}").run()?;
init_ostree(&sh, td)?;
// Basic sanity test of `bootc status` on an uninitialized root
let _g = sh.push_env("OSTREE_SYSROOT", td);
cmd!(sh, "bootc status").run()?;
Ok(())
}
// This needs nontrivial work for loopback devices
// #[context("bootc install")]
// fn run_bootc_install() -> Result<()> {
// let sh = Shell::new()?;
// let loopdev = LoopbackDevice::new_temp(&sh)?;
// let devpath = &loopdev.dev;
// println!("Using {devpath:?}");
// let selinux_enabled = crate::lsm::selinux_enabled()?;
// let selinux_opt = if selinux_enabled {
// ""
// } else {
// "--disable-selinux"
// };
// cmd!(sh, "bootc install {selinux_opt} {devpath}").run()?;
// Ok(())
// }
/// Tests run an ostree-based host
#[context("Privileged container tests")]
pub(crate) fn impl_run_host() -> Result<()> {
run_bootc_status()?;
println!("ok bootc status");
//run_bootc_install()?;
//println!("ok bootc install");
println!("ok host privileged testing");
Ok(())
}
#[context("Container tests")]
pub(crate) fn impl_run_container() -> Result<()> {
let sh = Shell::new()?;
let host: Host = serde_yaml::from_str(&cmd!(sh, "bootc status").read()?)?;
assert!(matches!(host.status.ty, None));
println!("ok status");
for c in ["upgrade", "update"] {
let o = Command::new("bootc").arg(c).output()?;
let st = o.status;
assert!(!st.success());
let stderr = String::from_utf8(o.stderr)?;
assert!(
stderr.contains("this command requires a booted host system"),
"stderr: {stderr}",
);
}
println!("ok upgrade/update are errors in container");
let config = cmd!(sh, "bootc install print-configuration").read()?;
let mut config: InstallConfiguration =
serde_json::from_str(&config).context("Parsing install config")?;
// Just verify we parsed the config, if any
drop(config);
println!("ok container integration testing");
Ok(())
}
#[context("Prep test install filesystem")]
fn prep_test_install_filesystem(blockdev: &Utf8Path) -> Result<tempfile::TempDir> {
let sh = Shell::new()?;
// Arbitrarily larger partition offsets
let efipn = "5";
let bootpn = "6";
let rootpn = "7";
let mountpoint_dir = tempfile::tempdir()?;
let mountpoint: &Utf8Path = mountpoint_dir.path().try_into().unwrap();
// Create the partition setup; we add some random empty partitions for 2,3,4 just to exercise things
cmd!(
sh,
"sgdisk -Z {blockdev} -n 1:0:+1M -c 1:BIOS-BOOT -t 1:21686148-6449-6E6F-744E-656564454649 -n 2:0:+3M -n 3:0:+2M -n 4:0:+5M -n {efipn}:0:+127M -c {efipn}:EFI-SYSTEM -t ${efipn}:C12A7328-F81F-11D2-BA4B-00A0C93EC93B -n {bootpn}:0:+510M -c {bootpn}:boot -n {rootpn}:0:0 -c {rootpn}:root -t {rootpn}:0FC63DAF-8483-4772-8E79-3D69D8477DE4"
)
.run()?;
// Create filesystems and mount
cmd!(sh, "mkfs.ext4 {blockdev}{bootpn}").run()?;
cmd!(sh, "mkfs.ext4 {blockdev}{rootpn}").run()?;
cmd!(sh, "mkfs.fat {blockdev}{efipn}").run()?;
cmd!(sh, "mount {blockdev}{rootpn} {mountpoint}").run()?;
cmd!(sh, "mkdir {mountpoint}/boot").run()?;
cmd!(sh, "mount {blockdev}{bootpn} {mountpoint}/boot").run()?;
let efidir = crate::bootloader::EFI_DIR;
cmd!(sh, "mkdir {mountpoint}/boot/{efidir}").run()?;
cmd!(sh, "mount {blockdev}{efipn} {mountpoint}/boot/{efidir}").run()?;
Ok(mountpoint_dir)
}
#[context("Test install filesystem")]
fn test_install_filesystem(image: &str, blockdev: &Utf8Path) -> Result<()> {
let sh = Shell::new()?;
let mountpoint_dir = prep_test_install_filesystem(blockdev)?;
let mountpoint: &Utf8Path = mountpoint_dir.path().try_into().unwrap();
// And run the install
cmd!(sh, "podman run --rm --privileged --pid=host --env=RUST_LOG -v /usr/bin/bootc:/usr/bin/bootc -v {mountpoint}:/target-root {image} bootc install to-filesystem /target-root").run()?;
cmd!(sh, "umount -R {mountpoint}").run()?;
Ok(())
}
fn verify_selinux_label_exists(root: &Dir, path: &Path, warn: bool) -> Result<()> {
let mut buf = [0u8; 1024];
let fdpath = format!("/proc/self/fd/{}/", root.as_raw_fd());
let fdpath = &Path::new(&fdpath).join(path);
match rustix::fs::lgetxattr(fdpath, "security.selinux", &mut buf) {
// Ignore EOPNOTSUPPORTED
Ok(_) | Err(rustix::io::Errno::OPNOTSUPP) => Ok(()),
Err(rustix::io::Errno::NODATA) if warn => {
eprintln!("No SELinux label found for: {path:?}");
Ok(())
}
Err(e) => Err(e).with_context(|| format!("Failed to look up context for {path:?}")),
}
}
fn verify_selinux_recurse(root: &Dir, path: &mut PathBuf, warn: bool) -> Result<()> {
for ent in root.read_dir(&path)? {
let ent = ent?;
let name = ent.file_name();
path.push(name);
verify_selinux_label_exists(root, &path, warn)?;
let file_type = ent.file_type()?;
if file_type.is_dir() {
verify_selinux_recurse(root, path, warn)?;
}
path.pop();
}
Ok(())
}
pub(crate) async fn run(opts: TestingOpts) -> Result<()> {
match opts {
TestingOpts::RunPrivilegedIntegration {} => {
crate::cli::ensure_self_unshared_mount_namespace().await?;
tokio::task::spawn_blocking(impl_run_host).await?
}
TestingOpts::RunContainerIntegration {} => {
tokio::task::spawn_blocking(impl_run_container).await?
}
TestingOpts::PrepTestInstallFilesystem { blockdev } => {
tokio::task::spawn_blocking(move || prep_test_install_filesystem(&blockdev).map(|_| ()))
.await?
}
TestingOpts::TestInstallFilesystem { image, blockdev } => {
crate::cli::ensure_self_unshared_mount_namespace().await?;
tokio::task::spawn_blocking(move || test_install_filesystem(&image, &blockdev)).await?
}
// This one is currently executed mainly from Github Actions
TestingOpts::VerifySELinux { root, warn } => {
let rootfs = cap_std::fs::Dir::open_ambient_dir(root, cap_std::ambient_authority())
.context("Opening dir")?;
let mut path = PathBuf::from(".");
tokio::task::spawn_blocking(move || verify_selinux_recurse(&rootfs, &mut path, warn))
.await?
}
}
}

View File

@@ -17,5 +17,8 @@ cap-std-ext = "4"
clap = { version= "4.5.4", features = ["derive","cargo"] }
fn-error-context = "0.2.1"
libtest-mimic = "0.7.3"
rustix = { "version" = "0.38.34", features = ["thread", "fs", "system", "process"] }
serde = { features = ["derive"], version = "1.0.199" }
serde_json = "1.0.116"
tempfile = "3.10.1"
xshell = { version = "0.2.6" }

View File

@@ -0,0 +1,52 @@
use std::process::Command;
use anyhow::{Context, Result};
use fn_error_context::context;
use libtest_mimic::Trial;
use xshell::{cmd, Shell};
fn new_test(description: &'static str, f: fn() -> anyhow::Result<()>) -> libtest_mimic::Trial {
Trial::test(description, move || f().map_err(Into::into))
}
pub(crate) fn test_bootc_status() -> Result<()> {
let sh = Shell::new()?;
let host: serde_json::Value = serde_json::from_str(&cmd!(sh, "bootc status --json").read()?)?;
assert!(host.get("status").unwrap().get("ty").is_none());
Ok(())
}
pub(crate) fn test_bootc_upgrade() -> Result<()> {
for c in ["upgrade", "update"] {
let o = Command::new("bootc").arg(c).output()?;
let st = o.status;
assert!(!st.success());
let stderr = String::from_utf8(o.stderr)?;
assert!(
stderr.contains("this command requires a booted host system"),
"stderr: {stderr}",
);
}
Ok(())
}
pub(crate) fn test_bootc_install_config() -> Result<()> {
let sh = &xshell::Shell::new()?;
let config = cmd!(sh, "bootc install print-configuration").read()?;
let config: serde_json::Value =
serde_json::from_str(&config).context("Parsing install config")?;
// Just verify we parsed the config, if any
drop(config);
Ok(())
}
/// Tests that should be run in a default container image.
#[context("Container tests")]
pub(crate) fn run(testargs: libtest_mimic::Arguments) -> Result<()> {
let tests = [
new_test("bootc upgrade", test_bootc_upgrade),
new_test("install config", test_bootc_install_config),
new_test("status", test_bootc_status),
];
libtest_mimic::run(&testargs, tests.into()).exit()
}

View File

@@ -3,25 +3,42 @@ use fn_error_context::context;
use libtest_mimic::Trial;
use xshell::cmd;
struct TestState {
image: String,
}
fn new_test(
state: &'static TestState,
description: &'static str,
f: fn(&'static str) -> anyhow::Result<()>,
) -> libtest_mimic::Trial {
Trial::test(description, move || f(&state.image).map_err(Into::into))
}
fn test_loopback_install(image: &'static str) -> Result<()> {
let base_args = super::install::BASE_ARGS;
let sh = &xshell::Shell::new()?;
let size = 10 * 1000 * 1000 * 1000;
let mut tmpdisk = tempfile::NamedTempFile::new_in("/var/tmp")?;
tmpdisk.as_file_mut().set_len(size)?;
let tmpdisk = tmpdisk.into_temp_path();
let tmpdisk = tmpdisk.to_str().unwrap();
cmd!(sh, "sudo {base_args...} -v {tmpdisk}:/disk {image} bootc install to-disk --via-loopback --skip-fetch-check /disk").run()?;
Ok(())
}
/// Tests that require real root (e.g. CAP_SYS_ADMIN) to do things like
/// create loopback devices, but are *not* destructive. At the current time
/// these tests are defined to reference a bootc container image.
#[context("Hostpriv tests")]
pub(crate) fn run_hostpriv(image: &str, testargs: libtest_mimic::Arguments) -> Result<()> {
// Just leak the image name so we get a static reference as required by the test framework
let image: &'static str = String::from(image).leak();
let base_args = super::install::BASE_ARGS;
let state = Box::new(TestState {
image: image.to_string(),
});
// Make this static because the tests require it
let state: &'static TestState = Box::leak(state);
let tests = [Trial::test("loopback install", move || {
let sh = &xshell::Shell::new()?;
let size = 10 * 1000 * 1000 * 1000;
let mut tmpdisk = tempfile::NamedTempFile::new_in("/var/tmp")?;
tmpdisk.as_file_mut().set_len(size)?;
let tmpdisk = tmpdisk.into_temp_path();
let tmpdisk = tmpdisk.to_str().unwrap();
cmd!(sh, "sudo {base_args...} -v {tmpdisk}:/disk {image} bootc install to-disk --via-loopback --skip-fetch-check /disk").run()?;
Ok(())
})];
let tests = [new_test(&state, "loopback install", test_loopback_install)];
libtest_mimic::run(&testargs, tests.into()).exit()
}

View File

@@ -1,5 +1,5 @@
use std::os::fd::AsRawFd;
use std::path::Path;
use std::{os::fd::AsRawFd, path::PathBuf};
use anyhow::Result;
use cap_std_ext::cap_std;
@@ -108,7 +108,9 @@ pub(crate) fn run_alongside(image: &str, mut testargs: libtest_mimic::Arguments)
let sh = &xshell::Shell::new()?;
reset_root(sh)?;
cmd!(sh, "sudo {BASE_ARGS...} {target_args...} {image} bootc install to-existing-root --acknowledge-destructive {generic_inst_args...}").run()?;
cmd!(sh, "sudo podman run --rm --privileged --pid=host {target_args...} {image} bootc internal-tests verify-selinux /target/ostree --warn").run()?;
let root = &Dir::open_ambient_dir("/ostree", cap_std::ambient_authority()).unwrap();
let mut path = PathBuf::from(".");
crate::selinux::verify_selinux_recurse(root, &mut path, true)?;
Ok(())
}),
Trial::test("without an install config", move || {

View File

@@ -0,0 +1,35 @@
use std::os::fd::AsRawFd;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use cap_std_ext::cap_std::fs::Dir;
fn verify_selinux_label_exists(root: &Dir, path: &Path, warn: bool) -> Result<()> {
let mut buf = [0u8; 1024];
let fdpath = format!("/proc/self/fd/{}/", root.as_raw_fd());
let fdpath = &Path::new(&fdpath).join(path);
match rustix::fs::lgetxattr(fdpath, "security.selinux", &mut buf) {
// Ignore EOPNOTSUPPORTED
Ok(_) | Err(rustix::io::Errno::OPNOTSUPP) => Ok(()),
Err(rustix::io::Errno::NODATA) if warn => {
eprintln!("No SELinux label found for: {path:?}");
Ok(())
}
Err(e) => Err(e).with_context(|| format!("Failed to look up context for {path:?}")),
}
}
pub(crate) fn verify_selinux_recurse(root: &Dir, path: &mut PathBuf, warn: bool) -> Result<()> {
for ent in root.read_dir(&path)? {
let ent = ent?;
let name = ent.file_name();
path.push(name);
verify_selinux_label_exists(root, &path, warn)?;
let file_type = ent.file_type()?;
if file_type.is_dir() {
verify_selinux_recurse(root, path, warn)?;
}
path.pop();
}
Ok(())
}

View File

@@ -1,7 +1,13 @@
use std::path::PathBuf;
use camino::Utf8PathBuf;
use cap_std_ext::cap_std::{self, fs::Dir};
use clap::Parser;
mod container;
mod hostpriv;
mod install;
mod selinux;
#[derive(Debug, Parser)]
#[clap(name = "bootc-integration-tests", version, rename_all = "kebab-case")]
@@ -17,6 +23,20 @@ pub(crate) enum Opt {
#[clap(flatten)]
testargs: libtest_mimic::Arguments,
},
/// Tests which should be executed inside an existing bootc container image.
/// These should be nondestructive.
Container {
#[clap(flatten)]
testargs: libtest_mimic::Arguments,
},
/// Extra helper utility to verify SELinux label presence
#[clap(name = "verify-selinux")]
VerifySELinux {
/// Path to target root
rootfs: Utf8PathBuf,
#[clap(long)]
warn: bool,
},
}
fn main() {
@@ -24,6 +44,12 @@ fn main() {
let r = match opt {
Opt::InstallAlongside { image, testargs } => install::run_alongside(&image, testargs),
Opt::HostPrivileged { image, testargs } => hostpriv::run_hostpriv(&image, testargs),
Opt::Container { testargs } => container::run(testargs),
Opt::VerifySELinux { rootfs, warn } => {
let root = &Dir::open_ambient_dir(&rootfs, cap_std::ambient_authority()).unwrap();
let mut path = PathBuf::from(".");
selinux::verify_selinux_recurse(root, &mut path, warn)
}
};
if let Err(e) = r {
eprintln!("error: {e:?}");

View File

@@ -1,47 +0,0 @@
#!/bin/bash
# Verify basic bootc functionality.
## kola:
## timeoutMin: 30
## tags: "needs-internet"
#
# Copyright (C) 2022 Red Hat, Inc.
set -xeuo pipefail
cd $(mktemp -d)
case "${AUTOPKGTEST_REBOOT_MARK:-}" in
"")
bootc status > status.txt
grep 'Version:' status.txt
bootc status --json > status.json
image=$(jq '.status.booted.image.image' < status.json)
echo "booted into $image"
echo "ok status test"
# Switch should be idempotent
# (also TODO, get rid of the crazy .image.image.image nesting)
name=$(echo "${image}" | jq -r '.image')
bootc switch $name
staged=$(bootc status --json | jq .status.staged)
test "$staged" = "null"
host_ty=$(jq -r '.status.type' < status.json)
test "${host_ty}" = "bootcHost"
# Now fake things out with an empty /run
unshare -m /bin/sh -c 'mount -t tmpfs tmpfs /run; bootc status --json > status-no-run.json'
host_ty_norun=$(jq -r '.status.type' < status-no-run.json)
test "${host_ty_norun}" = "null"
test "null" = $(jq '.status.staged' < status.json)
# Should be a no-op
bootc update
test "null" = $(jq '.status.staged' < status.json)
test '!' -w /usr
bootc usroverlay
test -w /usr
echo "ok usroverlay"
;;
*) echo "unexpected mark: ${AUTOPKGTEST_REBOOT_MARK}"; exit 1;;
esac

View File

@@ -1,54 +0,0 @@
#!/bin/bash
# Verify install path
## kola:
## timeoutMin: 30
## tags: "needs-internet"
## platforms: qemu # additionalDisks is only supported on qemu
## additionalDisks: ["20G"]
#
# Copyright (C) 2022 Red Hat, Inc.
set -xeuo pipefail
IMAGE=quay.io/centos-bootc/fedora-bootc:eln-1708320930
# TODO: better detect this, e.g. look for an empty device
DEV=/dev/vda
# Always work out of a temporary directory
cd $(mktemp -d)
case "${AUTOPKGTEST_REBOOT_MARK:-}" in
"")
mkdir -p ~/.config/containers
cp -a /etc/ostree/auth.json ~/.config/containers
mkdir -p usr/{lib,bin}
cp -a /usr/lib/bootc usr/lib
cp -a /usr/bin/bootc usr/bin
cat > Dockerfile << EOF
FROM ${IMAGE}
COPY usr usr
EOF
podman build -t localhost/testimage .
podman run --rm --privileged --pid=host --env RUST_LOG=error,bootc_lib::install=debug \
localhost/testimage bootc install to-disk --skip-fetch-check --karg=foo=bar ${DEV}
# In theory we could e.g. wipe the bootloader setup on the primary disk, then reboot;
# but for now let's just sanity test that the install command executes.
lsblk ${DEV}
mount /dev/vda3 /var/mnt
grep foo=bar /var/mnt/loader/entries/*.conf
grep localtestkarg=somevalue /var/mnt/loader/entries/*.conf
grep -Ee '^linux /boot/ostree' /var/mnt/loader/entries/*.conf
umount /var/mnt
echo "ok install"
mount /dev/vda4 /var/mnt
ls -dZ /var/mnt |grep ':root_t:'
umount /var/mnt
# Now test install to-filesystem
# Wipe the device
ls ${DEV}* | tac | xargs wipefs -af
# This prepares the device and also runs podman directliy
bootc internal-tests test-install-filesystem ${IMAGE} ${DEV}
;;
*) echo "unexpected mark: ${AUTOPKGTEST_REBOOT_MARK}"; exit 1;;
esac