Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 24 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,56 +27,50 @@ jobs:
components: rustfmt
- run: cargo fmt --all -- --check

build-and-unit-tests:
name: Build + unit tests
build:
name: Build + clippy + unit tests
runs-on: ubuntu-24.04
container:
image: quay.io/fedora/fedora:latest
steps:
- run: dnf -y install cargo clippy gcc-c++ fuse3-devel
- run: dnf -y install cargo clippy gcc-c++ fuse3-devel openssl-devel git
- uses: actions/checkout@v4
- name: Clippy
run: cargo clippy --workspace -- -D warnings
- name: Unit tests
run: cargo test --bin cfsrun

integration-rootless:
name: Integration tests (rootless)
runs-on: ubuntu-24.04
container:
image: quay.io/fedora/fedora:latest
options: "--user 1000 --tmpfs /var/tmp:rw,exec"
steps:
- run: |
dnf -y install cargo gcc-c++ fuse3-devel crun skopeo pasta jq
- uses: actions/checkout@v4
- name: Build composefs-rs (cfsctl)
- name: Build cfsrun
run: cargo build
- name: Build cfsctl
run: |
git clone --depth=1 https://github.com/containers/composefs-rs /tmp/composefs-rs
cargo build --manifest-path /tmp/composefs-rs/Cargo.toml -p composefs-ctl
- name: Build cfsrun
run: cargo build
- name: Run rootless integration tests
- name: Collect binaries
run: |
export CFSCTL=/tmp/composefs-rs/target/debug/cfsctl
cargo test --test integration
mkdir -p /tmp/binaries
cp target/debug/cfsrun /tmp/binaries/
cp /tmp/composefs-rs/target/debug/cfsctl /tmp/binaries/
- name: Upload binaries
uses: actions/upload-artifact@v4
with:
name: binaries
path: /tmp/binaries/

integration-rootful:
name: Integration tests (rootful)
needs: build
runs-on: ubuntu-24.04
container:
image: quay.io/fedora/fedora:latest
options: "--privileged --tmpfs /var/tmp:rw,exec"
steps:
- run: dnf -y install cargo gcc-c++ fuse3-devel crun skopeo pasta jq
- run: dnf -y install cargo gcc-c++ fuse3-devel openssl-devel crun skopeo pasta netavark
- uses: actions/checkout@v4
- name: Build composefs-rs (cfsctl)
run: |
git clone --depth=1 https://github.com/containers/composefs-rs /tmp/composefs-rs
cargo build --manifest-path /tmp/composefs-rs/Cargo.toml -p composefs-ctl
- name: Build cfsrun
run: cargo build
- name: Download binaries
uses: actions/download-artifact@v4
with:
name: binaries
path: /usr/local/bin
- run: chmod +x /usr/local/bin/cfsrun /usr/local/bin/cfsctl
- name: Run rootful integration tests
run: |
export CFSCTL=/tmp/composefs-rs/target/debug/cfsctl
cargo test --test integration
run: cargo test --test integration
62 changes: 38 additions & 24 deletions composefs-run/src/netavark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,36 +221,50 @@ pub fn setup(netns_path: &Path, container_id: &str, publish: &[super::PortSpec])
fs::create_dir_all(config_dir).ok();

let netavark = find_netavark()?;
let output = Command::new(&netavark)
.arg("--config")
.arg(config_dir)
.arg("setup")
.arg(netns_path)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.and_then(|mut child| {
use std::io::Write;
child
.stdin
.take()
.unwrap()
.write_all(options_json.as_bytes())?;
child.wait_with_output()
})
.context("Running netavark setup")?;

if !output.status.success() {
release_ip(&ip);
anyhow::bail!(
"netavark setup failed: {} {}",
// Netavark has a TOCTOU race when creating the bridge: two concurrent
// calls can both see ENODEV on get_link, then one fails with EEXIST
// on create_link. Retry in that case — the bridge exists on retry.
let mut last_err = String::new();
for _ in 0..3 {
let output = Command::new(&netavark)
.arg("--config")
.arg(config_dir)
.arg("setup")
.arg(netns_path)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.and_then(|mut child| {
use std::io::Write;
child
.stdin
.take()
.unwrap()
.write_all(options_json.as_bytes())?;
child.wait_with_output()
})
.context("Running netavark setup")?;

if output.status.success() {
return Ok(ip);
}

last_err = format!(
"{}{}",
String::from_utf8_lossy(&output.stderr),
String::from_utf8_lossy(&output.stdout)
);

if !last_err.contains("File exists") {
break;
}
std::thread::sleep(std::time::Duration::from_millis(50));
}

Ok(ip)
release_ip(&ip);
anyhow::bail!("netavark setup failed: {last_err}")
}

/// Run netavark teardown for the given network namespace.
Expand Down
6 changes: 4 additions & 2 deletions composefs-run/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,14 @@ fn rootful_device() {
}

#[test]
fn rootful_cgroup_path() {
fn rootful_cgroup() {
if !is_root() {
return;
}
// The container sees its cgroup root as "/" due to the cgroup namespace.
// Just verify it runs and has a cgroup v2 entry.
let output = run_ok(cfsrun().arg(IMAGE).args(["--", "cat", "/proc/1/cgroup"]));
assert!(stdout(&output).contains("cfsrun/"));
assert!(stdout(&output).contains("0::"));
}

#[test]
Expand Down
Loading