mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-18 17:33:02 +00:00
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:
parent
b3eab5ffea
commit
bf813f85f2
1650
src/tools/runk/Cargo.lock
generated
1650
src/tools/runk/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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"] }
|
||||||
|
@ -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" }
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user