diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 4169635395..29a3b915f7 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -129,6 +129,9 @@ impl agentService { // Add the root partition to the device cgroup to prevent access update_device_cgroup(&mut oci)?; + // Append guest hooks + append_guest_hooks(&s, &mut oci); + // write spec to bundle path, hooks might // read ocispec let olddir = setup_bundle(&cid, &mut oci)?; @@ -1084,6 +1087,15 @@ impl protocols::agent_ttrpc::AgentService for agentService { s.hostname = req.hostname.clone(); s.running = true; + if !req.guest_hook_path.is_empty() { + if let Err(e) = s.add_hooks(&req.guest_hook_path) { + error!( + sl!(), + "add guest hook {} failed: {:?}", req.guest_hook_path, e + ); + } + } + if req.sandbox_id.len() > 0 { s.id = req.sandbox_id.clone(); } @@ -1523,6 +1535,18 @@ fn update_container_namespaces( Ok(()) } +fn append_guest_hooks(s: &Sandbox, oci: &mut Spec) { + if s.hooks.is_none() { + return; + } + let guest_hooks = s.hooks.as_ref().unwrap(); + let mut hooks = oci.hooks.take().unwrap_or_default(); + hooks.prestart.append(&mut guest_hooks.prestart.clone()); + hooks.poststart.append(&mut guest_hooks.poststart.clone()); + hooks.poststop.append(&mut guest_hooks.poststop.clone()); + oci.hooks = Some(hooks); +} + // Check is the container process installed the // handler for specific signal. fn is_signal_handled(pid: pid_t, signum: u32) -> bool { diff --git a/src/agent/src/sandbox.rs b/src/agent/src/sandbox.rs index 5d7a993042..7f5000d961 100644 --- a/src/agent/src/sandbox.rs +++ b/src/agent/src/sandbox.rs @@ -11,7 +11,7 @@ use crate::namespace::NSTYPEPID; use crate::network::Network; use libc::pid_t; use netlink::{RtnlHandle, NETLINK_ROUTE}; -use oci::LinuxNamespace; +use oci::{Hook, Hooks}; use protocols::agent::OnlineCPUMemRequest; use regex::Regex; use rustjail::cgroups; @@ -22,6 +22,8 @@ use rustjail::process::Process; use slog::Logger; use std::collections::HashMap; use std::fs; +use std::os::unix::fs::PermissionsExt; +use std::path::Path; use std::sync::mpsc::Sender; #[derive(Debug)] @@ -42,6 +44,7 @@ pub struct Sandbox { pub no_pivot_root: bool, pub sender: Option>, pub rtnl: Option, + pub hooks: Option, } impl Sandbox { @@ -66,6 +69,7 @@ impl Sandbox { no_pivot_root: fs_type.eq(TYPEROOTFS), sender: None, rtnl: Some(RtnlHandle::new(NETLINK_ROUTE, 0).unwrap()), + hooks: None, }) } @@ -261,6 +265,57 @@ impl Sandbox { Ok(()) } + + pub fn add_hooks(&mut self, dir: &str) -> Result<()> { + let mut hooks = Hooks::default(); + if let Ok(hook) = self.find_hooks(dir, "prestart") { + hooks.prestart = hook; + } + if let Ok(hook) = self.find_hooks(dir, "poststart") { + hooks.poststart = hook; + } + if let Ok(hook) = self.find_hooks(dir, "poststop") { + hooks.poststop = hook; + } + self.hooks = Some(hooks); + Ok(()) + } + + fn find_hooks(&self, hook_path: &str, hook_type: &str) -> Result> { + let mut hooks = Vec::new(); + for entry in fs::read_dir(Path::new(hook_path).join(hook_type))? { + let entry = entry?; + // Reject non-file, symlinks and non-executable files + if !entry.file_type()?.is_file() + || entry.file_type()?.is_symlink() + || entry.metadata()?.permissions().mode() & 0o777 & 0o111 == 0 + { + continue; + } + + let name = entry.file_name(); + let hook = Hook { + path: Path::new(hook_path) + .join(hook_type) + .join(&name) + .to_str() + .unwrap() + .to_owned(), + args: vec![name.to_str().unwrap().to_owned(), hook_type.to_owned()], + ..Default::default() + }; + info!( + self.logger, + "found {} hook {:?} mode {:o}", + hook_type, + hook, + entry.metadata()?.permissions().mode() + ); + hooks.push(hook); + } + + Ok(hooks) + } } fn online_resources(logger: &Logger, path: &str, pattern: &str, num: i32) -> Result {