Skip to content

Commit 5ddd2e9

Browse files
committed
Add an internal-tests run-privileged-integration
Add a feature to enable internal tests. I originally started by matching ostreedev/ostree-rs-ext@6543c85 but since here the binary is really end user facing and not just a demo, we shouldn't enable the feature by default. If in the future we split off the tiny CLI bit out of the workspace, then we could auto-enable but that seems not worth it. Signed-off-by: Colin Walters <[email protected]>
1 parent 8c09af7 commit 5ddd2e9

File tree

5 files changed

+114
-20
lines changed

5 files changed

+114
-20
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
with:
5151
key: "build"
5252
- name: Build
53-
run: cargo build --release
53+
run: cargo build --release --features internal-testing-api
5454
- name: Upload binary
5555
uses: actions/upload-artifact@v2
5656
with:
@@ -110,21 +110,22 @@ jobs:
110110
run: cargo fmt -- --check -l
111111
- name: cargo clippy (warnings)
112112
run: cargo clippy -- -D warnings
113-
# privtest:
114-
# name: "Privileged testing"
115-
# needs: build
116-
# runs-on: ubuntu-latest
117-
# container:
118-
# image: quay.io/fedora/fedora-coreos:testing-devel
119-
# options: "--privileged --pid=host -v /run/systemd:/run/systemd -v /:/run/host"
120-
# steps:
121-
# - name: Checkout repository
122-
# uses: actions/checkout@v3
123-
# - name: Download
124-
# uses: actions/download-artifact@v2
125-
# with:
126-
# name: bootc
127-
# - name: Install
128-
# run: install bootc /usr/bin && rm -v bootc
129-
# - name: Integration tests
130-
# run: ./ci/priv-integration.sh
113+
privtest:
114+
name: "Privileged testing"
115+
needs: build
116+
runs-on: ubuntu-latest
117+
container:
118+
image: quay.io/fedora/fedora-coreos:testing-devel
119+
options: "--privileged --pid=host -v /run/systemd:/run/systemd -v /:/run/host"
120+
steps:
121+
- name: Checkout repository
122+
uses: actions/checkout@v3
123+
- name: Download
124+
uses: actions/download-artifact@v2
125+
with:
126+
name: bootc
127+
- name: Install
128+
run: install bootc /usr/bin && rm -v bootc
129+
- name: Integration tests
130+
run: bootc internal-tests run-privileged-integration
131+

lib/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ serde_json = "1.0.64"
2121
tokio = { features = ["io-std", "time", "process", "rt", "net"], version = ">= 1.13.0" }
2222
tokio-util = { features = ["io-util"], version = "0.7" }
2323
tracing = "0.1"
24+
tempfile = "3.3.0"
25+
xshell = { version = "0.2", optional = true }
2426

2527
[features]
28+
default = []
2629
docgen = ["clap_mangen"]
27-
30+
internal-testing-api = ["xshell"]

lib/src/cli.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ pub(crate) struct ManOpts {
7575
pub(crate) directory: Utf8PathBuf,
7676
}
7777

78+
/// Options for internal testing
79+
#[derive(Debug, clap::Subcommand)]
80+
pub(crate) enum TestingOpts {
81+
/// Execute integration tests that require a privileged container
82+
RunPrivilegedIntegration {},
83+
}
84+
7885
/// Deploy and upgrade via bootable container images.
7986
#[derive(Debug, Parser)]
8087
#[clap(name = "bootc")]
@@ -87,6 +94,10 @@ pub(crate) enum Opt {
8794
Switch(SwitchOpts),
8895
/// Display status
8996
Status(StatusOpts),
97+
/// Internal integration testing helpers.
98+
#[clap(hide(true), subcommand)]
99+
#[cfg(feature = "internal-testing-api")]
100+
InternalTests(TestingOpts),
90101
#[clap(hide(true))]
91102
#[cfg(feature = "docgen")]
92103
Man(ManOpts),
@@ -303,6 +314,11 @@ where
303314
Opt::Upgrade(opts) => upgrade(opts).await,
304315
Opt::Switch(opts) => switch(opts).await,
305316
Opt::Status(opts) => super::status::status(opts).await,
317+
#[cfg(feature = "internal-testing-api")]
318+
Opt::InternalTests(ref opts) => {
319+
ensure_self_unshared_mount_namespace().await?;
320+
crate::privtests::run(opts).await
321+
}
306322
#[cfg(feature = "docgen")]
307323
Opt::Man(manopts) => crate::docgen::generate_manpages(&manopts.directory),
308324
}

lib/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#![deny(clippy::todo)]
1515

1616
pub mod cli;
17+
#[cfg(feature = "internal-testing-api")]
18+
mod privtests;
1719
mod status;
1820
mod utils;
1921

lib/src/privtests.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::process::Command;
2+
3+
use anyhow::Result;
4+
use camino::{Utf8Path, Utf8PathBuf};
5+
use cap_std_ext::rustix;
6+
use rustix::fd::AsFd;
7+
use xshell::{cmd, Shell};
8+
9+
use super::cli::TestingOpts;
10+
11+
const IMGSIZE: u64 = 20 * 1024 * 1024 * 1024;
12+
13+
struct LoopbackDevice {
14+
#[allow(dead_code)]
15+
tmpf: tempfile::NamedTempFile,
16+
dev: Utf8PathBuf,
17+
}
18+
19+
impl LoopbackDevice {
20+
fn new_temp(sh: &xshell::Shell) -> Result<Self> {
21+
let mut tmpd = tempfile::NamedTempFile::new_in("/var/tmp")?;
22+
rustix::fs::ftruncate(tmpd.as_file_mut().as_fd(), IMGSIZE)?;
23+
let diskpath = tmpd.path();
24+
let path = cmd!(sh, "losetup --find --show {diskpath}").read()?;
25+
Ok(Self {
26+
tmpf: tmpd,
27+
dev: path.into(),
28+
})
29+
}
30+
}
31+
32+
impl Drop for LoopbackDevice {
33+
fn drop(&mut self) {
34+
let _ = Command::new("losetup")
35+
.args(["-d", self.dev.as_str()])
36+
.status();
37+
}
38+
}
39+
40+
fn init_ostree(sh: &Shell, rootfs: &Utf8Path) -> Result<()> {
41+
cmd!(sh, "ostree admin init-fs --modern {rootfs}").run()?;
42+
Ok(())
43+
}
44+
45+
pub(crate) fn impl_run() -> Result<()> {
46+
let sh = Shell::new()?;
47+
48+
let loopdev = LoopbackDevice::new_temp(&sh)?;
49+
let devpath = &loopdev.dev;
50+
println!("Using {devpath:?}");
51+
52+
let td = tempfile::tempdir()?;
53+
let td = td.path();
54+
let td: &Utf8Path = td.try_into()?;
55+
56+
cmd!(sh, "mkfs.xfs {devpath}").run()?;
57+
58+
cmd!(sh, "mount {devpath} {td}").run()?;
59+
60+
init_ostree(&sh, td)?;
61+
62+
let _g = sh.push_env("OSTREE_SYSROOT", td);
63+
cmd!(sh, "bootc status").run()?;
64+
65+
Ok(())
66+
}
67+
68+
pub(crate) async fn run(opts: &TestingOpts) -> Result<()> {
69+
match opts {
70+
TestingOpts::RunPrivilegedIntegration {} => tokio::task::spawn_blocking(impl_run).await?,
71+
}
72+
}

0 commit comments

Comments
 (0)