Skip to content

Commit

Permalink
Integration test linux cgroups cpus (#462)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsturzl authored Nov 8, 2021
1 parent ac96399 commit 22f4fab
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 1 deletion.
3 changes: 2 additions & 1 deletion crates/integration_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ which = "4.2.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
nix = "0.23.0"
libcontainer = { path = "../libcontainer" }
libcontainer = { path = "../libcontainer" }
num_cpus = "1.0"
2 changes: 2 additions & 0 deletions crates/integration_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ fn main() -> Result<()> {
let pidfile = get_pidfile_test();
let ns_itype = get_ns_itype_tests();
let cgroup_v1_pids = cgroups::pids::get_test_group();
let cgroup_v1_cpus = cgroups::cpus::get_test_group();
let seccomp_notify = get_seccomp_notify_test();

tm.add_test_group(&cl);
Expand All @@ -71,6 +72,7 @@ fn main() -> Result<()> {
tm.add_test_group(&pidfile);
tm.add_test_group(&ns_itype);
tm.add_test_group(&cgroup_v1_pids);
tm.add_test_group(&cgroup_v1_cpus);

tm.add_cleanup(Box::new(cgroups::cleanup));
tm.add_test_group(&seccomp_notify);
Expand Down
309 changes: 309 additions & 0 deletions crates/integration_test/src/tests/cgroups/cpus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
use std::path::Path;

use anyhow::{Context, Result};
use num_cpus;
use oci_spec::runtime::{
LinuxBuilder, LinuxCpu, LinuxCpuBuilder, LinuxResourcesBuilder, Spec, SpecBuilder,
};
use test_framework::{test_result, ConditionalTest, TestGroup, TestResult};

use crate::utils::{test_outside_container, test_utils::check_container_created};

const CPU_CGROUP_PREFIX: &str = "/sys/fs/cgroup/cpu,cpuacct";
const DEFAULT_REALTIME_PERIOD: u64 = 1000000;
const DEFAULT_REALTIME_RUNTIME: i64 = 950000;

fn create_cpu_spec(
shares: u64,
quota: i64,
period: u64,
cpus: &str,
mems: &str,
realtime_period_opt: Option<u64>,
realtime_runtime_opt: Option<i64>,
) -> Result<LinuxCpu> {
let mut builder = LinuxCpuBuilder::default()
.shares(shares)
.quota(quota)
.period(period)
.cpus(cpus)
.mems(mems);

if let Some(realtime_period) = realtime_period_opt {
builder = builder.realtime_period(realtime_period);
}

if let Some(realtime_runtime) = realtime_runtime_opt {
builder = builder.realtime_runtime(realtime_runtime);
}

builder.build().context("failed to build cpu spec")
}

fn create_spec(cgroup_name: &str, case: LinuxCpu) -> Result<Spec> {
let spec = SpecBuilder::default()
.linux(
LinuxBuilder::default()
.cgroups_path(Path::new("/runtime-test").join(cgroup_name))
.resources(
LinuxResourcesBuilder::default()
.cpu(case)
.build()
.context("failed to build resource spec")?,
)
.build()
.context("failed to build linux spec")?,
)
.build()
.context("failed to build spec")?;

Ok(spec)
}

fn create_empty_spec(cgroup_name: &str) -> Result<Spec> {
let spec = SpecBuilder::default()
.linux(
LinuxBuilder::default()
.cgroups_path(Path::new("/runtime-test").join(cgroup_name))
.resources(
LinuxResourcesBuilder::default()
.cpu(
LinuxCpuBuilder::default()
.build()
.context("failed to build cpus spec")?,
)
.build()
.context("failed to build resource spec")?,
)
.build()
.context("failed to build linux spec")?,
)
.build()
.context("failed to build spec")?;

Ok(spec)
}

fn get_realtime_period() -> Option<u64> {
if Path::new(CPU_CGROUP_PREFIX)
.join("cpu.rt_period_us")
.exists()
{
return Some(DEFAULT_REALTIME_PERIOD);
}
None
}

fn get_realtime_runtime() -> Option<i64> {
if Path::new(CPU_CGROUP_PREFIX)
.join("cpu.rt_runtime_us")
.exists()
{
return Some(DEFAULT_REALTIME_RUNTIME);
}
None
}

fn test_cpu_cgroups() -> TestResult {
let cgroup_name = "test_cpu_cgroups";
// Kernel counts 0 as a CPU, so on a system with 8 logical cores you will need `0-7` range set.
let cpu_range = format!("0-{}", num_cpus::get() - 1);

let realtime_period = get_realtime_period();
let realtime_runtime = get_realtime_runtime();

let cases = vec![
test_result!(create_cpu_spec(
1024,
100000,
50000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
100000,
50000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
100000,
200000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
100000,
200000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
500000,
50000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
500000,
50000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
500000,
200000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
1024,
500000,
200000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
100000,
50000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
100000,
50000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
100000,
200000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
100000,
200000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
500000,
50000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
500000,
50000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
500000,
200000,
"0",
"0",
realtime_period,
realtime_runtime,
)),
test_result!(create_cpu_spec(
2048,
500000,
200000,
&cpu_range,
"0",
realtime_period,
realtime_runtime,
)),
];

for case in cases.into_iter() {
let spec = test_result!(create_spec(cgroup_name, case));
let test_result = test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));

TestResult::Passed
});

if let TestResult::Failed(_) = test_result {
return test_result;
}
}

TestResult::Passed
}

fn test_empty_cpu() -> TestResult {
let cgroup_name = "test_empty_cpu";
let spec = test_result!(create_empty_spec(cgroup_name));

test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));
TestResult::Passed
})
}

fn can_run() -> bool {
Path::new(CPU_CGROUP_PREFIX).exists()
}

pub fn get_test_group<'a>() -> TestGroup<'a> {
let mut test_group = TestGroup::new("cgroup_v1_cpus");
let linux_cgroups_cpus = ConditionalTest::new(
"test_linux_cgroups_cpus",
Box::new(can_run),
Box::new(test_cpu_cgroups),
);

let empty_cpu = ConditionalTest::new(
"test_empty_cpu",
Box::new(can_run),
Box::new(test_empty_cpu),
);

test_group.add(vec![Box::new(linux_cgroups_cpus), Box::new(empty_cpu)]);

test_group
}
1 change: 1 addition & 0 deletions crates/integration_test/src/tests/cgroups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use anyhow::{Context, Result};
use procfs::process::Process;
use std::fs;

pub mod cpus;
pub mod pids;

pub fn cleanup() -> Result<()> {
Expand Down

0 comments on commit 22f4fab

Please sign in to comment.