runk: Align oci spec with oci-spec-rs

Utilized oci-spec-rs to align OCI Spec structures
and data representations in runk with the OCI Spec.

Fixes #9766

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
This commit is contained in:
Alex Lyn 2024-07-16 16:16:20 +08:00
parent b3eab5ffea
commit bf813f85f2
11 changed files with 1207 additions and 780 deletions

1650
src/tools/runk/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,8 @@ edition = "2018"
[dependencies] [dependencies]
libcontainer = { path = "./libcontainer" } libcontainer = { path = "./libcontainer" }
rustjail = { path = "../../agent/rustjail", features = ["standard-oci-runtime"] } rustjail = { path = "../../agent/rustjail", features = ["standard-oci-runtime"] }
oci = { path = "../../libs/oci" } runtime-spec = { path = "../../libs/runtime-spec" }
oci-spec = { version = "0.6.8", features = ["runtime"] }
logging = { path = "../../libs/logging" } logging = { path = "../../libs/logging" }
liboci-cli = "0.0.4" liboci-cli = "0.0.4"
clap = { version = "3.0.6", features = ["derive", "cargo"] } clap = { version = "3.0.6", features = ["derive", "cargo"] }

View File

@ -8,7 +8,8 @@ edition = "2018"
[dependencies] [dependencies]
rustjail = { path = "../../../agent/rustjail", features = ["standard-oci-runtime"] } rustjail = { path = "../../../agent/rustjail", features = ["standard-oci-runtime"] }
oci = { path = "../../../libs/oci" } runtime-spec = { path = "../../../libs/runtime-spec" }
oci-spec = { version = "0.6.8", features = ["runtime"] }
kata-sys-util = { path = "../../../libs/kata-sys-util" } kata-sys-util = { path = "../../../libs/kata-sys-util" }
logging = { path = "../../../libs/logging" } logging = { path = "../../../libs/logging" }
derive_builder = "0.10.2" derive_builder = "0.10.2"
@ -26,3 +27,4 @@ procfs = "0.14.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3.3.0" tempfile = "3.3.0"
test-utils = { path = "../../../libs/test-utils" } test-utils = { path = "../../../libs/test-utils" }
protocols = { path ="../../../libs/protocols" }

View File

@ -8,7 +8,9 @@ use crate::status::Status;
use crate::utils::validate_spec; use crate::utils::validate_spec;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_builder::Builder; use derive_builder::Builder;
use oci::{ContainerState, Process as OCIProcess, Spec}; use oci::{Process as OCIProcess, Spec};
use oci_spec::runtime as oci;
use runtime_spec::ContainerState;
use rustjail::container::update_namespaces; use rustjail::container::update_namespaces;
use slog::{debug, Logger}; use slog::{debug, Logger};
use std::fs::File; use std::fs::File;
@ -105,8 +107,8 @@ impl ActivatedContainer {
// If with --process, load process from file. // If with --process, load process from file.
// Otherwise, update process with args and other options. // Otherwise, update process with args and other options.
if let Some(process_path) = self.process.as_ref() { if let Some(process_path) = self.process.as_ref() {
spec.process = Some(Self::get_process(process_path)?); spec.set_process(Some(Self::get_process(process_path)?));
} else if let Some(process) = spec.process.as_mut() { } else if let Some(process) = spec.process_mut().as_mut() {
self.update_process(process)?; self.update_process(process)?;
} else { } else {
return Err(anyhow!("process is empty in spec")); return Err(anyhow!("process is empty in spec"));
@ -118,15 +120,15 @@ impl ActivatedContainer {
/// Update process with args and other options. /// Update process with args and other options.
fn update_process(&self, process: &mut OCIProcess) -> Result<()> { fn update_process(&self, process: &mut OCIProcess) -> Result<()> {
process.args = self.args.clone(); process.set_args(Some(self.args.clone()));
process.no_new_privileges = self.no_new_privs; process.set_no_new_privileges(Some(self.no_new_privs));
process.terminal = self.tty; process.set_terminal(Some(self.tty));
if let Some(cwd) = self.cwd.as_ref() { if let Some(cwd) = self.cwd.as_ref() {
process.cwd = cwd.as_path().display().to_string(); process.set_cwd(cwd.as_path().to_path_buf());
}
if let Some(process_env) = process.env_mut() {
process_env.extend(self.env.iter().map(|kv| format!("{}={}", kv.0, kv.1)));
} }
process
.env
.extend(self.env.iter().map(|kv| format!("{}={}", kv.0, kv.1)));
Ok(()) Ok(())
} }
@ -143,7 +145,7 @@ mod tests {
use crate::status::Status; use crate::status::Status;
use crate::utils::test_utils::*; use crate::utils::test_utils::*;
use nix::unistd::getpid; use nix::unistd::getpid;
use oci::{Linux, LinuxNamespace, User}; use oci_spec::runtime::{LinuxBuilder, LinuxNamespaceBuilder, ProcessBuilder, User};
use rustjail::container::TYPETONAME; use rustjail::container::TYPETONAME;
use scopeguard::defer; use scopeguard::defer;
use slog::o; use slog::o;
@ -193,11 +195,10 @@ mod tests {
let pid = getpid().as_raw(); let pid = getpid().as_raw();
let mut spec = create_dummy_spec(); let mut spec = create_dummy_spec();
spec.root.as_mut().unwrap().path = bundle_dir spec.root_mut()
.path() .as_mut()
.join(TEST_ROOTFS_PATH) .unwrap()
.to_string_lossy() .set_path(bundle_dir.path().join(TEST_ROOTFS_PATH));
.to_string();
let status = create_custom_dummy_status(&id, pid, root.path(), &spec); let status = create_custom_dummy_status(&id, pid, root.path(), &spec);
status.save().unwrap(); status.save().unwrap();
@ -223,36 +224,39 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
let linux = Linux { let linux = LinuxBuilder::default()
namespaces: TYPETONAME .namespaces(
TYPETONAME
.iter() .iter()
.filter(|&(_, &name)| name != "user") .filter(|&(_, &name)| name != "user")
.map(|ns| LinuxNamespace { .map(|ns| {
r#type: ns.0.to_string(), LinuxNamespaceBuilder::default()
path: format!("/proc/{}/ns/{}", pid, ns.1), .typ(ns.0.clone())
.path(PathBuf::from(&format!("/proc/{}/ns/{}", pid, ns.1)))
.build()
.unwrap()
}) })
.collect(), .collect::<Vec<_>>(),
..Default::default() )
}; .build()
spec.linux = Some(linux); .unwrap();
spec.process = Some(OCIProcess {
terminal: result.tty, spec.set_linux(Some(linux));
console_size: None, let process = ProcessBuilder::default()
user: User::default(), .terminal(result.tty)
args: result.args.clone(), .user(User::default())
cwd: result.cwd.clone().unwrap().to_string_lossy().to_string(), .args(result.args.clone())
env: vec![ .cwd(result.cwd.clone().unwrap().to_string_lossy().to_string())
.env(vec![
"PATH=/bin:/usr/bin".to_string(), "PATH=/bin:/usr/bin".to_string(),
"K1=V1".to_string(), "K1=V1".to_string(),
"K2=V2".to_string(), "K2=V2".to_string(),
], ])
capabilities: None, .no_new_privileges(result.no_new_privs)
rlimits: Vec::new(), .build()
no_new_privileges: result.no_new_privs, .unwrap();
apparmor_profile: "".to_string(),
oom_score_adj: None, spec.set_process(Some(process));
selinux_label: "".to_string(),
});
let launcher = result.clone().create_launcher(&logger).unwrap(); let launcher = result.clone().create_launcher(&logger).unwrap();
assert!(!launcher.init); assert!(!launcher.init);
assert_eq!(launcher.runner.config.spec.unwrap(), spec); assert_eq!(launcher.runner.config.spec.unwrap(), spec);
@ -269,11 +273,11 @@ mod tests {
skip_if_not_root!(); skip_if_not_root!();
let bundle_dir = tempdir().unwrap(); let bundle_dir = tempdir().unwrap();
let process_file = bundle_dir.path().join(TEST_PROCESS_FILE_NAME); let process_file = bundle_dir.path().join(TEST_PROCESS_FILE_NAME);
let process_template = OCIProcess {
args: vec!["sleep".to_string(), "10".to_string()], let mut process_template = OCIProcess::default();
cwd: "/".to_string(), process_template.set_args(Some(vec!["sleep".to_string(), "10".to_string()]));
..Default::default() process_template.set_cwd(PathBuf::from("/"));
};
let file = File::create(process_file.clone()).unwrap(); let file = File::create(process_file.clone()).unwrap();
serde_json::to_writer(&file, &process_template).unwrap(); serde_json::to_writer(&file, &process_template).unwrap();
@ -284,11 +288,10 @@ mod tests {
let id = "test_activated_container_create_with_process".to_string(); let id = "test_activated_container_create_with_process".to_string();
let pid = getpid().as_raw(); let pid = getpid().as_raw();
let mut spec = create_dummy_spec(); let mut spec = create_dummy_spec();
spec.root.as_mut().unwrap().path = bundle_dir spec.root_mut()
.path() .as_mut()
.join(TEST_ROOTFS_PATH) .unwrap()
.to_string_lossy() .set_path(bundle_dir.path().join(TEST_ROOTFS_PATH));
.to_string();
create_activated_dirs(root.path(), &id, bundle_dir.path()); create_activated_dirs(root.path(), &id, bundle_dir.path());
let status = create_custom_dummy_status(&id, pid, root.path(), &spec); let status = create_custom_dummy_status(&id, pid, root.path(), &spec);
@ -300,7 +303,7 @@ mod tests {
let launcher = ActivatedContainerBuilder::default() let launcher = ActivatedContainerBuilder::default()
.id(id) .id(id)
.root(root.into_path()) .root(root.into_path())
.console_socket(None) .console_socket(Some(PathBuf::from(TEST_CONSOLE_SOCKET_PATH)))
.pid_file(None) .pid_file(None)
.tty(true) .tty(true)
.cwd(Some(PathBuf::from(TEST_BUNDLE_PATH))) .cwd(Some(PathBuf::from(TEST_BUNDLE_PATH)))
@ -319,7 +322,14 @@ mod tests {
assert!(!launcher.init); assert!(!launcher.init);
assert_eq!( assert_eq!(
launcher.runner.config.spec.unwrap().process.unwrap(), launcher
.runner
.config
.spec
.unwrap()
.process()
.clone()
.unwrap(),
process_template process_template
); );
} }

View File

@ -15,8 +15,8 @@ use nix::{
sys::signal::SIGKILL, sys::signal::SIGKILL,
unistd::{chdir, unlink, Pid}, unistd::{chdir, unlink, Pid},
}; };
use oci::{ContainerState, State as OCIState};
use procfs; use procfs;
use runtime_spec::{ContainerState, State as OCIState};
use rustjail::cgroups::fs::Manager as CgroupManager; use rustjail::cgroups::fs::Manager as CgroupManager;
use rustjail::{ use rustjail::{
container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME}, container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME},
@ -59,15 +59,18 @@ impl Container {
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("spec config was not present"))?; .ok_or_else(|| anyhow!("spec config was not present"))?;
let linux = spec let linux = spec
.linux .linux()
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("linux config was not present"))?; .ok_or_else(|| anyhow!("linux config was not present"))?;
let cpath = if linux.cgroups_path.is_empty() { let cpath = if linux.cgroups_path().is_none() {
id.to_string() id.to_string()
} else { } else {
linux linux
.cgroups_path .cgroups_path()
.clone() .clone()
.unwrap_or_default()
.display()
.to_string()
.trim_start_matches('/') .trim_start_matches('/')
.to_string() .to_string()
}; };
@ -142,13 +145,16 @@ impl Container {
.to_str() .to_str()
.ok_or_else(|| anyhow!("invalid bundle path"))? .ok_or_else(|| anyhow!("invalid bundle path"))?
.to_string(), .to_string(),
annotations: spec.annotations.clone(), annotations: spec.annotations().clone().unwrap_or_default(),
}; };
if let Some(hooks) = spec.hooks.as_ref() { if let Some(hooks) = spec.hooks().as_ref() {
info!(&logger, "Poststop Hooks"); info!(&logger, "Poststop Hooks");
let mut poststop_hookstates = HookStates::new(); let mut poststop_hookstates = HookStates::new();
poststop_hookstates.execute_hooks(&hooks.poststop, Some(oci_state.clone()))?; poststop_hookstates.execute_hooks(
&hooks.poststop().clone().unwrap_or_default(),
Some(oci_state.clone()),
)?;
} }
match oci_state.status { match oci_state.status {
@ -281,12 +287,10 @@ impl ContainerLauncher {
/// Generate rustjail::Process from OCI::Process /// Generate rustjail::Process from OCI::Process
fn get_process(&self, logger: &Logger) -> Result<Process> { fn get_process(&self, logger: &Logger) -> Result<Process> {
let spec = self.runner.config.spec.as_ref().unwrap(); let spec = self.runner.config.spec.as_ref().unwrap();
if spec.process.is_some() { if spec.process().is_some() {
Ok(Process::new( Ok(Process::new(
logger, logger,
spec.process spec.process().as_ref().unwrap(),
.as_ref()
.ok_or_else(|| anyhow!("process config was not present in the spec file"))?,
// rustjail::LinuxContainer use the exec_id to identify processes in a container, // rustjail::LinuxContainer use the exec_id to identify processes in a container,
// so we can get the spawned process by ctr.get_process(exec_id) later. // so we can get the spawned process by ctr.get_process(exec_id) later.
// Since LinuxContainer is temporarily created to spawn one process in each runk invocation, // Since LinuxContainer is temporarily created to spawn one process in each runk invocation,

View File

@ -6,7 +6,7 @@
use crate::container::{load_linux_container, Container, ContainerLauncher}; use crate::container::{load_linux_container, Container, ContainerLauncher};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_builder::Builder; use derive_builder::Builder;
use oci::ContainerState; use runtime_spec::ContainerState;
use slog::{debug, Logger}; use slog::{debug, Logger};
use std::path::PathBuf; use std::path::PathBuf;
@ -113,11 +113,10 @@ mod tests {
let pid = getpid().as_raw(); let pid = getpid().as_raw();
let mut spec = create_dummy_spec(); let mut spec = create_dummy_spec();
spec.root.as_mut().unwrap().path = bundle_dir spec.root_mut()
.path() .as_mut()
.join(TEST_ROOTFS_PATH) .unwrap()
.to_string_lossy() .set_path(bundle_dir.path().join(TEST_ROOTFS_PATH));
.to_string();
let status = create_custom_dummy_status(&id, pid, root.path(), &spec); let status = create_custom_dummy_status(&id, pid, root.path(), &spec);
status.save().unwrap(); status.save().unwrap();

View File

@ -8,7 +8,7 @@ use crate::status::Status;
use crate::utils::{canonicalize_spec_root, validate_spec}; use crate::utils::{canonicalize_spec_root, validate_spec};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_builder::Builder; use derive_builder::Builder;
use oci::Spec; use oci_spec::runtime::Spec;
use rustjail::specconv::CreateOpts; use rustjail::specconv::CreateOpts;
use slog::{debug, Logger}; use slog::{debug, Logger};
use std::path::PathBuf; use std::path::PathBuf;
@ -91,11 +91,11 @@ mod tests {
use super::*; use super::*;
use crate::container::CONFIG_FILE_NAME; use crate::container::CONFIG_FILE_NAME;
use crate::utils::test_utils::*; use crate::utils::test_utils::*;
use oci_spec::runtime::Process;
use slog::o; use slog::o;
use std::fs::{create_dir, File}; use std::fs::{create_dir, File};
use std::path::Path; use std::path::Path;
use tempfile::tempdir; use tempfile::tempdir;
use test_utils::skip_if_not_root;
#[test] #[test]
fn test_init_container_validate() { fn test_init_container_validate() {
@ -126,11 +126,10 @@ mod tests {
let file = File::create(config_file).unwrap(); let file = File::create(config_file).unwrap();
serde_json::to_writer(&file, &spec).unwrap(); serde_json::to_writer(&file, &spec).unwrap();
spec.root.as_mut().unwrap().path = bundle_dir spec.root_mut()
.path() .as_mut()
.join(TEST_ROOTFS_PATH) .unwrap()
.to_string_lossy() .set_path(bundle_dir.path().join(TEST_ROOTFS_PATH));
.to_string();
let test_data = TestContainerData { let test_data = TestContainerData {
// Since tests are executed concurrently, container_id must be unique in tests with cgroup. // Since tests are executed concurrently, container_id must be unique in tests with cgroup.
// Or the cgroup directory may be removed by other tests in advance. // Or the cgroup directory may be removed by other tests in advance.
@ -179,11 +178,12 @@ mod tests {
let bundle_dir = tempdir().unwrap(); let bundle_dir = tempdir().unwrap();
let config_file = bundle_dir.path().join(CONFIG_FILE_NAME); let config_file = bundle_dir.path().join(CONFIG_FILE_NAME);
let mut spec = oci::Spec { let mut spec = Spec::default();
process: Some(oci::Process::default()), spec.set_process(Some(Process::default()));
..Default::default() spec.process_mut()
}; .as_mut()
spec.process.as_mut().unwrap().terminal = true; .unwrap()
.set_terminal(Some(true));
let file = File::create(config_file).unwrap(); let file = File::create(config_file).unwrap();
serde_json::to_writer(&file, &spec).unwrap(); serde_json::to_writer(&file, &spec).unwrap();

View File

@ -14,8 +14,8 @@ use nix::{
sys::{signal::kill, stat::Mode}, sys::{signal::kill, stat::Mode},
unistd::Pid, unistd::Pid,
}; };
use oci::{ContainerState, State as OCIState};
use procfs::process::ProcState; use procfs::process::ProcState;
use runtime_spec::{ContainerState, State as OCIState};
use rustjail::{cgroups::fs::Manager as CgroupManager, specconv::CreateOpts}; use rustjail::{cgroups::fs::Manager as CgroupManager, specconv::CreateOpts};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
@ -60,10 +60,10 @@ impl Status {
.clone() .clone()
.spec .spec
.ok_or_else(|| anyhow!("spec config was not present"))? .ok_or_else(|| anyhow!("spec config was not present"))?
.root .root()
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("root config was not present in the spec"))? .ok_or_else(|| anyhow!("root config was not present in the spec"))?
.path .path()
.clone(); .clone();
Ok(Self { Ok(Self {
@ -72,7 +72,7 @@ impl Status {
pid: oci_state.pid, pid: oci_state.pid,
root: root.to_path_buf(), root: root.to_path_buf(),
bundle: bundle.to_path_buf(), bundle: bundle.to_path_buf(),
rootfs, rootfs: rootfs.display().to_string(),
process_start_time, process_start_time,
created, created,
cgroup_manager: cgroup_mg, cgroup_manager: cgroup_mg,
@ -187,7 +187,7 @@ mod tests {
use ::test_utils::skip_if_not_root; use ::test_utils::skip_if_not_root;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use nix::unistd::getpid; use nix::unistd::getpid;
use oci::ContainerState; use runtime_spec::ContainerState;
use rustjail::cgroups::fs::Manager as CgroupManager; use rustjail::cgroups::fs::Manager as CgroupManager;
use scopeguard::defer; use scopeguard::defer;
use std::path::Path; use std::path::Path;

View File

@ -5,7 +5,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use nix::sys::stat::Mode; use nix::sys::stat::Mode;
use oci::{Process, Spec}; use oci_spec::runtime::{Process, Spec};
use std::{ use std::{
fs::{DirBuilder, File}, fs::{DirBuilder, File},
io::{prelude::*, BufReader}, io::{prelude::*, BufReader},
@ -37,28 +37,24 @@ pub fn create_dir_with_mode<P: AsRef<Path>>(path: P, mode: Mode, recursive: bool
/// If root in spec is a relative path, make it absolute. /// If root in spec is a relative path, make it absolute.
pub fn canonicalize_spec_root(spec: &mut Spec, bundle_canon: &Path) -> Result<()> { pub fn canonicalize_spec_root(spec: &mut Spec, bundle_canon: &Path) -> Result<()> {
let spec_root = spec let spec_root = spec
.root .root_mut()
.as_mut() .as_mut()
.ok_or_else(|| anyhow!("root config was not present in the spec file"))?; .ok_or_else(|| anyhow!("root config was not present in the spec file"))?;
let rootfs_path = Path::new(&spec_root.path); let rootfs_path = &spec_root.path();
if !rootfs_path.is_absolute() { if !rootfs_path.is_absolute() {
spec_root.path = bundle_canon let bundle_canon_path = bundle_canon.join(rootfs_path).canonicalize()?;
.join(rootfs_path) spec_root.set_path(bundle_canon_path);
.canonicalize()?
.to_str()
.map(|s| s.to_string())
.ok_or_else(|| anyhow!("failed to convert a rootfs path into a canonical path"))?;
} }
Ok(()) Ok(())
} }
/// Check whether spec is valid. Now runk only support detach mode. /// Check whether spec is valid. Now runk only support detach mode.
pub fn validate_spec(spec: &Spec, console_socket: &Option<PathBuf>) -> Result<()> { pub fn validate_spec(spec: &Spec, console_socket: &Option<PathBuf>) -> Result<()> {
validate_process_spec(&spec.process)?; validate_process_spec(spec.process())?;
if let Some(process) = spec.process.as_ref() { if let Some(process) = spec.process().as_ref() {
// runk always launches containers with detached mode, so users have to // runk always launches containers with detached mode, so users have to
// use a console socket with run or create operation when a terminal is used. // use a console socket with run or create operation when a terminal is used.
if process.terminal && console_socket.is_none() { if process.terminal().is_some() && console_socket.is_none() {
return Err(anyhow!( return Err(anyhow!(
"cannot allocate a pseudo-TTY without setting a console socket" "cannot allocate a pseudo-TTY without setting a console socket"
)); ));
@ -72,14 +68,14 @@ pub fn validate_process_spec(process: &Option<Process>) -> Result<()> {
let process = process let process = process
.as_ref() .as_ref()
.ok_or_else(|| anyhow!("process property must not be empty"))?; .ok_or_else(|| anyhow!("process property must not be empty"))?;
if process.cwd.is_empty() { if process.cwd().as_os_str().is_empty() {
return Err(anyhow!("cwd property must not be empty")); return Err(anyhow!("cwd property must not be empty"));
} }
let cwd = Path::new(process.cwd.as_str()); let cwd = process.cwd();
if !cwd.is_absolute() { if !cwd.is_absolute() {
return Err(anyhow!("cwd must be an absolute path")); return Err(anyhow!("cwd must be an absolute path"));
} }
if process.args.is_empty() { if process.args().is_none() {
return Err(anyhow!("args must not be empty")); return Err(anyhow!("args must not be empty"));
} }
Ok(()) Ok(())
@ -91,7 +87,9 @@ pub(crate) mod test_utils {
use crate::status::Status; use crate::status::Status;
use chrono::DateTime; use chrono::DateTime;
use nix::unistd::getpid; use nix::unistd::getpid;
use oci::{ContainerState, LinuxNamespace, Process, Root, Spec, State as OCIState}; use oci::{LinuxBuilder, LinuxNamespaceBuilder, Process, Root, Spec};
use oci_spec::runtime as oci;
use runtime_spec::{ContainerState, State as OCIState};
use rustjail::{ use rustjail::{
cgroups::fs::Manager as CgroupManager, container::TYPETONAME, specconv::CreateOpts, cgroups::fs::Manager as CgroupManager, container::TYPETONAME, specconv::CreateOpts,
}; };
@ -129,40 +127,46 @@ pub(crate) mod test_utils {
} }
pub fn create_dummy_spec() -> Spec { pub fn create_dummy_spec() -> Spec {
let linux = oci::Linux { let linux = LinuxBuilder::default()
namespaces: TYPETONAME .namespaces(
TYPETONAME
.iter() .iter()
.filter(|&(_, &name)| name != "user") .filter(|&(_, &name)| name != "user")
.map(|ns| LinuxNamespace { .map(|ns| {
r#type: ns.0.to_string(), LinuxNamespaceBuilder::default()
path: "".to_string(), .typ(ns.0.clone())
.path(PathBuf::from(""))
.build()
.unwrap()
}) })
.collect(), .collect::<Vec<_>>(),
..Default::default() )
}; .build()
Spec { .unwrap();
version: TEST_OCI_SPEC_VERSION.to_string(),
process: Some(Process { let mut process = Process::default();
args: vec!["sleep".to_string(), "10".to_string()], process.set_args(Some(vec!["sleep".to_string(), "10".to_string()]));
env: vec!["PATH=/bin:/usr/bin".to_string()], process.set_env(Some(vec!["PATH=/bin:/usr/bin".to_string()]));
cwd: "/".to_string(), process.set_cwd(PathBuf::from("/"));
..Default::default()
}), let mut root = Root::default();
hostname: TEST_HOST_NAME.to_string(), root.set_path(PathBuf::from(TEST_ROOTFS_PATH));
root: Some(Root { root.set_readonly(Some(false));
path: TEST_ROOTFS_PATH.to_string(),
readonly: false, let mut spec = Spec::default();
}), spec.set_version(TEST_OCI_SPEC_VERSION.to_string());
linux: Some(linux), spec.set_process(Some(process));
..Default::default() spec.set_hostname(Some(TEST_HOST_NAME.to_string()));
} spec.set_root(Some(root));
spec.set_linux(Some(linux));
spec
} }
pub fn create_dummy_opts() -> CreateOpts { pub fn create_dummy_opts() -> CreateOpts {
let spec = Spec { let mut spec = Spec::default();
root: Some(Root::default()), spec.set_root(Some(Root::default()));
..Default::default()
};
CreateOpts { CreateOpts {
cgroup_name: "".to_string(), cgroup_name: "".to_string(),
use_systemd_cgroup: false, use_systemd_cgroup: false,
@ -219,7 +223,7 @@ pub(crate) mod test_utils {
.unwrap() .unwrap()
.starttime; .starttime;
Status { Status {
oci_version: spec.version.clone(), oci_version: spec.version().clone(),
id: id.to_string(), id: id.to_string(),
pid, pid,
root: root.to_path_buf(), root: root.to_path_buf(),
@ -247,13 +251,13 @@ pub(crate) mod test_utils {
#[test] #[test]
fn test_canonicalize_spec_root() { fn test_canonicalize_spec_root() {
let gen_spec = |p: &str| -> Spec { let gen_spec = |p: &str| -> Spec {
Spec { let mut root = Root::default();
root: Some(Root { root.set_path(PathBuf::from(p));
path: p.to_string(), root.set_readonly(Some(false));
readonly: false,
}), let mut spec = Spec::default();
..Default::default() spec.set_root(Some(root));
} spec
}; };
let rootfs_name = TEST_ROOTFS_PATH; let rootfs_name = TEST_ROOTFS_PATH;
@ -263,29 +267,28 @@ pub(crate) mod test_utils {
create_dir_all(abs_root.clone()).unwrap(); create_dir_all(abs_root.clone()).unwrap();
let mut spec = gen_spec(abs_root.to_str().unwrap()); let mut spec = gen_spec(abs_root.to_str().unwrap());
assert!(canonicalize_spec_root(&mut spec, bundle_dir).is_ok()); assert!(canonicalize_spec_root(&mut spec, bundle_dir).is_ok());
assert_eq!(spec.root.unwrap().path, abs_root.to_str().unwrap()); assert_eq!(spec.root_mut().clone().unwrap().path(), &abs_root);
let mut spec = gen_spec(rootfs_name); let mut spec = gen_spec(rootfs_name);
assert!(canonicalize_spec_root(&mut spec, bundle_dir).is_ok()); assert!(canonicalize_spec_root(&mut spec, bundle_dir).is_ok());
assert_eq!(spec.root.unwrap().path, abs_root.to_str().unwrap()); assert_eq!(spec.root().clone().unwrap().path(), &abs_root);
} }
#[test] #[test]
pub fn test_validate_process_spec() { pub fn test_validate_process_spec() {
let valid_process = Process { let mut valid_process = Process::default();
args: vec!["test".to_string()], valid_process.set_args(Some(vec!["test".to_string()]));
cwd: "/".to_string(), valid_process.set_cwd(PathBuf::from("/"));
..Default::default()
};
assert!(validate_process_spec(&None).is_err()); assert!(validate_process_spec(&None).is_err());
assert!(validate_process_spec(&Some(valid_process.clone())).is_ok()); assert!(validate_process_spec(&Some(valid_process.clone())).is_ok());
let mut invalid_process = valid_process.clone(); let mut invalid_process = valid_process.clone();
invalid_process.args = vec![]; invalid_process.set_args(None);
assert!(validate_process_spec(&Some(invalid_process)).is_err()); assert!(validate_process_spec(&Some(invalid_process)).is_err());
let mut invalid_process = valid_process.clone(); let mut invalid_process = valid_process.clone();
invalid_process.cwd = "".to_string(); invalid_process.set_cwd(PathBuf::from(""));
assert!(validate_process_spec(&Some(invalid_process)).is_err()); assert!(validate_process_spec(&Some(invalid_process)).is_err());
let mut invalid_process = valid_process; let mut invalid_process = valid_process;
invalid_process.cwd = "test/".to_string(); invalid_process.set_cwd(PathBuf::from("test/"));
assert!(validate_process_spec(&Some(invalid_process)).is_err()); assert!(validate_process_spec(&Some(invalid_process)).is_err());
} }
} }

View File

@ -7,7 +7,7 @@ use super::state::get_container_state_name;
use anyhow::Result; use anyhow::Result;
use libcontainer::container::Container; use libcontainer::container::Container;
use liboci_cli::List; use liboci_cli::List;
use oci::ContainerState; use runtime_spec::ContainerState;
use slog::{info, Logger}; use slog::{info, Logger};
use std::fmt::Write as _; use std::fmt::Write as _;
use std::{fs, os::unix::prelude::MetadataExt, path::Path}; use std::{fs, os::unix::prelude::MetadataExt, path::Path};

View File

@ -7,7 +7,7 @@ use anyhow::Result;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use libcontainer::{container::Container, status::Status}; use libcontainer::{container::Container, status::Status};
use liboci_cli::State; use liboci_cli::State;
use oci::ContainerState; use runtime_spec::ContainerState;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use slog::{info, Logger}; use slog::{info, Logger};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -62,7 +62,7 @@ pub fn get_container_state_name(state: ContainerState) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use oci::ContainerState; use runtime_spec::ContainerState;
#[test] #[test]
fn test_get_container_state_name() { fn test_get_container_state_name() {