diff --git a/tests/contest/contest/src/main.rs b/tests/contest/contest/src/main.rs index e0d3a4a0..e18f639a 100644 --- a/tests/contest/contest/src/main.rs +++ b/tests/contest/contest/src/main.rs @@ -21,6 +21,7 @@ use crate::tests::linux_ns_itype::get_ns_itype_tests; use crate::tests::mounts_recursive::get_mounts_recursive_test; use crate::tests::no_pivot::get_no_pivot_test; use crate::tests::pidfile::get_pidfile_test; +use crate::tests::process_rlimits::get_process_rlimits_test; use crate::tests::readonly_paths::get_ro_paths_test; use crate::tests::scheduler::get_scheduler_test; use crate::tests::seccomp::get_seccomp_test; @@ -114,6 +115,7 @@ fn main() -> Result<()> { let scheduler = get_scheduler_test(); let io_priority_test = get_io_priority_test(); let devices = get_devices_test(); + let process_rlimtis = get_process_rlimits_test(); let no_pivot = get_no_pivot_test(); tm.add_test_group(Box::new(cl)); @@ -138,6 +140,7 @@ fn main() -> Result<()> { tm.add_test_group(Box::new(sysctl)); tm.add_test_group(Box::new(scheduler)); tm.add_test_group(Box::new(devices)); + tm.add_test_group(Box::new(process_rlimtis)); tm.add_test_group(Box::new(no_pivot)); tm.add_test_group(Box::new(io_priority_test)); diff --git a/tests/contest/contest/src/tests/mod.rs b/tests/contest/contest/src/tests/mod.rs index 7a742d38..b3321015 100644 --- a/tests/contest/contest/src/tests/mod.rs +++ b/tests/contest/contest/src/tests/mod.rs @@ -11,6 +11,7 @@ pub mod linux_ns_itype; pub mod mounts_recursive; pub mod no_pivot; pub mod pidfile; +pub mod process_rlimits; pub mod readonly_paths; pub mod scheduler; pub mod seccomp; diff --git a/tests/contest/contest/src/tests/process_rlimits/mod.rs b/tests/contest/contest/src/tests/process_rlimits/mod.rs new file mode 100644 index 00000000..2e23c3cf --- /dev/null +++ b/tests/contest/contest/src/tests/process_rlimits/mod.rs @@ -0,0 +1,2 @@ +mod process_rlimits_test; +pub use process_rlimits_test::get_process_rlimits_test; diff --git a/tests/contest/contest/src/tests/process_rlimits/process_rlimits_test.rs b/tests/contest/contest/src/tests/process_rlimits/process_rlimits_test.rs new file mode 100644 index 00000000..7d5456d5 --- /dev/null +++ b/tests/contest/contest/src/tests/process_rlimits/process_rlimits_test.rs @@ -0,0 +1,67 @@ +use anyhow::{Context, Ok, Result}; +use oci_spec::runtime::{ + PosixRlimit, PosixRlimitBuilder, PosixRlimitType, ProcessBuilder, Spec, SpecBuilder, +}; +use test_framework::{test_result, Test, TestGroup, TestResult}; + +use crate::utils::test_inside_container; + +const GIGABYTES: u64 = 1024 * 1024 * 1024; + +fn create_rlimit( + rlimit_type: PosixRlimitType, + hard_val: u64, + soft_val: u64, +) -> Result { + let rlimit = PosixRlimitBuilder::default() + .typ(rlimit_type) + .hard(hard_val) + .soft(soft_val) + .build()?; + Ok(rlimit) +} + +#[allow(clippy::identity_op)] +fn create_spec() -> Result { + let spec = SpecBuilder::default() + .process( + ProcessBuilder::default() + .args(vec![ + "runtimetest".to_string(), + "process_rlimits".to_string(), + ]) + .rlimits(vec![ + create_rlimit(PosixRlimitType::RlimitAs, 2 * GIGABYTES, 1 * GIGABYTES).unwrap(), + create_rlimit(PosixRlimitType::RlimitCore, 4 * GIGABYTES, 3 * GIGABYTES) + .unwrap(), + create_rlimit(PosixRlimitType::RlimitData, 6 * GIGABYTES, 5 * GIGABYTES) + .unwrap(), + create_rlimit(PosixRlimitType::RlimitFsize, 8 * GIGABYTES, 7 * GIGABYTES) + .unwrap(), + create_rlimit(PosixRlimitType::RlimitStack, 10 * GIGABYTES, 9 * GIGABYTES) + .unwrap(), + create_rlimit(PosixRlimitType::RlimitCpu, 120, 60).unwrap(), + create_rlimit(PosixRlimitType::RlimitNofile, 4000, 3000).unwrap(), + ]) + .build() + .expect("error in creating process config"), + ) + .build() + .context("failed to build spec")?; + + Ok(spec) +} + +fn process_rlimits_test() -> TestResult { + let spec = test_result!(create_spec()); + test_inside_container(spec, &|_| Ok(())) +} + +pub fn get_process_rlimits_test() -> TestGroup { + let mut process_rlimits_test_group = TestGroup::new("process_rlimits"); + + let test = Test::new("process_rlimits_test", Box::new(process_rlimits_test)); + process_rlimits_test_group.add(vec![Box::new(test)]); + + process_rlimits_test_group +} diff --git a/tests/contest/runtimetest/src/main.rs b/tests/contest/runtimetest/src/main.rs index 486495a8..cbb96226 100644 --- a/tests/contest/runtimetest/src/main.rs +++ b/tests/contest/runtimetest/src/main.rs @@ -44,6 +44,7 @@ fn main() { "io_priority_class_be" => tests::test_io_priority_class(&spec, IoprioClassBe), "io_priority_class_idle" => tests::test_io_priority_class(&spec, IoprioClassIdle), "devices" => tests::validate_devices(&spec), + "process_rlimits" => tests::validate_process_rlimits(&spec), "no_pivot" => tests::validate_rootfs(), _ => eprintln!("error due to unexpected execute test name: {execute_test}"), } diff --git a/tests/contest/runtimetest/src/tests.rs b/tests/contest/runtimetest/src/tests.rs index dec34dee..57b9e779 100644 --- a/tests/contest/runtimetest/src/tests.rs +++ b/tests/contest/runtimetest/src/tests.rs @@ -6,10 +6,13 @@ use std::path::Path; use anyhow::{bail, Result}; use nix::errno::Errno; use nix::libc; +use nix::sys::resource::{getrlimit, Resource}; use nix::sys::utsname; use nix::unistd::getcwd; use oci_spec::runtime::IOPriorityClass::{self, IoprioClassBe, IoprioClassIdle, IoprioClassRt}; -use oci_spec::runtime::{LinuxDevice, LinuxDeviceType, LinuxSchedulerPolicy, Spec}; +use oci_spec::runtime::{ + LinuxDevice, LinuxDeviceType, LinuxSchedulerPolicy, PosixRlimit, PosixRlimitType, Spec, +}; use crate::utils::{self, test_read_access, test_write_access}; @@ -546,6 +549,53 @@ pub fn test_io_priority_class(spec: &Spec, io_priority_class: IOPriorityClass) { } } +pub fn validate_process_rlimits(spec: &Spec) { + let process = spec.process().as_ref().unwrap(); + let spec_rlimits: &Vec = process.rlimits().as_ref().unwrap(); + + for spec_rlimit in spec_rlimits.iter() { + let (soft_limit, hard_limit) = getrlimit(change_resource_type(spec_rlimit.typ())).unwrap(); + if spec_rlimit.hard() != hard_limit { + eprintln!( + "error type of {:?} hard rlimit expected {:?} , got {:?}", + spec_rlimit.typ(), + spec_rlimit.hard(), + hard_limit + ) + } + + if spec_rlimit.soft() != soft_limit { + eprintln!( + "error type of {:?} soft rlimit expected {:?} , got {:?}", + spec_rlimit.typ(), + spec_rlimit.soft(), + soft_limit + ) + } + } +} + +fn change_resource_type(resource_type: PosixRlimitType) -> Resource { + match resource_type { + PosixRlimitType::RlimitCpu => Resource::RLIMIT_CPU, + PosixRlimitType::RlimitFsize => Resource::RLIMIT_FSIZE, + PosixRlimitType::RlimitData => Resource::RLIMIT_DATA, + PosixRlimitType::RlimitStack => Resource::RLIMIT_STACK, + PosixRlimitType::RlimitCore => Resource::RLIMIT_CORE, + PosixRlimitType::RlimitRss => Resource::RLIMIT_RSS, + PosixRlimitType::RlimitNproc => Resource::RLIMIT_NPROC, + PosixRlimitType::RlimitNofile => Resource::RLIMIT_NOFILE, + PosixRlimitType::RlimitMemlock => Resource::RLIMIT_MEMLOCK, + PosixRlimitType::RlimitAs => Resource::RLIMIT_AS, + PosixRlimitType::RlimitLocks => Resource::RLIMIT_LOCKS, + PosixRlimitType::RlimitSigpending => Resource::RLIMIT_SIGPENDING, + PosixRlimitType::RlimitMsgqueue => Resource::RLIMIT_MSGQUEUE, + PosixRlimitType::RlimitNice => Resource::RLIMIT_NICE, + PosixRlimitType::RlimitRtprio => Resource::RLIMIT_RTPRIO, + PosixRlimitType::RlimitRttime => Resource::RLIMIT_RTTIME, + } +} + // the validate_rootfs function is used to validate the rootfs of the container is // as expected. This function is used in the no_pivot test to validate the rootfs pub fn validate_rootfs() {