forked from containers/bootc
-
Notifications
You must be signed in to change notification settings - Fork 0
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
This also starts to make the logic reusable outside of Github Actions. Signed-off-by: Colin Walters <[email protected]>
- Loading branch information
Showing
7 changed files
with
207 additions
and
91 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,26 +68,6 @@ jobs: | |
with: | ||
name: bootc.tar.zst | ||
path: target/bootc.tar.zst | ||
build-c9s: | ||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'control/skip-ci') }} | ||
runs-on: ubuntu-latest | ||
container: quay.io/centos/centos:stream9 | ||
steps: | ||
- run: dnf -y install git-core | ||
- uses: actions/checkout@v4 | ||
- name: Install deps | ||
run: ./ci/installdeps.sh | ||
- name: Cache Dependencies | ||
uses: Swatinem/rust-cache@v2 | ||
with: | ||
key: "build-c9s" | ||
- name: Build | ||
run: make test-bin-archive | ||
- name: Upload binary | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: bootc-c9s.tar.zst | ||
path: target/bootc.tar.zst | ||
cargo-deny: | ||
runs-on: ubuntu-latest | ||
steps: | ||
|
@@ -127,78 +107,21 @@ jobs: | |
run: sudo tar -C / -xvf bootc.tar.zst | ||
- name: Integration tests | ||
run: bootc internal-tests run-container-integration | ||
privtest-alongside: | ||
install-tests: | ||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'control/skip-ci') }} | ||
name: "Test install-alongside" | ||
needs: [build-c9s] | ||
runs-on: ubuntu-latest | ||
name: "Test install" | ||
# For a not-ancient podman | ||
runs-on: ubuntu-24.04 | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
- name: Ensure host skopeo is disabled | ||
run: sudo rm -f /bin/skopeo /usr/bin/skopeo | ||
- name: Download | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: bootc-c9s.tar.zst | ||
- name: Install | ||
run: tar -xvf bootc.tar.zst | ||
- name: Integration tests | ||
run: | | ||
set -xeuo pipefail | ||
image=quay.io/centos-bootc/centos-bootc-dev:stream9 | ||
echo 'ssh-ed25519 ABC0123 [email protected]' > test_authorized_keys | ||
sudo podman run --rm --privileged -v ./test_authorized_keys:/test_authorized_keys --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ | ||
${image} bootc install to-filesystem --acknowledge-destructive \ | ||
--karg=foo=bar --disable-selinux --replace=alongside --root-ssh-authorized-keys=/test_authorized_keys /target | ||
ls -al /boot/loader/ | ||
sudo grep foo=bar /boot/loader/entries/*.conf | ||
grep authorized_keys /ostree/deploy/default/deploy/*/etc/tmpfiles.d/bootc-root-ssh.conf | ||
# TODO fix https://github.com/containers/bootc/pull/137 | ||
sudo chattr -i /ostree/deploy/default/deploy/* | ||
sudo rm /ostree/deploy/default -rf | ||
sudo podman run --rm --privileged --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ | ||
${image} bootc install to-existing-root --acknowledge-destructive | ||
sudo podman run --rm --privileged -v /:/target -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable ${image} bootc internal-tests verify-selinux /target/ostree --warn | ||
install-to-existing-root: | ||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'control/skip-ci') }} | ||
name: "Test install-to-existing-root" | ||
needs: [build-c9s] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Download | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: bootc-c9s.tar.zst | ||
- name: Install | ||
run: tar -xvf bootc.tar.zst | ||
- name: Integration tests | ||
run: | | ||
set -xeuo pipefail | ||
# We should be able to install to-existing-root with no install config, | ||
# so we bind mount an empty directory over /usr/lib/bootc/install. | ||
empty=$(mktemp -d) | ||
image=quay.io/centos-bootc/centos-bootc-dev:stream9 | ||
sudo podman run --rm --privileged --env RUST_LOG=debug -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc -v ${empty}:/usr/lib/bootc/install --pid=host --security-opt label=disable \ | ||
${image} bootc install to-existing-root | ||
install-to-loopback: | ||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'control/skip-ci') }} | ||
name: "Test install to-disk --via-loopback" | ||
needs: [build-c9s] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Download | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: bootc-c9s.tar.zst | ||
- name: Install | ||
run: tar -xvf bootc.tar.zst | ||
- name: Integration tests | ||
run: | | ||
set -xeuo pipefail | ||
image=quay.io/centos-bootc/centos-bootc-dev:stream9 | ||
tmpdisk=$(mktemp -p /var/tmp) | ||
truncate -s 20G ${tmpdisk} | ||
sudo podman run --rm --privileged --env RUST_LOG=debug -v /dev:/dev -v /:/target -v /var/lib/containers:/var/lib/containers -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ | ||
-v ${tmpdisk}:/disk ${image} bootc install to-disk --via-loopback /disk | ||
sudo podman build -t localhost/bootc -f hack/Containerfile . | ||
cargo run -p tests-integration run-install-tests localhost/bootc | ||
docs: | ||
if: ${{ contains(github.event.pull_request.labels.*.name, 'documentation') }} | ||
runs-on: ubuntu-latest | ||
|
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,160 @@ | ||
use std::os::fd::AsRawFd; | ||
use std::path::Path; | ||
|
||
use anyhow::{Context, 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, "chattr -i /ostree/deploy/default/deploy/*").run()?; | ||
cmd!(sh, "sudo rm /ostree/deploy/default -rf").run()?; | ||
Ok(()) | ||
} | ||
|
||
fn run_install<'a, 'b>( | ||
sh: &Shell, | ||
podman_args: impl Iterator<Item = &'a str>, | ||
image: &str, | ||
install_args: impl Iterator<Item = &'b str>, | ||
) -> Result<()> { | ||
cmd!(sh, "sudo podman run --rm --privileged -v /dev:/dev -v /var/lib/containers:/var/lib/containers --pid=host --security-opt label=disable {podman_args...} {image} bootc install {install_args...}").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") | ||
} | ||
|
||
#[context("Install tests")] | ||
fn run_install_tests(image: &str) -> Result<()> { | ||
let sh = &xshell::Shell::new()?; | ||
|
||
let target_args = ["-v", "/:/target"]; | ||
|
||
reset_root(sh)?; | ||
// A test case for replace=alongside with ssh keys and a karg, and SELinux disabled | ||
{ | ||
let tmpd = &sh.create_temp_dir()?; | ||
let tmp_keys = tmpd.path().join("test_authorized_keys"); | ||
std::fs::write(&tmp_keys, b"ssh-ed25519 ABC0123 [email protected]")?; | ||
let tmp_keys = format!("{}:/test_authorized_keys", tmp_keys.to_str().unwrap()); | ||
let install_args = [ | ||
"to-filesystem", | ||
"--acknowledge-destructive", | ||
"--karg=foo=bar", | ||
"--disable-selinux", | ||
"--replace=alongside", | ||
"--root-ssh-authorized-keys=/test_authorized_keys", | ||
"/target", | ||
]; | ||
run_install( | ||
sh, | ||
["-v", tmp_keys.as_str()].into_iter(), | ||
image, | ||
install_args.into_iter(), | ||
)?; | ||
|
||
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); | ||
} | ||
println!("ok install with tmpfiles and karg"); | ||
|
||
reset_root(sh)?; | ||
// And now an install where we verify selinux state | ||
run_install( | ||
sh, | ||
target_args.into_iter(), | ||
image, | ||
["to-existing-root", "--acknowledge-destructive"].into_iter(), | ||
)?; | ||
cmd!(sh, "sudo podman run --rm --privileged --pid=host {image} bootc internal-tests verify-selinux /target/ostree --warn").run()?; | ||
println!("ok install selinux"); | ||
|
||
reset_root(sh)?; | ||
// Test without an install config | ||
{ | ||
let empty = sh.create_temp_dir()?; | ||
let empty_arg = format!("{}:/usr/lib/bootc/install", empty.path().to_str().unwrap()); | ||
run_install( | ||
sh, | ||
target_args.into_iter().chain(["-v", empty_arg.as_str()]), | ||
image, | ||
["bootc", "install", "to-existing-root"].into_iter(), | ||
)?; | ||
} | ||
|
||
reset_root(sh)?; | ||
// And test a loopback install | ||
{ | ||
let size = 20_1000_1000_1000; | ||
let mut tmpdisk = tempfile::NamedTempFile::new_in("/var/tmp")?; | ||
tmpdisk.as_file_mut().set_len(size)?; | ||
let tmpdisk = tmpdisk.path().to_str().unwrap(); | ||
let diskarg = format!("{tmpdisk}:/disk"); | ||
run_install( | ||
sh, | ||
["-v", diskarg.as_str()].into_iter(), | ||
image, | ||
["to-disk", "--via-loopback", "/disk"].into_iter(), | ||
)?; | ||
} | ||
println!("ok install to-disk --via-loopback"); | ||
|
||
Ok(()) | ||
} |