mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-20 06:00:06 +08:00
* test(podman): run driver-podman userns suite against rootful Podman too The driver-specific-integration job only ran the driver-podman testsuite (default/auto/keep-id/private userns reference checks) against fedora-podman-rootless, leaving rootful behavior for this scenario unverified even though the compute driver auto-detects and explicitly supports rootful Podman. The default-userns-baseline and userns-profile playbooks hard-asserted a rootless tmachine gateway user, so pointing them at a rootful environment would have failed that assertion immediately rather than exercising anything. They now detect rootful vs. rootless via the existing tmachine_container_runtime role and branch the reference-capture user accordingly, while keeping the captured reference file itself owned by tmachine, since the archived test binary that reads it back always runs unprivileged as tmachine regardless of daemon mode. Signed-off-by: politerealism <burdcat17@gmail.com> * test(podman): add real-daemon coverage for resource limits and daemon failure Neither the Podman driver's resource-limit enforcement nor its behavior when the Podman daemon is unreachable had any test coverage against a real daemon; both were only exercised through unit tests against a mocked Podman client. podman_resource_limits.rs creates a sandbox with --cpu/--memory flags and reads /sys/fs/cgroup/memory.max and cpu.max from inside the sandbox itself, verifying the limit is actually enforced rather than just echoed back by the template API. Expected values are cross-checked against the driver's own parse_cpu_to_microseconds/parse_memory_to_bytes and against a real local `podman run --cpus/--memory` container. podman_preflight.rs spawns the standalone openshell-driver-podman binary against a guaranteed-nonexistent Podman socket and asserts it exits non-zero within its bounded retry window with an actionable error naming the socket path, rather than hanging or failing silently. Signed-off-by: politerealism <burdcat17@gmail.com> * test(podman): make rootful userns and cgroup checks pass Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(podman): match lifecycle containers by isolation role label Signed-off-by: Drew Newberry <anewberry@nvidia.com> * test(podman): accept non-expiring bootstrap tokens Signed-off-by: Drew Newberry <anewberry@nvidia.com> --------- Signed-off-by: politerealism <burdcat17@gmail.com> Signed-off-by: Drew Newberry <anewberry@nvidia.com> Co-authored-by: Drew Newberry <anewberry@nvidia.com>
90 lines
3.3 KiB
Rust
90 lines
3.3 KiB
Rust
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#![cfg(feature = "e2e-podman")]
|
|
|
|
//! Podman-specific E2E coverage verifying that declared sandbox CPU/memory
|
|
//! resource limits are actually enforced by cgroups inside the workload, not
|
|
//! just echoed back by the API/template layer.
|
|
//!
|
|
//! `e2e/rust/tests/sandbox_templates.rs` already verifies that
|
|
//! `sandbox template create --cpu ... --memory ...` is stored and returned
|
|
//! correctly, but it never inspects the resulting container's real resource
|
|
//! state. This test creates a sandbox with those flags directly and reads the
|
|
//! cgroup v2 interface files from inside the sandbox itself, so it exercises
|
|
//! the actual enforcement boundary the workload experiences.
|
|
|
|
use openshell_e2e::harness::sandbox::SandboxGuard;
|
|
|
|
const CGROUP_READ_POLICY: &str = r"version: 1
|
|
filesystem_policy:
|
|
include_workdir: true
|
|
read_only: [/usr, /lib, /lib64, /proc, /etc, /sys/fs/cgroup]
|
|
read_write: [/sandbox, /tmp, /dev/null]
|
|
landlock:
|
|
compatibility: best_effort
|
|
network_policies: {}
|
|
";
|
|
|
|
const CPU_REQUEST: &str = "500m";
|
|
const MEMORY_REQUEST: &str = "512Mi";
|
|
|
|
// "500m" (500 millicores) becomes a 50000us quota over Podman's 100000us
|
|
// (100ms) CFS period — see
|
|
// crates/openshell-driver-podman/src/container.rs's parse_cpu_to_microseconds.
|
|
// Verified directly against a real `podman run --cpus=0.5` container, whose
|
|
// cpu.max reads "50000 100000".
|
|
const EXPECTED_CPU_MAX: &str = "50000 100000";
|
|
|
|
// "512Mi" (mebibytes) becomes exactly 512 * 1024 * 1024 bytes — see
|
|
// crates/openshell-driver-podman/src/container.rs's parse_memory_to_bytes.
|
|
// Verified directly against a real `podman run --memory=512m` container,
|
|
// whose memory.max reads "536870912".
|
|
const EXPECTED_MEMORY_MAX: &str = "536870912";
|
|
|
|
#[tokio::test]
|
|
async fn sandbox_resource_limits_are_enforced_via_cgroups() {
|
|
if std::env::var("OPENSHELL_E2E_DRIVER").as_deref() != Ok("podman") {
|
|
eprintln!("Skipping Podman resource-limit test: e2e driver is not podman");
|
|
return;
|
|
}
|
|
|
|
let policy = tempfile::NamedTempFile::new().expect("create cgroup read policy file");
|
|
std::fs::write(policy.path(), CGROUP_READ_POLICY).expect("write cgroup read policy");
|
|
let policy_path = policy.path().to_str().expect("policy path is UTF-8");
|
|
let mut sandbox = SandboxGuard::create(&[
|
|
"--cpu",
|
|
CPU_REQUEST,
|
|
"--memory",
|
|
MEMORY_REQUEST,
|
|
"--policy",
|
|
policy_path,
|
|
])
|
|
.await
|
|
.expect("sandbox create with resource limits should succeed");
|
|
|
|
let memory_max = sandbox
|
|
.exec(&["cat", "/sys/fs/cgroup/memory.max"])
|
|
.await
|
|
.expect("read memory.max from sandbox cgroup")
|
|
.trim()
|
|
.to_string();
|
|
assert_eq!(
|
|
memory_max, EXPECTED_MEMORY_MAX,
|
|
"sandbox cgroup should enforce the declared {MEMORY_REQUEST} memory limit, got {memory_max}"
|
|
);
|
|
|
|
let cpu_max = sandbox
|
|
.exec(&["cat", "/sys/fs/cgroup/cpu.max"])
|
|
.await
|
|
.expect("read cpu.max from sandbox cgroup")
|
|
.trim()
|
|
.to_string();
|
|
assert_eq!(
|
|
cpu_max, EXPECTED_CPU_MAX,
|
|
"sandbox cgroup should enforce the declared {CPU_REQUEST} CPU limit, got {cpu_max}"
|
|
);
|
|
|
|
sandbox.cleanup().await;
|
|
}
|