From 6c3cd7f51d7db732da6d8346eeba277aebc7cf3f Mon Sep 17 00:00:00 2001 From: Yashodhan Joshi Date: Sat, 16 Oct 2021 10:55:40 +0530 Subject: [PATCH 1/3] Setup ns_itype test (WIP) --- youki_integration_test/Cargo.lock | 74 +++++++++++++++- youki_integration_test/Cargo.toml | 3 +- youki_integration_test/src/main.rs | 4 +- .../src/tests/linux_ns_itype/mod.rs | 2 + .../src/tests/linux_ns_itype/ns_itype_test.rs | 85 +++++++++++++++++++ youki_integration_test/src/tests/mod.rs | 1 + .../src/utils/test_utils.rs | 1 + 7 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 youki_integration_test/src/tests/linux_ns_itype/mod.rs create mode 100644 youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs diff --git a/youki_integration_test/Cargo.lock b/youki_integration_test/Cargo.lock index a4cf20865..ffdf82b0b 100644 --- a/youki_integration_test/Cargo.lock +++ b/youki_integration_test/Cargo.lock @@ -26,12 +26,31 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + [[package]] name = "clap" version = "3.0.0-beta.2" @@ -279,6 +298,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "ident_case" version = "1.0.1" @@ -332,11 +357,30 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "oci-spec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33c04af97b8e9e3155d9c530a1260e7e6c8d36a1e7353e54f3aa013d388a0c7" +checksum = "63f0f82a50257e72a6f13616dc093f3d0874294629bf8b7d0bc2a098e3db324f" dependencies = [ "derive_builder", "getset", @@ -396,6 +440,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "procfs" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e344cafeaeefe487300c361654bcfc85db3ac53619eeccced29f5ea18c4c70" +dependencies = [ + "bitflags", + "byteorder", + "chrono", + "flate2", + "hex", + "lazy_static", + "libc", +] + [[package]] name = "quote" version = "1.0.9" @@ -562,6 +621,16 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "unicode-segmentation" version = "1.8.0" @@ -656,6 +725,7 @@ dependencies = [ "flate2", "oci-spec", "once_cell", + "procfs", "rand", "serde", "serde_json", diff --git a/youki_integration_test/Cargo.toml b/youki_integration_test/Cargo.toml index b5469e5e7..2233bb968 100644 --- a/youki_integration_test/Cargo.toml +++ b/youki_integration_test/Cargo.toml @@ -18,6 +18,7 @@ members = [ ] [dependencies] +procfs = "0.10.1" uuid = "0.8" rand = "0.8.0" tar = "0.4" @@ -25,7 +26,7 @@ flate2 = "1.0" test_framework = { path = "./test_framework"} anyhow = "1.0" once_cell = "1.8.0" -oci-spec = "0.5.1" +oci-spec = "=0.5.2" which = "4.2.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" \ No newline at end of file diff --git a/youki_integration_test/src/main.rs b/youki_integration_test/src/main.rs index 695b0eb1d..5c092dcae 100644 --- a/youki_integration_test/src/main.rs +++ b/youki_integration_test/src/main.rs @@ -2,6 +2,7 @@ mod tests; mod utils; use crate::tests::lifecycle::{ContainerCreate, ContainerLifecycle}; +use crate::tests::linux_ns_itype::get_ns_itype_tests; use crate::tests::pidfile::get_pidfile_test; use crate::tests::tlb::get_tlb_test; use crate::utils::support::set_runtime_path; @@ -53,18 +54,19 @@ fn main() -> Result<()> { } }, } - let mut tm = TestManager::new(); let cl = ContainerLifecycle::new(); let cc = ContainerCreate::new(); let huge_tlb = get_tlb_test(); let pidfile = get_pidfile_test(); + let ns_itype = get_ns_itype_tests(); tm.add_test_group(&cl); tm.add_test_group(&cc); tm.add_test_group(&huge_tlb); tm.add_test_group(&pidfile); + tm.add_test_group(&ns_itype); if let Some(tests) = opts.tests { let tests_to_run = parse_tests(&tests); diff --git a/youki_integration_test/src/tests/linux_ns_itype/mod.rs b/youki_integration_test/src/tests/linux_ns_itype/mod.rs new file mode 100644 index 000000000..f2d29d71d --- /dev/null +++ b/youki_integration_test/src/tests/linux_ns_itype/mod.rs @@ -0,0 +1,2 @@ +mod ns_itype_test; +pub use ns_itype_test::get_ns_itype_tests; diff --git a/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs new file mode 100644 index 000000000..a8f44a904 --- /dev/null +++ b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs @@ -0,0 +1,85 @@ +use crate::utils::test_outside_container; +use anyhow::anyhow; +use oci_spec::runtime::LinuxBuilder; +use oci_spec::runtime::{Spec, SpecBuilder}; +use procfs::process::Process; +use test_framework::{Test, TestGroup, TestResult}; + +// I'm not sure we even need this +//const NAMESPACES: [&str; 5] = ["pid", "net", "ipc", "uts", "mnt"]; + +// get spec for the test +fn get_spec() -> Spec { + let r = SpecBuilder::default() + // We need to remove hostname to avoid test failures when not creating UTS namespace + .hostname("") + .linux( + LinuxBuilder::default() + .namespaces( + // the original test essientially skips all default namespaces, + // so we just put an empty vec here + vec![], + ) + // if these both are not empty, we cannot set a inherited + // mnt namespace, as these both require a private mnt namespace + // original test config has these empty by default, and has a function + // to add them if required + .masked_paths(vec![]) + .readonly_paths(vec![]) + .build() + .expect("could not build spec"), + ) + .build() + .unwrap(); + r +} + +fn get_test<'a>(test_name: &'static str) -> Test<'a> { + Test::new( + test_name, + Box::new(move || { + let host_proc = Process::myself().unwrap(); + let host_namespaces = match host_proc.namespaces() { + Ok(n) => n, + Err(e) => { + return TestResult::Err(anyhow!("Error in resolving host namespaces : {}", e)) + } + }; + // ! we don't have to actually store these separately + // ! as we are making all namespaces to be inherited, we can directly compare + // ! the hashmaps (?) + // let mut ns_inode = HashMap::new(); + // for ns in namespaces { + // ns_inode.insert(ns.ns_type.into_string().unwrap(), ns.identifier); + // } + + let spec = get_spec(); + test_outside_container(spec, &move |data| { + let pid = data.state.unwrap().pid.unwrap(); + let container_process = Process::new(pid).unwrap(); + let container_namespaces = container_process.namespaces().unwrap(); + + // for ns in namespaces { + // let inode = ns_inode + // .get(&ns.ns_type.clone().into_string().unwrap()) + // .unwrap(); + + // ! directly compare the hashmaps + if container_namespaces != host_namespaces { + return TestResult::Err(anyhow!( + "Error : namespaces are not correctly inherited" + )); + } + // } + TestResult::Ok + }) + }), + ) +} + +pub fn get_ns_itype_tests<'a>() -> TestGroup<'a> { + let mut tg = TestGroup::new("ns_itype"); + let tests: Vec<_> = vec![Box::new(get_test("ns_itype"))]; + tg.add(tests); + tg +} diff --git a/youki_integration_test/src/tests/mod.rs b/youki_integration_test/src/tests/mod.rs index 368f21f61..4d3ef2202 100644 --- a/youki_integration_test/src/tests/mod.rs +++ b/youki_integration_test/src/tests/mod.rs @@ -1,3 +1,4 @@ pub mod lifecycle; +pub mod linux_ns_itype; pub mod pidfile; pub mod tlb; diff --git a/youki_integration_test/src/utils/test_utils.rs b/youki_integration_test/src/utils/test_utils.rs index 339c18e1e..777e144ff 100644 --- a/youki_integration_test/src/utils/test_utils.rs +++ b/youki_integration_test/src/utils/test_utils.rs @@ -33,6 +33,7 @@ pub struct State { pub use_systemd: Option, } +#[derive(Debug)] pub struct ContainerData { pub id: String, pub state: Option, From 287f13bec918369d7f7074d8191edb19bc24820b Mon Sep 17 00:00:00 2001 From: Yashodhan Joshi Date: Sun, 17 Oct 2021 15:17:19 +0530 Subject: [PATCH 2/3] Add namespace inheritance test --- youki_integration_test/Cargo.lock | 7 ++-- youki_integration_test/Cargo.toml | 4 +-- .../src/tests/linux_ns_itype/ns_itype_test.rs | 36 +++++-------------- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/youki_integration_test/Cargo.lock b/youki_integration_test/Cargo.lock index ffdf82b0b..9e7b73ada 100644 --- a/youki_integration_test/Cargo.lock +++ b/youki_integration_test/Cargo.lock @@ -379,8 +379,7 @@ dependencies = [ [[package]] name = "oci-spec" version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63f0f82a50257e72a6f13616dc093f3d0874294629bf8b7d0bc2a098e3db324f" +source = "git+https://github.com/containers/oci-spec-rs?rev=3d5132a18c305be59d58187201429d8f0243b513#3d5132a18c305be59d58187201429d8f0243b513" dependencies = [ "derive_builder", "getset", @@ -442,9 +441,9 @@ dependencies = [ [[package]] name = "procfs" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e344cafeaeefe487300c361654bcfc85db3ac53619eeccced29f5ea18c4c70" +checksum = "3f2e7eea7c1d7beccbd5acc1e37ac844afccf176525674aad26ece3de1fc7733" dependencies = [ "bitflags", "byteorder", diff --git a/youki_integration_test/Cargo.toml b/youki_integration_test/Cargo.toml index 2233bb968..d2970a3a5 100644 --- a/youki_integration_test/Cargo.toml +++ b/youki_integration_test/Cargo.toml @@ -18,7 +18,7 @@ members = [ ] [dependencies] -procfs = "0.10.1" +procfs = "0.11.0" uuid = "0.8" rand = "0.8.0" tar = "0.4" @@ -26,7 +26,7 @@ flate2 = "1.0" test_framework = { path = "./test_framework"} anyhow = "1.0" once_cell = "1.8.0" -oci-spec = "=0.5.2" +oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "3d5132a18c305be59d58187201429d8f0243b513" } which = "4.2.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" \ No newline at end of file diff --git a/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs index a8f44a904..62702f5a3 100644 --- a/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs +++ b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs @@ -5,25 +5,18 @@ use oci_spec::runtime::{Spec, SpecBuilder}; use procfs::process::Process; use test_framework::{Test, TestGroup, TestResult}; -// I'm not sure we even need this -//const NAMESPACES: [&str; 5] = ["pid", "net", "ipc", "uts", "mnt"]; - // get spec for the test fn get_spec() -> Spec { - let r = SpecBuilder::default() - // We need to remove hostname to avoid test failures when not creating UTS namespace - .hostname("") + let mut r = SpecBuilder::default() .linux( LinuxBuilder::default() .namespaces( - // the original test essientially skips all default namespaces, - // so we just put an empty vec here + // we have to remove all namespaces, so we directly + // provide an empty vec here vec![], ) // if these both are not empty, we cannot set a inherited // mnt namespace, as these both require a private mnt namespace - // original test config has these empty by default, and has a function - // to add them if required .masked_paths(vec![]) .readonly_paths(vec![]) .build() @@ -31,6 +24,8 @@ fn get_spec() -> Spec { ) .build() .unwrap(); + // We need to remove hostname to avoid test failures when not creating UTS namespace + r.set_hostname(None); r } @@ -45,32 +40,19 @@ fn get_test<'a>(test_name: &'static str) -> Test<'a> { return TestResult::Err(anyhow!("Error in resolving host namespaces : {}", e)) } }; - // ! we don't have to actually store these separately - // ! as we are making all namespaces to be inherited, we can directly compare - // ! the hashmaps (?) - // let mut ns_inode = HashMap::new(); - // for ns in namespaces { - // ns_inode.insert(ns.ns_type.into_string().unwrap(), ns.identifier); - // } - let spec = get_spec(); test_outside_container(spec, &move |data| { - let pid = data.state.unwrap().pid.unwrap(); + let pid = match data.state { + Some(s) => s.pid.unwrap(), + None => return TestResult::Err(anyhow!("State command returned error")), + }; let container_process = Process::new(pid).unwrap(); let container_namespaces = container_process.namespaces().unwrap(); - - // for ns in namespaces { - // let inode = ns_inode - // .get(&ns.ns_type.clone().into_string().unwrap()) - // .unwrap(); - - // ! directly compare the hashmaps if container_namespaces != host_namespaces { return TestResult::Err(anyhow!( "Error : namespaces are not correctly inherited" )); } - // } TestResult::Ok }) }), From cf260fe8a662c0c479b8f3735abe235b4fa8125f Mon Sep 17 00:00:00 2001 From: Yashodhan Joshi Date: Wed, 20 Oct 2021 21:04:03 +0530 Subject: [PATCH 3/3] Add ns_itype test --- .../src/tests/linux_ns_itype/ns_itype_test.rs | 22 ++++++++++++------- .../src/tests/pidfile/pidfile_test.rs | 8 +++---- .../src/tests/tlb/tlb_test.rs | 16 ++++++++------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs index 62702f5a3..d2a7b4cdb 100644 --- a/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs +++ b/youki_integration_test/src/tests/linux_ns_itype/ns_itype_test.rs @@ -33,27 +33,33 @@ fn get_test<'a>(test_name: &'static str) -> Test<'a> { Test::new( test_name, Box::new(move || { - let host_proc = Process::myself().unwrap(); + let host_proc = Process::myself().expect("error in getting /proc/self"); let host_namespaces = match host_proc.namespaces() { Ok(n) => n, Err(e) => { - return TestResult::Err(anyhow!("Error in resolving host namespaces : {}", e)) + return TestResult::Failed(anyhow!( + "error in resolving host namespaces : {}", + e + )) } }; let spec = get_spec(); test_outside_container(spec, &move |data| { let pid = match data.state { Some(s) => s.pid.unwrap(), - None => return TestResult::Err(anyhow!("State command returned error")), + None => return TestResult::Failed(anyhow!("state command returned error")), }; - let container_process = Process::new(pid).unwrap(); - let container_namespaces = container_process.namespaces().unwrap(); + let container_process = + Process::new(pid).expect("error in getting /proc for container process"); + let container_namespaces = container_process + .namespaces() + .expect("error in getting namespaces of container process"); if container_namespaces != host_namespaces { - return TestResult::Err(anyhow!( - "Error : namespaces are not correctly inherited" + return TestResult::Failed(anyhow!( + "error : namespaces are not correctly inherited" )); } - TestResult::Ok + TestResult::Passed }) }), ) diff --git a/youki_integration_test/src/tests/pidfile/pidfile_test.rs b/youki_integration_test/src/tests/pidfile/pidfile_test.rs index 7892047ed..1d5197f81 100644 --- a/youki_integration_test/src/tests/pidfile/pidfile_test.rs +++ b/youki_integration_test/src/tests/pidfile/pidfile_test.rs @@ -46,7 +46,7 @@ fn test_pidfile() -> TestResult { if !err.is_empty() { cleanup(&container_id, &bundle); - return TestResult::Failed(anyhow!("Error in state : {}", err)); + return TestResult::Failed(anyhow!("error in state : {}", err)); } let state: State = serde_json::from_str(&out).unwrap(); @@ -54,7 +54,7 @@ fn test_pidfile() -> TestResult { if state.id != container_id.to_string() { cleanup(&container_id, &bundle); return TestResult::Failed(anyhow!( - "Error in state : ID not matched ,expected {} got {}", + "error in state : id not matched ,expected {} got {}", container_id, state.id )); @@ -63,7 +63,7 @@ fn test_pidfile() -> TestResult { if state.status != "created" { cleanup(&container_id, &bundle); return TestResult::Failed(anyhow!( - "Error in state : Status not matched ,expected 'created' got {}", + "error in state : status not matched ,expected 'created' got {}", state.status )); } @@ -78,7 +78,7 @@ fn test_pidfile() -> TestResult { if state.pid.unwrap() != pidfile { cleanup(&container_id, &bundle); return TestResult::Failed(anyhow!( - "Error : Pid not matched ,expected {} as per state, but got {} from pidfile instead", + "error : pid not matched ,expected {} as per state, but got {} from pidfile instead", state.pid.unwrap(), pidfile )); diff --git a/youki_integration_test/src/tests/tlb/tlb_test.rs b/youki_integration_test/src/tests/tlb/tlb_test.rs index be3e3047d..34509efb7 100644 --- a/youki_integration_test/src/tests/tlb/tlb_test.rs +++ b/youki_integration_test/src/tests/tlb/tlb_test.rs @@ -5,7 +5,7 @@ use oci_spec::runtime::LinuxBuilder; use oci_spec::runtime::{LinuxHugepageLimitBuilder, LinuxResourcesBuilder}; use oci_spec::runtime::{Spec, SpecBuilder}; use std::path::PathBuf; -use test_framework::{ConditionalTest, TestGroup, TestResult}; +use test_framework::{test_result, ConditionalTest, TestGroup, TestResult}; fn check_hugetlb() -> bool { PathBuf::from("/sys/fs/cgroup/hugetlb").exists() @@ -21,7 +21,7 @@ fn make_hugetlb_spec(page_size: &str, limit: i64) -> Spec { .page_size(page_size.to_owned()) .limit(limit) .build() - .expect("Could not build")]) + .expect("could not build")]) .build() .unwrap(), ) @@ -52,7 +52,7 @@ fn test_wrong_tlb() -> TestResult { } if res.success() { // The operation should not have succeeded as pagesize was not power of 2 - TestResult::Failed(anyhow!("Invalid page size of {} was allowed", page)) + TestResult::Failed(anyhow!("invalid page size of {} was allowed", page)) } else { TestResult::Passed } @@ -77,8 +77,10 @@ fn extract_page_size(dir_name: &str) -> String { fn get_tlb_sizes() -> Vec { let mut sizes = Vec::new(); - for hugetlb_entry in std::fs::read_dir("/sys/kernel/mm/hugepages").unwrap() { - let hugetlb_entry = hugetlb_entry.unwrap(); + for hugetlb_entry in std::fs::read_dir("/sys/kernel/mm/hugepages") + .expect("error in reading /sys/kernel/mm/hugepages") + { + let hugetlb_entry = hugetlb_entry.expect("error in reading /sys/kernel/mm/hugepages entry"); if !hugetlb_entry.path().is_dir() { continue; } @@ -100,7 +102,7 @@ fn validate_tlb(id: &str, size: &str, limit: i64) -> TestResult { TestResult::Passed } else { TestResult::Failed(anyhow!( - "Page limit not set correctly : for size {}, expected {}, got {}", + "page limit not set correctly : for size {}, expected {}, got {}", size, limit, val @@ -117,7 +119,7 @@ fn test_valid_tlb() -> TestResult { for size in tlb_sizes.iter() { let spec = make_hugetlb_spec(size, limit); let res = test_outside_container(spec, &|data| { - check_container_created(&data).unwrap(); + test_result!(check_container_created(&data)); let r = validate_tlb(&data.id, size, limit); if matches!(r, TestResult::Failed(_)) {