-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move install tests shell script into Rust
A few things going on here: - Rewrite logic from shell script into Rust (using xshell, so it's still convenient to fork commands) - Make the test logic take an externally-built container image instead of using a `-v bootc:/usr/bin/bootc` bind mount - Build the container image using our stock hack/Containerfile in Github Actions instead of building for c9s in GHA - This all hence starts to make the logic reusable outside of Github Actions too; the container build is a known standard thing. Signed-off-by: Colin Walters <walters@verbum.org>
- Loading branch information
Showing
7 changed files
with
205 additions
and
92 deletions.
There are no files selected for viewing
This file contains 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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 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 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 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,20 @@ | ||
# Our integration tests | ||
[package] | ||
name = "tests-integration" | ||
version = "0.1.0" | ||
license = "MIT OR Apache-2.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[[bin]] | ||
name = "tests-integration" | ||
path = "src/tests-integration.rs" | ||
|
||
[dependencies] | ||
anyhow = "1.0.82" | ||
camino = "1.1.6" | ||
cap-std-ext = "4" | ||
clap = { version= "4.5.4", features = ["derive","cargo"] } | ||
fn-error-context = "0.2.1" | ||
tempfile = "3.10.1" | ||
xshell = { version = "0.2.6" } |
This file contains 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,157 @@ | ||
use std::os::fd::AsRawFd; | ||
use std::path::Path; | ||
|
||
use anyhow::Result; | ||
use cap_std_ext::cap_std; | ||
use cap_std_ext::cap_std::fs::Dir; | ||
use clap::Parser; | ||
use fn_error_context::context; | ||
|
||
use xshell::{cmd, Shell}; | ||
|
||
#[derive(Debug, Parser, PartialEq, Eq)] | ||
#[clap(name = "bootc-integration-tests", version, rename_all = "kebab-case")] | ||
pub(crate) enum Opt { | ||
RunInstallTests { | ||
/// Source container image reference | ||
image: String, | ||
}, | ||
} | ||
|
||
fn main() { | ||
if let Err(e) = try_main() { | ||
eprintln!("error: {e:?}"); | ||
std::process::exit(1); | ||
} | ||
} | ||
|
||
fn try_main() -> Result<()> { | ||
let opt = Opt::parse(); | ||
match opt { | ||
Opt::RunInstallTests { image } => run_install_tests(image.as_str()), | ||
} | ||
} | ||
|
||
// Clear out and delete any ostree roots | ||
fn reset_root(sh: &Shell) -> Result<()> { | ||
// TODO fix https://github.com/containers/bootc/pull/137 | ||
if !Path::new("/ostree/deploy/default").exists() { | ||
return Ok(()); | ||
} | ||
cmd!( | ||
sh, | ||
"sudo /bin/sh -c 'chattr -i /ostree/deploy/default/deploy/*'" | ||
) | ||
.run()?; | ||
cmd!(sh, "sudo rm /ostree/deploy/default -rf").run()?; | ||
Ok(()) | ||
} | ||
|
||
fn find_deployment_root() -> Result<Dir> { | ||
let _stateroot = "default"; | ||
let d = Dir::open_ambient_dir( | ||
"/ostree/deploy/default/deploy", | ||
cap_std::ambient_authority(), | ||
)?; | ||
for child in d.entries()? { | ||
let child = child?; | ||
if !child.file_type()?.is_dir() { | ||
continue; | ||
} | ||
return Ok(child.open_dir()?); | ||
} | ||
anyhow::bail!("Failed to find deployment root") | ||
} | ||
|
||
fn run_test<F>(sh: &Shell, desc: &str, f: F) -> Result<()> | ||
where | ||
F: FnOnce(&Shell) -> Result<()>, | ||
{ | ||
reset_root(sh)?; | ||
println!("test: {desc}"); | ||
match f(sh) { | ||
Ok(r) => { | ||
println!("ok: {desc}"); | ||
Ok(r) | ||
} | ||
Err(e) => { | ||
eprintln!("FAILED: {desc}"); | ||
Err(e) | ||
} | ||
} | ||
} | ||
|
||
#[context("Install tests")] | ||
fn run_install_tests(image: &str) -> Result<()> { | ||
let sh = &xshell::Shell::new()?; | ||
|
||
let base_args = [ | ||
"podman", | ||
"run", | ||
"--rm", | ||
"--privileged", | ||
"-v", | ||
"/dev:/dev", | ||
"-v", | ||
"/var/lib/containers:/var/lib/containers", | ||
"--pid=host", | ||
"--security-opt", | ||
"label=disable", | ||
]; | ||
let image_install = [image, "bootc", "install"]; | ||
let target_args = ["-v", "/:/target"]; | ||
// We always need this as we assume we're operating on a local image | ||
let generic_inst_args = ["--skip-fetch-check"]; | ||
|
||
run_test(sh, "loopback install", |sh| { | ||
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_install...} to-disk --via-loopback {generic_inst_args...} /disk").run()?; | ||
Ok(()) | ||
})?; | ||
|
||
run_test( | ||
sh, | ||
"replace=alongside with ssh keys and a karg, and SELinux disabled", | ||
|sh| { | ||
let tmpd = &sh.create_temp_dir()?; | ||
let tmp_keys = tmpd.path().join("test_authorized_keys"); | ||
let tmp_keys = tmp_keys.to_str().unwrap(); | ||
std::fs::write(&tmp_keys, b"ssh-ed25519 ABC0123 testcase@example.com")?; | ||
cmd!(sh, "sudo {base_args...} {target_args...} -v {tmp_keys}:/test_authorized_keys {image_install...} to-filesystem {generic_inst_args...} --acknowledge-destructive --karg=foo=bar --replace=alongside --root-ssh-authorized-keys=/test_authorized_keys /target").run()?; | ||
|
||
cmd!( | ||
sh, | ||
"sudo /bin/sh -c 'grep foo=bar /boot/loader/entries/*.conf'" | ||
) | ||
.run()?; | ||
let deployment = &find_deployment_root()?; | ||
let cwd = sh.push_dir(format!("/proc/self/fd/{}", deployment.as_raw_fd())); | ||
cmd!( | ||
sh, | ||
"grep authorized_keys etc/tmpfiles.d/bootc-root-ssh.conf" | ||
) | ||
.run()?; | ||
drop(cwd); | ||
Ok(()) | ||
}, | ||
)?; | ||
|
||
run_test(sh, "Install and verify selinux state", |sh| { | ||
cmd!(sh, "sudo {base_args...} {target_args...} {image_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()?; | ||
Ok(()) | ||
})?; | ||
|
||
run_test(sh, "without an install config", |sh| { | ||
let empty = sh.create_temp_dir()?; | ||
let empty = empty.path().to_str().unwrap(); | ||
cmd!(sh, "sudo {base_args...} {target_args...} -v {empty}:/usr/lib/bootc/install {image_install...} to-existing-root {generic_inst_args...}").run()?; | ||
Ok(()) | ||
})?; | ||
|
||
Ok(()) | ||
} |