Skip to content

Commit

Permalink
cli: add container --lint
Browse files Browse the repository at this point in the history
Add initial lint functionality, the first lint
checks if there are multiple kernels in the image.

fixes: containers#216
Co-authored-by: Joseph Marrero <jmarrero@redhat.com>
Co-authored-by: Huijing Hei <hhei@redhat.com>
Co-authored-by: Yasmin de Souza <ydesouza@redhat.com>
Co-authored-by: Renata Ravanelli <rravanel@redhat.com>
Co-authored-by: Adam Piasecki <c4rt0gr4ph3r@gmail.com>
  • Loading branch information
6 people committed May 3, 2024
1 parent 79b1bc3 commit a0de33d
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 1 deletion.
55 changes: 55 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ pub(crate) struct ManOpts {
pub(crate) directory: Utf8PathBuf,
}

#[derive(Debug, Parser, PartialEq, Eq)]
pub(crate) struct ContainerOpts {
/// Run linting checking for files not supported on the container.
#[clap(long)]
pub(crate) lint: bool,
}

/// Hidden, internal only options
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
pub(crate) enum InternalsOpts {
Expand Down Expand Up @@ -181,6 +188,10 @@ pub(crate) enum TestingOpts {
#[clap(long)]
warn: bool,
},
// Test set of lints on ostree container
TestBuildLint {
image: String,
},
}

/// Deploy and transactionally in-place with bootable container images.
Expand Down Expand Up @@ -292,6 +303,8 @@ pub(crate) enum Opt {
#[clap(subcommand)]
#[cfg(feature = "install")]
Install(InstallOpts),
/// Commands to run on the container like lint.
Container(ContainerOpts),
/// Execute the given command in the host mount namespace
#[cfg(feature = "install")]
#[clap(hide = true)]
Expand Down Expand Up @@ -600,6 +613,14 @@ async fn edit(opts: EditOpts) -> Result<()> {
Ok(())
}

async fn container(opts: ContainerOpts) -> Result<()> {
if opts.lint {
lint()?;
}

Ok(())
}

/// Implementation of `bootc usroverlay`
async fn usroverlay() -> Result<()> {
// This is just a pass-through today. At some point we may make this a libostree API
Expand All @@ -610,6 +631,21 @@ async fn usroverlay() -> Result<()> {
.into());
}

/// Implementation of `bootc build commit`
/// async fn lint() -> Result<()> {
#[context("linting")]
fn lint() -> Result<()> {
if !ostree_ext::container_utils::is_ostree_container()? {
anyhow::bail!(
"Not in a ostree container, this command only verifies ostree containers."
);
}

let root = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
tracing::debug!("Found kernel: {:?}", ostree_ext::bootabletree::find_kernel_dir_fs(&root)?);
return Ok(());
}

/// Parse the provided arguments and execute.
/// Calls [`structopt::clap::Error::exit`] on failure, printing the error message and aborting the program.
pub async fn run_from_iter<I>(args: I) -> Result<()>
Expand Down Expand Up @@ -656,6 +692,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
Opt::Rollback(opts) => rollback(opts).await,
Opt::Edit(opts) => edit(opts).await,
Opt::UsrOverlay => usroverlay().await,
Opt::Container(opts) => container(opts).await,
#[cfg(feature = "install")]
Opt::Install(opts) => match opts {
InstallOpts::ToDisk(opts) => crate::install::install_to_disk(opts).await,
Expand Down Expand Up @@ -730,3 +767,21 @@ fn test_parse_generator() {
Opt::Internals(InternalsOpts::SystemdGenerator { .. })
));
}

#[test]
fn test_linting() {
// linting should only occur in side of a container.
match ostree_ext::container_utils::is_ostree_container() {
Ok(result) => {
if !result {
let expected_error_message = "Not in a ostree container, this command only verifies ostree containers.";

let result = lint();
assert_eq!(result.err().unwrap().to_string(), expected_error_message, "Error message mismatch");
}

},
Err(_) =>{
}
}
}
38 changes: 37 additions & 1 deletion lib/src/privtests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ 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;

Expand Down Expand Up @@ -196,6 +195,37 @@ fn verify_selinux_recurse(root: &Dir, path: &mut PathBuf, warn: bool) -> Result<
Ok(())
}

#[context("Container tests")]
fn test_container_lint(image: &str) -> Result<()> {

let sh = Shell::new()?;

// Smoke test of container --lint
let _test_1_result = cmd!(sh, "podman run --rm --privileged --pid=host --env=RUST_LOG -v /usr/bin/bootc:/usr/bin/bootc {image} bootc container --lint").run();

// Setup for multiple kernels lint test
cmd!(sh, "podman run -dt --name test --privileged --pid=host --env=RUST_LOG -v /usr/bin/bootc:/usr/bin/bootc {image} bash").run()?;
let kernel_name = cmd!(sh, "podman exec test bash -c 'ls /usr/lib/modules | tail -n -1'" ).read()?;
Command::new("podman")
.arg("exec")
.arg("test")
.arg("bash")
.arg("-c")
.arg(format!("sudo cp -r /usr/lib/modules/{} /usr/lib/modules/delete-me", kernel_name))
.output()?;
let more_then_one_kernel_result = cmd!(sh, "podman exec test bash -c 'bootc container --lint'").read_stderr();
// Container Cleanup
cmd!(sh, "podman rm -f test").run()?;

_test_1_result?;
if let Err(e) = more_then_one_kernel_result {
assert!(e.to_string().contains("bootc container --lint"));
} else {
assert!(false, "Expected error, got none");
}
Ok(())
}

pub(crate) async fn run(opts: TestingOpts) -> Result<()> {
match opts {
TestingOpts::RunPrivilegedIntegration {} => {
Expand All @@ -221,5 +251,11 @@ pub(crate) async fn run(opts: TestingOpts) -> Result<()> {
tokio::task::spawn_blocking(move || verify_selinux_recurse(&rootfs, &mut path, warn))
.await?
}
TestingOpts::TestBuildLint { image } => {
tokio::task::spawn_blocking(move || test_build_lint(&image)).await?
}
TestingOpts::TestContainerLint { image } => {
tokio::task::spawn_blocking(move || test_container_lint(&image)).await?
}
}
}

0 comments on commit a0de33d

Please sign in to comment.