Skip to content

Commit a972723

Browse files
authored
Merge pull request #43 from cgwalters/status-container
cli: More gracefully handle client commands in a container
2 parents a291e5b + 90f601c commit a972723

File tree

4 files changed

+65
-7
lines changed

4 files changed

+65
-7
lines changed

.github/workflows/ci.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,17 @@ jobs:
125125
run: sudo install bootc /usr/bin && rm -v bootc
126126
- name: Integration tests
127127
run: sudo podman run --rm -ti --privileged -v /run/systemd:/run/systemd -v /:/run/host -v /usr/bin/bootc:/usr/bin/bootc --pid=host quay.io/fedora/fedora-coreos:testing-devel bootc internal-tests run-privileged-integration
128-
128+
container-tests:
129+
name: "Container testing"
130+
needs: build
131+
runs-on: ubuntu-latest
132+
container: quay.io/fedora/fedora-coreos:testing-devel
133+
steps:
134+
- name: Download
135+
uses: actions/download-artifact@v2
136+
with:
137+
name: bootc
138+
- name: Install
139+
run: install bootc /usr/bin && rm -v bootc
140+
- name: Integration tests
141+
run: bootc internal-tests run-container-integration

lib/src/cli.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub(crate) struct ManOpts {
8080
pub(crate) enum TestingOpts {
8181
/// Execute integration tests that require a privileged container
8282
RunPrivilegedIntegration {},
83+
/// Execute integration tests that target a not-privileged ostree container
84+
RunContainerIntegration {},
8385
}
8486

8587
/// Deploy and upgrade via bootable container images.
@@ -214,6 +216,11 @@ async fn stage(
214216
/// A few process changes that need to be made for writing.
215217
#[context("Preparing for write")]
216218
async fn prepare_for_write() -> Result<()> {
219+
if ostree_ext::container_utils::is_ostree_container()? {
220+
anyhow::bail!(
221+
"Detected container (ostree base); this command requires a booted host system."
222+
);
223+
}
217224
ensure_self_unshared_mount_namespace().await?;
218225
if crate::lsm::selinux_enabled()? {
219226
crate::lsm::selinux_ensure_install()?;
@@ -329,10 +336,7 @@ where
329336
Opt::Install(opts) => crate::install::install(opts).await,
330337
Opt::Status(opts) => super::status::status(opts).await,
331338
#[cfg(feature = "internal-testing-api")]
332-
Opt::InternalTests(ref opts) => {
333-
ensure_self_unshared_mount_namespace().await?;
334-
crate::privtests::run(opts).await
335-
}
339+
Opt::InternalTests(ref opts) => crate::privtests::run(opts).await,
336340
#[cfg(feature = "docgen")]
337341
Opt::Man(manopts) => crate::docgen::generate_manpages(&manopts.directory),
338342
}

lib/src/privtests.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,41 @@ fn run_bootc_status() -> Result<()> {
8787
// Ok(())
8888
// }
8989

90-
pub(crate) fn impl_run() -> Result<()> {
90+
/// Tests run an ostree-based host
91+
#[context("Privileged container tests")]
92+
pub(crate) fn impl_run_host() -> Result<()> {
9193
run_bootc_status()?;
9294
println!("ok bootc status");
9395
//run_bootc_install()?;
9496
//println!("ok bootc install");
97+
println!("ok host privileged testing");
98+
Ok(())
99+
}
100+
101+
#[context("Container tests")]
102+
pub(crate) fn impl_run_container() -> Result<()> {
103+
assert!(ostree_ext::container_utils::is_ostree_container()?);
104+
let sh = Shell::new()?;
105+
let stout = cmd!(sh, "bootc status").read()?;
106+
assert!(stout.contains("Running in a container (ostree base)."));
107+
drop(stout);
108+
let o = Command::new("bootc").arg("upgrade").output()?;
109+
let st = o.status;
110+
assert!(!st.success());
111+
let stderr = String::from_utf8(o.stderr)?;
112+
assert!(stderr.contains("this command requires a booted host system"));
113+
println!("ok container integration testing");
95114
Ok(())
96115
}
97116

98117
pub(crate) async fn run(opts: &TestingOpts) -> Result<()> {
99118
match opts {
100-
TestingOpts::RunPrivilegedIntegration {} => tokio::task::spawn_blocking(impl_run).await?,
119+
TestingOpts::RunPrivilegedIntegration {} => {
120+
crate::cli::ensure_self_unshared_mount_namespace().await?;
121+
tokio::task::spawn_blocking(impl_run_host).await?
122+
}
123+
TestingOpts::RunContainerIntegration {} => {
124+
tokio::task::spawn_blocking(impl_run_container).await?
125+
}
101126
}
102127
}

lib/src/status.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ pub(crate) struct DeploymentStatus {
5353
pub(crate) deploy_serial: Option<u32>,
5454
}
5555

56+
/// This struct is serialized when we're running in a container image.
57+
#[derive(serde::Serialize)]
58+
pub(crate) struct StatusInContainer {
59+
pub(crate) is_container: bool,
60+
}
61+
5662
impl DeploymentStatus {
5763
/// Gather metadata from an ostree deployment into a Rust structure
5864
pub(crate) fn from_deployment(deployment: &ostree::Deployment, booted: bool) -> Result<Self> {
@@ -102,6 +108,16 @@ fn get_deployments(
102108

103109
/// Implementation of the `bootc status` CLI command.
104110
pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
111+
if ostree_ext::container_utils::is_ostree_container()? {
112+
if opts.json {
113+
let mut stdout = std::io::stdout().lock();
114+
serde_json::to_writer(&mut stdout, &StatusInContainer { is_container: true })
115+
.context("Serializing status")?;
116+
} else {
117+
println!("Running in a container (ostree base).");
118+
}
119+
return Ok(());
120+
}
105121
let sysroot = super::cli::get_locked_sysroot().await?;
106122
let repo = &sysroot.repo().unwrap();
107123
let booted_deployment = sysroot.booted_deployment();

0 commit comments

Comments
 (0)