mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-18 19:59:45 +00:00
agent: refactor guest hooks
We have to execute some hooks both in host and guest. And in /libs/kata-sys-util/src/hooks.rs, the coomon operations are implemented. In this commit, we are going to refactor the code of guest hooks using code in /libs/kata-sys-util/src/hooks.rs. At the same time, we move function valid_env to kata-sys-util to make it usable by both agent and runtime. Fixes: #5857 Signed-off-by: Yushuo <y-shuo@linux.alibaba.com>
This commit is contained in:
parent
39394fa2a8
commit
85f9094f17
1
src/agent/Cargo.lock
generated
1
src/agent/Cargo.lock
generated
@ -1684,6 +1684,7 @@ dependencies = [
|
|||||||
"cgroups-rs",
|
"cgroups-rs",
|
||||||
"futures",
|
"futures",
|
||||||
"inotify",
|
"inotify",
|
||||||
|
"kata-sys-util",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"libseccomp",
|
"libseccomp",
|
||||||
|
@ -11,6 +11,7 @@ serde_json = "1.0.39"
|
|||||||
serde_derive = "1.0.91"
|
serde_derive = "1.0.91"
|
||||||
oci = { path = "../../libs/oci" }
|
oci = { path = "../../libs/oci" }
|
||||||
protocols = { path ="../../libs/protocols" }
|
protocols = { path ="../../libs/protocols" }
|
||||||
|
kata-sys-util = { path = "../../libs/kata-sys-util" }
|
||||||
caps = "0.5.0"
|
caps = "0.5.0"
|
||||||
nix = "0.24.2"
|
nix = "0.24.2"
|
||||||
scopeguard = "1.0.0"
|
scopeguard = "1.0.0"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use libc::pid_t;
|
use libc::pid_t;
|
||||||
use oci::{ContainerState, LinuxDevice, LinuxIdMapping};
|
use oci::{ContainerState, LinuxDevice, LinuxIdMapping};
|
||||||
use oci::{Hook, Linux, LinuxNamespace, LinuxResources, Spec};
|
use oci::{Linux, LinuxNamespace, LinuxResources, Spec};
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@ -66,6 +66,9 @@ use rlimit::{setrlimit, Resource, Rlim};
|
|||||||
use tokio::io::AsyncBufReadExt;
|
use tokio::io::AsyncBufReadExt;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use kata_sys_util::hooks::HookStates;
|
||||||
|
use kata_sys_util::validate::valid_env;
|
||||||
|
|
||||||
pub const EXEC_FIFO_FILENAME: &str = "exec.fifo";
|
pub const EXEC_FIFO_FILENAME: &str = "exec.fifo";
|
||||||
|
|
||||||
const INIT: &str = "INIT";
|
const INIT: &str = "INIT";
|
||||||
@ -1099,12 +1102,14 @@ impl BaseContainer for LinuxContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.hooks.is_some() {
|
// guest Poststop hook
|
||||||
info!(self.logger, "poststop");
|
// * should be executed after the container is deleted but before the delete operation returns
|
||||||
let hooks = spec.hooks.as_ref().unwrap();
|
// * the executable file is in agent namespace
|
||||||
for h in hooks.poststop.iter() {
|
// * should also be executed in agent namespace.
|
||||||
execute_hook(&self.logger, h, &st).await?;
|
if let Some(hooks) = spec.hooks.as_ref() {
|
||||||
}
|
info!(self.logger, "guest Poststop hook");
|
||||||
|
let mut hook_states = HookStates::new();
|
||||||
|
hook_states.execute_hooks(&hooks.poststop, Some(st))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.status.transition(ContainerState::Stopped);
|
self.status.transition(ContainerState::Stopped);
|
||||||
@ -1150,16 +1155,14 @@ impl BaseContainer for LinuxContainer {
|
|||||||
.ok_or_else(|| anyhow!("OCI spec was not found"))?;
|
.ok_or_else(|| anyhow!("OCI spec was not found"))?;
|
||||||
let st = self.oci_state()?;
|
let st = self.oci_state()?;
|
||||||
|
|
||||||
// run poststart hook
|
// guest Poststart hook
|
||||||
if spec.hooks.is_some() {
|
// * should be executed after the container is started but before the delete operation returns
|
||||||
info!(self.logger, "poststart hook");
|
// * the executable file is in agent namespace
|
||||||
let hooks = spec
|
// * should also be executed in agent namespace.
|
||||||
.hooks
|
if let Some(hooks) = spec.hooks.as_ref() {
|
||||||
.as_ref()
|
info!(self.logger, "guest Poststart hook");
|
||||||
.ok_or_else(|| anyhow!("OCI hooks were not found"))?;
|
let mut hook_states = HookStates::new();
|
||||||
for h in hooks.poststart.iter() {
|
hook_states.execute_hooks(&hooks.poststart, Some(st))?;
|
||||||
execute_hook(&self.logger, h, &st).await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unistd::close(fd)?;
|
unistd::close(fd)?;
|
||||||
@ -1380,13 +1383,14 @@ async fn join_namespaces(
|
|||||||
|
|
||||||
info!(logger, "get ready to run prestart hook!");
|
info!(logger, "get ready to run prestart hook!");
|
||||||
|
|
||||||
// run prestart hook
|
// guest Prestart hook
|
||||||
if spec.hooks.is_some() {
|
// * should be executed during the start operation, and before the container command is executed
|
||||||
info!(logger, "prestart hook");
|
// * the executable file is in agent namespace
|
||||||
let hooks = spec.hooks.as_ref().unwrap();
|
// * should also be executed in agent namespace.
|
||||||
for h in hooks.prestart.iter() {
|
if let Some(hooks) = spec.hooks.as_ref() {
|
||||||
execute_hook(&logger, h, st).await?;
|
info!(logger, "guest Prestart hook");
|
||||||
}
|
let mut hook_states = HookStates::new();
|
||||||
|
hook_states.execute_hooks(&hooks.prestart, Some(st.clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify child run prestart hooks completed
|
// notify child run prestart hooks completed
|
||||||
@ -1566,143 +1570,6 @@ fn set_sysctls(sysctls: &HashMap<String, String>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::process::Stdio;
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
|
|
||||||
pub async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> {
|
|
||||||
let logger = logger.new(o!("action" => "execute-hook"));
|
|
||||||
|
|
||||||
let binary = PathBuf::from(h.path.as_str());
|
|
||||||
let path = binary.canonicalize()?;
|
|
||||||
if !path.exists() {
|
|
||||||
return Err(anyhow!("Path {:?} does not exist", path));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut args = h.args.clone();
|
|
||||||
// the hook.args[0] is the hook binary name which shouldn't be included
|
|
||||||
// in the Command.args
|
|
||||||
if args.len() > 1 {
|
|
||||||
args.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// all invalid envs will be omitted, only valid envs will be passed to hook.
|
|
||||||
let env: HashMap<&str, &str> = h.env.iter().filter_map(|e| valid_env(e)).collect();
|
|
||||||
|
|
||||||
// Avoid the exit signal to be reaped by the global reaper.
|
|
||||||
let _wait_locker = WAIT_PID_LOCKER.lock().await;
|
|
||||||
let mut child = tokio::process::Command::new(path)
|
|
||||||
.args(args.iter())
|
|
||||||
.envs(env.iter())
|
|
||||||
.kill_on_drop(true)
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
// default timeout 10s
|
|
||||||
let mut timeout: u64 = 10;
|
|
||||||
|
|
||||||
// if timeout is set if hook, then use the specified value
|
|
||||||
if let Some(t) = h.timeout {
|
|
||||||
if t > 0 {
|
|
||||||
timeout = t as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let state = serde_json::to_string(st)?;
|
|
||||||
let path = h.path.clone();
|
|
||||||
|
|
||||||
let join_handle = tokio::spawn(async move {
|
|
||||||
if let Some(mut stdin) = child.stdin.take() {
|
|
||||||
match stdin.write_all(state.as_bytes()).await {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
info!(logger, "write to child stdin failed: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// read something from stdout and stderr for debug
|
|
||||||
if let Some(stdout) = child.stdout.as_mut() {
|
|
||||||
let mut out = String::new();
|
|
||||||
match stdout.read_to_string(&mut out).await {
|
|
||||||
Ok(_) => {
|
|
||||||
info!(logger, "child stdout: {}", out.as_str());
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
info!(logger, "read from child stdout failed: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut err = String::new();
|
|
||||||
if let Some(stderr) = child.stderr.as_mut() {
|
|
||||||
match stderr.read_to_string(&mut err).await {
|
|
||||||
Ok(_) => {
|
|
||||||
info!(logger, "child stderr: {}", err.as_str());
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
info!(logger, "read from child stderr failed: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match child.wait().await {
|
|
||||||
Ok(exit) => {
|
|
||||||
let code = exit
|
|
||||||
.code()
|
|
||||||
.ok_or_else(|| anyhow!("hook exit status has no status code"))?;
|
|
||||||
|
|
||||||
if code != 0 {
|
|
||||||
error!(
|
|
||||||
logger,
|
|
||||||
"hook {} exit status is {}, error message is {}", &path, code, err
|
|
||||||
);
|
|
||||||
return Err(anyhow!(nix::Error::UnknownErrno));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!(logger, "hook {} exit status is 0", &path);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => Err(anyhow!(
|
|
||||||
"wait child error: {} {}",
|
|
||||||
e,
|
|
||||||
e.raw_os_error().unwrap()
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
match tokio::time::timeout(Duration::new(timeout, 0), join_handle).await {
|
|
||||||
Ok(r) => r.unwrap(),
|
|
||||||
Err(_) => Err(anyhow!(nix::Error::ETIMEDOUT)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// valid environment variables according to https://doc.rust-lang.org/std/env/fn.set_var.html#panics
|
|
||||||
fn valid_env(e: &str) -> Option<(&str, &str)> {
|
|
||||||
// wherther key or value will contain NULL char.
|
|
||||||
if e.as_bytes().contains(&b'\0') {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v: Vec<&str> = e.splitn(2, '=').collect();
|
|
||||||
|
|
||||||
// key can't hold an `equal` sign, but value can
|
|
||||||
if v.len() != 2 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (key, value) = (v[0].trim(), v[1].trim());
|
|
||||||
|
|
||||||
// key can't be empty
|
|
||||||
if key.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some((key, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1713,7 +1580,6 @@ mod tests {
|
|||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use test_utils::skip_if_not_root;
|
use test_utils::skip_if_not_root;
|
||||||
use tokio::process::Command;
|
|
||||||
|
|
||||||
macro_rules! sl {
|
macro_rules! sl {
|
||||||
() => {
|
() => {
|
||||||
@ -1721,113 +1587,6 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn which(cmd: &str) -> String {
|
|
||||||
let output: std::process::Output = Command::new("which")
|
|
||||||
.arg(cmd)
|
|
||||||
.output()
|
|
||||||
.await
|
|
||||||
.expect("which command failed to run");
|
|
||||||
|
|
||||||
match String::from_utf8(output.stdout) {
|
|
||||||
Ok(v) => v.trim_end_matches('\n').to_string(),
|
|
||||||
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_execute_hook() {
|
|
||||||
let temp_file = "/tmp/test_execute_hook";
|
|
||||||
|
|
||||||
let touch = which("touch").await;
|
|
||||||
|
|
||||||
defer!(fs::remove_file(temp_file).unwrap(););
|
|
||||||
let invalid_str = vec![97, b'\0', 98];
|
|
||||||
let invalid_string = std::str::from_utf8(&invalid_str).unwrap();
|
|
||||||
let invalid_env = format!("{}=value", invalid_string);
|
|
||||||
|
|
||||||
execute_hook(
|
|
||||||
&slog_scope::logger(),
|
|
||||||
&Hook {
|
|
||||||
path: touch,
|
|
||||||
args: vec!["touch".to_string(), temp_file.to_string()],
|
|
||||||
env: vec![invalid_env],
|
|
||||||
timeout: Some(10),
|
|
||||||
},
|
|
||||||
&OCIState {
|
|
||||||
version: "1.2.3".to_string(),
|
|
||||||
id: "321".to_string(),
|
|
||||||
status: ContainerState::Running,
|
|
||||||
pid: 2,
|
|
||||||
bundle: "".to_string(),
|
|
||||||
annotations: Default::default(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(Path::new(&temp_file).exists(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_execute_hook_with_error() {
|
|
||||||
let ls = which("ls").await;
|
|
||||||
|
|
||||||
let res = execute_hook(
|
|
||||||
&slog_scope::logger(),
|
|
||||||
&Hook {
|
|
||||||
path: ls,
|
|
||||||
args: vec!["ls".to_string(), "/tmp/not-exist".to_string()],
|
|
||||||
env: vec![],
|
|
||||||
timeout: None,
|
|
||||||
},
|
|
||||||
&OCIState {
|
|
||||||
version: "1.2.3".to_string(),
|
|
||||||
id: "321".to_string(),
|
|
||||||
status: ContainerState::Running,
|
|
||||||
pid: 2,
|
|
||||||
bundle: "".to_string(),
|
|
||||||
annotations: Default::default(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let expected_err = nix::Error::UnknownErrno;
|
|
||||||
assert_eq!(
|
|
||||||
res.unwrap_err().downcast::<nix::Error>().unwrap(),
|
|
||||||
expected_err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_execute_hook_with_timeout() {
|
|
||||||
let sleep = which("sleep").await;
|
|
||||||
|
|
||||||
let res = execute_hook(
|
|
||||||
&slog_scope::logger(),
|
|
||||||
&Hook {
|
|
||||||
path: sleep,
|
|
||||||
args: vec!["sleep".to_string(), "2".to_string()],
|
|
||||||
env: vec![],
|
|
||||||
timeout: Some(1),
|
|
||||||
},
|
|
||||||
&OCIState {
|
|
||||||
version: "1.2.3".to_string(),
|
|
||||||
id: "321".to_string(),
|
|
||||||
status: ContainerState::Running,
|
|
||||||
pid: 2,
|
|
||||||
bundle: "".to_string(),
|
|
||||||
annotations: Default::default(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let expected_err = nix::Error::ETIMEDOUT;
|
|
||||||
assert_eq!(
|
|
||||||
res.unwrap_err().downcast::<nix::Error>().unwrap(),
|
|
||||||
expected_err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_status_transtition() {
|
fn test_status_transtition() {
|
||||||
let mut status = ContainerStatus::new();
|
let mut status = ContainerStatus::new();
|
||||||
@ -2167,49 +1926,4 @@ mod tests {
|
|||||||
let ret = do_init_child(std::io::stdin().as_raw_fd());
|
let ret = do_init_child(std::io::stdin().as_raw_fd());
|
||||||
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
assert!(ret.is_err(), "Expecting Err, Got {:?}", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_valid_env() {
|
|
||||||
let env = valid_env("a=b=c");
|
|
||||||
assert_eq!(Some(("a", "b=c")), env);
|
|
||||||
|
|
||||||
let env = valid_env("a=b");
|
|
||||||
assert_eq!(Some(("a", "b")), env);
|
|
||||||
let env = valid_env("a =b");
|
|
||||||
assert_eq!(Some(("a", "b")), env);
|
|
||||||
|
|
||||||
let env = valid_env(" a =b");
|
|
||||||
assert_eq!(Some(("a", "b")), env);
|
|
||||||
|
|
||||||
let env = valid_env("a= b");
|
|
||||||
assert_eq!(Some(("a", "b")), env);
|
|
||||||
|
|
||||||
let env = valid_env("a=b ");
|
|
||||||
assert_eq!(Some(("a", "b")), env);
|
|
||||||
let env = valid_env("a=b c ");
|
|
||||||
assert_eq!(Some(("a", "b c")), env);
|
|
||||||
|
|
||||||
let env = valid_env("=b");
|
|
||||||
assert_eq!(None, env);
|
|
||||||
|
|
||||||
let env = valid_env("a=");
|
|
||||||
assert_eq!(Some(("a", "")), env);
|
|
||||||
|
|
||||||
let env = valid_env("a==");
|
|
||||||
assert_eq!(Some(("a", "=")), env);
|
|
||||||
|
|
||||||
let env = valid_env("a");
|
|
||||||
assert_eq!(None, env);
|
|
||||||
|
|
||||||
let invalid_str = vec![97, b'\0', 98];
|
|
||||||
let invalid_string = std::str::from_utf8(&invalid_str).unwrap();
|
|
||||||
|
|
||||||
let invalid_env = format!("{}=value", invalid_string);
|
|
||||||
let env = valid_env(&invalid_env);
|
|
||||||
assert_eq!(None, env);
|
|
||||||
|
|
||||||
let invalid_env = format!("key={}", invalid_string);
|
|
||||||
let env = valid_env(&invalid_env);
|
|
||||||
assert_eq!(None, env);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
8
src/libs/Cargo.lock
generated
8
src/libs/Cargo.lock
generated
@ -40,6 +40,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -420,6 +426,8 @@ dependencies = [
|
|||||||
name = "kata-types"
|
name = "kata-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"base64",
|
||||||
"bitmask-enum",
|
"bitmask-enum",
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"glob",
|
"glob",
|
||||||
|
@ -13,6 +13,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use subprocess::{ExitStatus, Popen, PopenConfig, PopenError, Redirection};
|
use subprocess::{ExitStatus, Popen, PopenConfig, PopenError, Redirection};
|
||||||
|
|
||||||
|
use crate::validate::valid_env;
|
||||||
use crate::{eother, sl};
|
use crate::{eother, sl};
|
||||||
|
|
||||||
const DEFAULT_HOOK_TIMEOUT_SEC: i32 = 10;
|
const DEFAULT_HOOK_TIMEOUT_SEC: i32 = 10;
|
||||||
@ -206,9 +207,8 @@ impl<'a> HookExecutor<'a> {
|
|||||||
|
|
||||||
let mut envs: Vec<(OsString, OsString)> = Vec::new();
|
let mut envs: Vec<(OsString, OsString)> = Vec::new();
|
||||||
for e in hook.env.iter() {
|
for e in hook.env.iter() {
|
||||||
match e.split_once('=') {
|
if let Some((key, value)) = valid_env(e) {
|
||||||
Some((key, value)) => envs.push((OsString::from(key), OsString::from(value))),
|
envs.push((OsString::from(key), OsString::from(value)));
|
||||||
None => warn!(sl!(), "env {} of hook {:?} is invalid", e, hook),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,27 @@ pub fn verify_id(id: &str) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check and reserve valid environment variables
|
||||||
|
// invalid env var may cause panic, refer to https://doc.rust-lang.org/std/env/fn.set_var.html#panics
|
||||||
|
// key should not:
|
||||||
|
// * contain NUL character '\0'
|
||||||
|
// * contain ASCII equal sign '='
|
||||||
|
// * be empty
|
||||||
|
// value should not:
|
||||||
|
// * contain NUL character '\0'
|
||||||
|
pub fn valid_env(e: &str) -> Option<(&str, &str)> {
|
||||||
|
// split the env str by '=' at the first time to ensure there is no '=' in key,
|
||||||
|
// and also to ensure there is at least '=' in env str
|
||||||
|
if let Some((key, value)) = e.split_once('=') {
|
||||||
|
if !key.is_empty() && !key.as_bytes().contains(&b'\0') && !value.as_bytes().contains(&b'\0')
|
||||||
|
{
|
||||||
|
return Some((key.trim(), value.trim()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -264,4 +285,49 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_valid_env() {
|
||||||
|
let env = valid_env("a=b=c");
|
||||||
|
assert_eq!(Some(("a", "b=c")), env);
|
||||||
|
|
||||||
|
let env = valid_env("a=b");
|
||||||
|
assert_eq!(Some(("a", "b")), env);
|
||||||
|
let env = valid_env("a =b");
|
||||||
|
assert_eq!(Some(("a", "b")), env);
|
||||||
|
|
||||||
|
let env = valid_env(" a =b");
|
||||||
|
assert_eq!(Some(("a", "b")), env);
|
||||||
|
|
||||||
|
let env = valid_env("a= b");
|
||||||
|
assert_eq!(Some(("a", "b")), env);
|
||||||
|
|
||||||
|
let env = valid_env("a=b ");
|
||||||
|
assert_eq!(Some(("a", "b")), env);
|
||||||
|
let env = valid_env("a=b c ");
|
||||||
|
assert_eq!(Some(("a", "b c")), env);
|
||||||
|
|
||||||
|
let env = valid_env("=b");
|
||||||
|
assert_eq!(None, env);
|
||||||
|
|
||||||
|
let env = valid_env("a=");
|
||||||
|
assert_eq!(Some(("a", "")), env);
|
||||||
|
|
||||||
|
let env = valid_env("a==");
|
||||||
|
assert_eq!(Some(("a", "=")), env);
|
||||||
|
|
||||||
|
let env = valid_env("a");
|
||||||
|
assert_eq!(None, env);
|
||||||
|
|
||||||
|
let invalid_str = vec![97, b'\0', 98];
|
||||||
|
let invalid_string = std::str::from_utf8(&invalid_str).unwrap();
|
||||||
|
|
||||||
|
let invalid_env = format!("{}=value", invalid_string);
|
||||||
|
let env = valid_env(&invalid_env);
|
||||||
|
assert_eq!(None, env);
|
||||||
|
|
||||||
|
let invalid_env = format!("key={}", invalid_string);
|
||||||
|
let env = valid_env(&invalid_env);
|
||||||
|
assert_eq!(None, env);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
171
src/tools/runk/Cargo.lock
generated
171
src/tools/runk/Cargo.lock
generated
@ -139,6 +139,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
@ -151,6 +157,22 @@ version = "1.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitmask-enum"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd9e32d7420c85055e8107e5b2463c4eeefeaac18b52359fe9f9c08a18f342b2"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-unit"
|
||||||
|
version = "3.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "415301c9de11005d4b92193c0eb7ac7adc37e5a49e0ac9bed0a42343512744b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.4.3"
|
||||||
@ -274,6 +296,12 @@ dependencies = [
|
|||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "common-path"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "1.2.4"
|
version = "1.2.4"
|
||||||
@ -474,6 +502,17 @@ version = "2.5.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fail"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe5e43d0f78a42ad591453aedb1d7ae631ce7ee445c7643691055a9ed8d3b01c"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"rand 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@ -609,6 +648,17 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -620,6 +670,12 @@ dependencies = [
|
|||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@ -724,6 +780,50 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kata-sys-util"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"cgroups-rs",
|
||||||
|
"chrono",
|
||||||
|
"common-path",
|
||||||
|
"fail",
|
||||||
|
"kata-types",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"nix 0.24.2",
|
||||||
|
"oci",
|
||||||
|
"once_cell",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"serde_json",
|
||||||
|
"slog",
|
||||||
|
"slog-scope",
|
||||||
|
"subprocess",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kata-types"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"base64",
|
||||||
|
"bitmask-enum",
|
||||||
|
"byte-unit",
|
||||||
|
"glob",
|
||||||
|
"lazy_static",
|
||||||
|
"num_cpus",
|
||||||
|
"oci",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"slog",
|
||||||
|
"slog-scope",
|
||||||
|
"thiserror",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -744,6 +844,7 @@ dependencies = [
|
|||||||
"cgroups-rs",
|
"cgroups-rs",
|
||||||
"chrono",
|
"chrono",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
|
"kata-sys-util",
|
||||||
"libc",
|
"libc",
|
||||||
"logging",
|
"logging",
|
||||||
"nix 0.23.1",
|
"nix 0.23.1",
|
||||||
@ -1232,6 +1333,19 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.16",
|
||||||
|
"libc",
|
||||||
|
"rand_chacha 0.2.2",
|
||||||
|
"rand_core 0.5.1",
|
||||||
|
"rand_hc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@ -1239,8 +1353,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core",
|
"rand_core 0.6.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1250,7 +1374,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1259,7 +1392,16 @@ version = "0.6.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.7",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1277,7 +1419,7 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.7",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -1368,6 +1510,7 @@ dependencies = [
|
|||||||
"cgroups-rs",
|
"cgroups-rs",
|
||||||
"futures",
|
"futures",
|
||||||
"inotify",
|
"inotify",
|
||||||
|
"kata-sys-util",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"libseccomp",
|
"libseccomp",
|
||||||
@ -1557,6 +1700,16 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subprocess"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.91"
|
version = "1.0.91"
|
||||||
@ -1834,6 +1987,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.0+wasi-snapshot-preview1"
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
@ -2010,7 +2169,7 @@ dependencies = [
|
|||||||
"nix 0.23.1",
|
"nix 0.23.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ordered-stream",
|
"ordered-stream",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"sha1",
|
"sha1",
|
||||||
|
@ -9,6 +9,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
rustjail = { path = "../../../agent/rustjail", features = ["standard-oci-runtime"] }
|
rustjail = { path = "../../../agent/rustjail", features = ["standard-oci-runtime"] }
|
||||||
oci = { path = "../../../libs/oci" }
|
oci = { path = "../../../libs/oci" }
|
||||||
|
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"
|
||||||
libc = "0.2.108"
|
libc = "0.2.108"
|
||||||
|
@ -19,18 +19,20 @@ use oci::{ContainerState, State as OCIState};
|
|||||||
use procfs;
|
use procfs;
|
||||||
use rustjail::cgroups::fs::Manager as CgroupManager;
|
use rustjail::cgroups::fs::Manager as CgroupManager;
|
||||||
use rustjail::{
|
use rustjail::{
|
||||||
container::{self, BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME},
|
container::{BaseContainer, LinuxContainer, EXEC_FIFO_FILENAME},
|
||||||
process::{Process, ProcessOperations},
|
process::{Process, ProcessOperations},
|
||||||
specconv::CreateOpts,
|
specconv::CreateOpts,
|
||||||
};
|
};
|
||||||
use scopeguard::defer;
|
use scopeguard::defer;
|
||||||
use slog::{debug, Logger};
|
use slog::{debug, info, Logger};
|
||||||
use std::{
|
use std::{
|
||||||
env::current_dir,
|
env::current_dir,
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use kata_sys_util::hooks::HookStates;
|
||||||
|
|
||||||
pub const CONFIG_FILE_NAME: &str = "config.json";
|
pub const CONFIG_FILE_NAME: &str = "config.json";
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
@ -139,14 +141,10 @@ impl Container {
|
|||||||
annotations: spec.annotations.clone(),
|
annotations: spec.annotations.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if spec.hooks.is_some() {
|
if let Some(hooks) = spec.hooks.as_ref() {
|
||||||
let hooks = spec
|
info!(&logger, "Poststop Hooks");
|
||||||
.hooks
|
let mut poststop_hookstates = HookStates::new();
|
||||||
.as_ref()
|
poststop_hookstates.execute_hooks(&hooks.poststop, Some(oci_state.clone()))?;
|
||||||
.ok_or_else(|| anyhow!("hooks config was not present"))?;
|
|
||||||
for h in hooks.poststop.iter() {
|
|
||||||
container::execute_hook(logger, h, &oci_state).await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match oci_state.status {
|
match oci_state.status {
|
||||||
|
Loading…
Reference in New Issue
Block a user