runtime-rs: add oci hook support

According to the runtime OCI Spec, there can be some hook
operations in the lifecycle of the container. In these hook
operations, the runtime can execute some commands. There are different
points in time in the container lifecycle  and different hook types
can be executed.

In this commit, we are now supporting 4 types of hooks(same in
runtime-go): Prestart hook, CreateRuntime hook, Poststart hook and
Poststop hook.

Fixes: #5787

Signed-off-by: Yushuo <y-shuo@linux.alibaba.com>
This commit is contained in:
Yushuo 2022-11-18 19:25:09 +08:00
parent ecac3a9e10
commit 875f2db528
22 changed files with 192 additions and 8 deletions

View File

@ -154,12 +154,15 @@ fn hook_grpc_to_oci(h: &[grpcHook]) -> Vec<oci::Hook> {
fn hooks_grpc_to_oci(h: &grpc::Hooks) -> oci::Hooks { fn hooks_grpc_to_oci(h: &grpc::Hooks) -> oci::Hooks {
let prestart = hook_grpc_to_oci(h.Prestart.as_ref()); let prestart = hook_grpc_to_oci(h.Prestart.as_ref());
let create_runtime = hook_grpc_to_oci(h.CreateRuntime.as_ref());
let poststart = hook_grpc_to_oci(h.Poststart.as_ref()); let poststart = hook_grpc_to_oci(h.Poststart.as_ref());
let poststop = hook_grpc_to_oci(h.Poststop.as_ref()); let poststop = hook_grpc_to_oci(h.Poststop.as_ref());
oci::Hooks { oci::Hooks {
prestart, prestart,
create_runtime,
poststart, poststart,
poststop, poststop,
} }
@ -860,6 +863,7 @@ mod tests {
env: Vec::from([String::from("env1"), String::from("env2")]), env: Vec::from([String::from("env1"), String::from("env2")]),
timeout: Some(10), timeout: Some(10),
}]), }]),
..Default::default()
}, },
}, },
TestData { TestData {
@ -908,6 +912,7 @@ mod tests {
env: Vec::from([String::from("env1"), String::from("env2")]), env: Vec::from([String::from("env1"), String::from("env2")]),
timeout: Some(10), timeout: Some(10),
}]), }]),
..Default::default()
}, },
}, },
]; ];

View File

@ -50,6 +50,8 @@ pub struct InstanceInfo {
pub vmm_version: String, pub vmm_version: String,
/// The pid of the current VMM process. /// The pid of the current VMM process.
pub pid: u32, pub pid: u32,
/// The tid of the current VMM master thread.
pub master_tid: u32,
/// The state of async actions. /// The state of async actions.
pub async_state: AsyncState, pub async_state: AsyncState,
/// List of tids of vcpu threads (vcpu index, tid) /// List of tids of vcpu threads (vcpu index, tid)
@ -66,6 +68,7 @@ impl InstanceInfo {
state: InstanceState::Uninitialized, state: InstanceState::Uninitialized,
vmm_version, vmm_version,
pid: std::process::id(), pid: std::process::id(),
master_tid: 0,
async_state: AsyncState::Uninitialized, async_state: AsyncState::Uninitialized,
tids: Vec::new(), tids: Vec::new(),
last_instance_downtime: 0, last_instance_downtime: 0,
@ -80,6 +83,7 @@ impl Default for InstanceInfo {
state: InstanceState::Uninitialized, state: InstanceState::Uninitialized,
vmm_version: env!("CARGO_PKG_VERSION").to_string(), vmm_version: env!("CARGO_PKG_VERSION").to_string(),
pid: std::process::id(), pid: std::process::id(),
master_tid: 0,
async_state: AsyncState::Uninitialized, async_state: AsyncState::Uninitialized,
tids: Vec::new(), tids: Vec::new(),
last_instance_downtime: 0, last_instance_downtime: 0,

View File

@ -193,6 +193,8 @@ pub struct Hooks {
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub prestart: Vec<Hook>, pub prestart: Vec<Hook>,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub create_runtime: Vec<Hook>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub poststart: Vec<Hook>, pub poststart: Vec<Hook>,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub poststop: Vec<Hook>, pub poststop: Vec<Hook>,
@ -1401,6 +1403,7 @@ mod tests {
env: vec![], env: vec![],
timeout: None, timeout: None,
}], }],
..Default::default()
}), }),
annotations: [ annotations: [
("com.example.key1".to_string(), "value1".to_string()), ("com.example.key1".to_string(), "value1".to_string()),

View File

@ -166,6 +166,9 @@ message Hooks {
// Poststop is a list of hooks to be run after the container process exits. // Poststop is a list of hooks to be run after the container process exits.
repeated Hook Poststop = 3 [(gogoproto.nullable) = false]; repeated Hook Poststop = 3 [(gogoproto.nullable) = false];
// Createruntime is a list of hooks to be run during the creation of runtime(sandbox).
repeated Hook CreateRuntime = 4 [(gogoproto.nullable) = false];
} }
message Hook { message Hook {

View File

@ -294,6 +294,7 @@ impl From<oci::Hooks> for crate::oci::Hooks {
fn from(from: Hooks) -> Self { fn from(from: Hooks) -> Self {
crate::oci::Hooks { crate::oci::Hooks {
Prestart: from_vec(from.prestart), Prestart: from_vec(from.prestart),
CreateRuntime: from_vec(from.create_runtime),
Poststart: from_vec(from.poststart), Poststart: from_vec(from.poststart),
Poststop: from_vec(from.poststop), Poststop: from_vec(from.poststop),
unknown_fields: Default::default(), unknown_fields: Default::default(),
@ -974,6 +975,10 @@ impl From<crate::oci::Hooks> for oci::Hooks {
for hook in from.take_Prestart().to_vec() { for hook in from.take_Prestart().to_vec() {
prestart.push(hook.into()) prestart.push(hook.into())
} }
let mut create_runtime = Vec::new();
for hook in from.take_CreateRuntime().to_vec() {
create_runtime.push(hook.into())
}
let mut poststart = Vec::new(); let mut poststart = Vec::new();
for hook in from.take_Poststart().to_vec() { for hook in from.take_Poststart().to_vec() {
poststart.push(hook.into()); poststart.push(hook.into());
@ -984,6 +989,7 @@ impl From<crate::oci::Hooks> for oci::Hooks {
} }
oci::Hooks { oci::Hooks {
prestart, prestart,
create_runtime,
poststart, poststart,
poststop, poststop,
} }

View File

@ -1703,6 +1703,8 @@ dependencies = [
"bitflags", "bitflags",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"memoffset 0.6.5",
"pin-utils",
] ]
[[package]] [[package]]
@ -2428,12 +2430,15 @@ dependencies = [
"hyper", "hyper",
"hyperlocal", "hyperlocal",
"hypervisor", "hypervisor",
"kata-sys-util",
"kata-types", "kata-types",
"lazy_static", "lazy_static",
"linux_container", "linux_container",
"logging", "logging",
"nix 0.25.1",
"oci", "oci",
"persist", "persist",
"serde_json",
"shim-interface", "shim-interface",
"slog", "slog",
"slog-scope", "slog-scope",

View File

@ -472,6 +472,10 @@ impl CloudHypervisorInner {
Ok(Vec::<u32>::new()) Ok(Vec::<u32>::new())
} }
pub(crate) async fn get_vmm_master_tid(&self) -> Result<u32> {
todo!()
}
pub(crate) async fn check(&self) -> Result<()> { pub(crate) async fn check(&self) -> Result<()> {
Ok(()) Ok(())
} }

View File

@ -118,6 +118,11 @@ impl Hypervisor for CloudHypervisor {
inner.get_pids().await inner.get_pids().await
} }
async fn get_vmm_master_tid(&self) -> Result<u32> {
let inner = self.inner.read().await;
inner.get_vmm_master_tid().await
}
async fn check(&self) -> Result<()> { async fn check(&self) -> Result<()> {
let inner = self.inner.read().await; let inner = self.inner.read().await;
inner.check().await inner.check().await

View File

@ -127,6 +127,11 @@ impl DragonballInner {
Ok(Vec::from_iter(pids.into_iter())) Ok(Vec::from_iter(pids.into_iter()))
} }
pub(crate) async fn get_vmm_master_tid(&self) -> Result<u32> {
let master_tid = self.vmm_instance.get_vmm_master_tid();
Ok(master_tid)
}
pub(crate) async fn check(&self) -> Result<()> { pub(crate) async fn check(&self) -> Result<()> {
Ok(()) Ok(())
} }

View File

@ -117,6 +117,11 @@ impl Hypervisor for Dragonball {
inner.get_pids().await inner.get_pids().await
} }
async fn get_vmm_master_tid(&self) -> Result<u32> {
let inner = self.inner.read().await;
inner.get_vmm_master_tid().await
}
async fn check(&self) -> Result<()> { async fn check(&self) -> Result<()> {
let inner = self.inner.read().await; let inner = self.inner.read().await;
inner.check().await inner.check().await

View File

@ -75,6 +75,12 @@ impl VmmInstance {
share_info_lock.write().unwrap().id = String::from(id); share_info_lock.write().unwrap().id = String::from(id);
} }
pub fn get_vmm_master_tid(&self) -> u32 {
let info = self.vmm_shared_info.clone();
let result = info.read().unwrap().master_tid;
result
}
pub fn get_vcpu_tids(&self) -> Vec<(u8, u32)> { pub fn get_vcpu_tids(&self) -> Vec<(u8, u32)> {
let info = self.vmm_shared_info.clone(); let info = self.vmm_shared_info.clone();
let result = info.read().unwrap().tids.clone(); let result = info.read().unwrap().tids.clone();
@ -103,6 +109,7 @@ impl VmmInstance {
Some(kvm.into_raw_fd()), Some(kvm.into_raw_fd()),
) )
.expect("Failed to start vmm"); .expect("Failed to start vmm");
let vmm_shared_info = self.get_shared_info();
self.vmm_thread = Some( self.vmm_thread = Some(
thread::Builder::new() thread::Builder::new()
@ -110,6 +117,9 @@ impl VmmInstance {
.spawn(move || { .spawn(move || {
|| -> Result<i32> { || -> Result<i32> {
debug!(sl!(), "run vmm thread start"); debug!(sl!(), "run vmm thread start");
let cur_tid = nix::unistd::gettid().as_raw() as u32;
vmm_shared_info.write().unwrap().master_tid = cur_tid;
if let Some(netns_path) = netns { if let Some(netns_path) = netns {
info!(sl!(), "set netns for vmm master {}", &netns_path); info!(sl!(), "set netns for vmm master {}", &netns_path);
let netns_fd = File::open(&netns_path) let netns_fd = File::open(&netns_path)

View File

@ -87,6 +87,7 @@ pub trait Hypervisor: Send + Sync {
async fn hypervisor_config(&self) -> HypervisorConfig; async fn hypervisor_config(&self) -> HypervisorConfig;
async fn get_thread_ids(&self) -> Result<VcpuThreadIds>; async fn get_thread_ids(&self) -> Result<VcpuThreadIds>;
async fn get_pids(&self) -> Result<Vec<u32>>; async fn get_pids(&self) -> Result<Vec<u32>>;
async fn get_vmm_master_tid(&self) -> Result<u32>;
async fn cleanup(&self) -> Result<()>; async fn cleanup(&self) -> Result<()>;
async fn check(&self) -> Result<()>; async fn check(&self) -> Result<()>;
async fn get_jailer_root(&self) -> Result<String>; async fn get_jailer_root(&self) -> Result<String>;

View File

@ -89,6 +89,11 @@ impl QemuInner {
todo!() todo!()
} }
pub(crate) async fn get_vmm_master_tid(&self) -> Result<u32> {
info!(sl!(), "QemuInner::get_vmm_master_tid()");
todo!()
}
pub(crate) async fn cleanup(&self) -> Result<()> { pub(crate) async fn cleanup(&self) -> Result<()> {
info!(sl!(), "QemuInner::cleanup()"); info!(sl!(), "QemuInner::cleanup()");
todo!() todo!()

View File

@ -103,6 +103,11 @@ impl Hypervisor for Qemu {
inner.get_thread_ids().await inner.get_thread_ids().await
} }
async fn get_vmm_master_tid(&self) -> Result<u32> {
let inner = self.inner.read().await;
inner.get_vmm_master_tid().await
}
async fn cleanup(&self) -> Result<()> { async fn cleanup(&self) -> Result<()> {
let inner = self.inner.read().await; let inner = self.inner.read().await;
inner.cleanup().await inner.cleanup().await

View File

@ -13,9 +13,12 @@ slog-scope = "4.4.0"
tokio = { version = "1.8.0", features = ["rt-multi-thread"] } tokio = { version = "1.8.0", features = ["rt-multi-thread"] }
hyper = { version = "0.14.20", features = ["stream", "server", "http1"] } hyper = { version = "0.14.20", features = ["stream", "server", "http1"] }
hyperlocal = "0.8" hyperlocal = "0.8"
serde_json = "1.0.88"
nix = "0.25.0"
common = { path = "./common" } common = { path = "./common" }
kata-types = { path = "../../../libs/kata-types" } kata-types = { path = "../../../libs/kata-types" }
kata-sys-util = { path = "../../../libs/kata-sys-util" }
logging = { path = "../../../libs/logging"} logging = { path = "../../../libs/logging"}
oci = { path = "../../../libs/oci" } oci = { path = "../../../libs/oci" }
shim-interface = { path = "../../../libs/shim-interface" } shim-interface = { path = "../../../libs/shim-interface" }

View File

@ -26,3 +26,4 @@ agent = { path = "../../agent" }
kata-sys-util = { path = "../../../../libs/kata-sys-util" } kata-sys-util = { path = "../../../../libs/kata-sys-util" }
kata-types = { path = "../../../../libs/kata-types" } kata-types = { path = "../../../../libs/kata-types" }
oci = { path = "../../../../libs/oci" } oci = { path = "../../../../libs/oci" }

View File

@ -17,6 +17,9 @@ pub trait Sandbox: Send + Sync {
// agent function // agent function
async fn agent_sock(&self) -> Result<String>; async fn agent_sock(&self) -> Result<String>;
// hypervisor function
async fn get_vmm_master_tid(&self) -> Result<u32>;
// utils // utils
async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>>; async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>>;
async fn get_iptables(&self, is_ipv6: bool) -> Result<Vec<u8>>; async fn get_iptables(&self, is_ipv6: bool) -> Result<Vec<u8>>;

View File

@ -18,6 +18,8 @@ use hypervisor::Param;
use kata_types::{ use kata_types::{
annotations::Annotation, config::default::DEFAULT_GUEST_DNS_FILE, config::TomlConfig, annotations::Annotation, config::default::DEFAULT_GUEST_DNS_FILE, config::TomlConfig,
}; };
use kata_sys_util::hooks::HookStates;
#[cfg(feature = "linux")] #[cfg(feature = "linux")]
use linux_container::LinuxContainer; use linux_container::LinuxContainer;
use persist::sandbox_persist::Persist; use persist::sandbox_persist::Persist;
@ -81,7 +83,12 @@ impl RuntimeHandlerManagerInner {
Ok(()) Ok(())
} }
async fn try_init(&mut self, spec: &oci::Spec, options: &Option<Vec<u8>>) -> Result<()> { async fn try_init(
&mut self,
spec: &oci::Spec,
state: &oci::State,
options: &Option<Vec<u8>>,
) -> Result<()> {
// return if runtime instance has init // return if runtime instance has init
if self.runtime_instance.is_some() { if self.runtime_instance.is_some() {
return Ok(()); return Ok(());
@ -125,6 +132,35 @@ impl RuntimeHandlerManagerInner {
.await .await
.context("init runtime handler")?; .context("init runtime handler")?;
let mut st = state.clone();
if let Some(runtime_instance) = self.runtime_instance.clone() {
let vmm_master_tid = runtime_instance
.sandbox
.get_vmm_master_tid()
.await
.context("get vmm master tid")?;
st.pid = vmm_master_tid as i32;
}
// Prestart Hooks [DEPRECATED in newest oci spec]:
// * should be run in runtime namespace
// * should be run after vm is started, but before container is created
// if Prestart Hook and CreateRuntime Hook are both supported
// * spec details: https://github.com/opencontainers/runtime-spec/blob/c1662686cff159595277b79322d0272f5182941b/config.md#prestart
if let Some(hooks) = spec.hooks.as_ref() {
let mut prestart_hook_states = HookStates::new();
prestart_hook_states.execute_hooks(&hooks.prestart, Some(st.clone()))?
}
// CreateRuntime Hooks:
// * should be run in runtime namespace
// * should be run when creating the runtime
// * spec details: https://github.com/opencontainers/runtime-spec/blob/c1662686cff159595277b79322d0272f5182941b/config.md#createruntime-hooks
if let Some(hooks) = spec.hooks.as_ref() {
let mut create_runtime_hook_states = HookStates::new();
create_runtime_hook_states.execute_hooks(&hooks.create_runtime, Some(st.clone()))?
}
// the sandbox creation can reach here only once and the sandbox is created // the sandbox creation can reach here only once and the sandbox is created
// so we can safely create the shim management socket right now // so we can safely create the shim management socket right now
// the unwrap here is safe because the runtime handler is correctly created // the unwrap here is safe because the runtime handler is correctly created
@ -207,10 +243,11 @@ impl RuntimeHandlerManager {
async fn try_init_runtime_instance( async fn try_init_runtime_instance(
&self, &self,
spec: &oci::Spec, spec: &oci::Spec,
state: &oci::State,
options: &Option<Vec<u8>>, options: &Option<Vec<u8>>,
) -> Result<()> { ) -> Result<()> {
let mut inner = self.inner.write().await; let mut inner = self.inner.write().await;
inner.try_init(spec, options).await inner.try_init(spec, state, options).await
} }
pub async fn handler_message(&self, req: Request) -> Result<Response> { pub async fn handler_message(&self, req: Request) -> Result<Response> {
@ -222,8 +259,16 @@ impl RuntimeHandlerManager {
oci::OCI_SPEC_CONFIG_FILE_NAME oci::OCI_SPEC_CONFIG_FILE_NAME
); );
let spec = oci::Spec::load(&bundler_path).context("load spec")?; let spec = oci::Spec::load(&bundler_path).context("load spec")?;
let state = oci::State {
version: spec.version.clone(),
id: container_config.container_id.to_string(),
status: oci::ContainerState::Creating,
pid: 0,
bundle: bundler_path,
annotations: spec.annotations.clone(),
};
self.try_init_runtime_instance(&spec, &container_config.options) self.try_init_runtime_instance(&spec, &state, &container_config.options)
.await .await
.context("try init runtime instance")?; .context("try init runtime instance")?;
let instance = self let instance = self

View File

@ -37,6 +37,7 @@ pub struct Container {
pid: u32, pid: u32,
pub container_id: ContainerID, pub container_id: ContainerID,
config: ContainerConfig, config: ContainerConfig,
spec: oci::Spec,
inner: Arc<RwLock<ContainerInner>>, inner: Arc<RwLock<ContainerInner>>,
agent: Arc<dyn Agent>, agent: Arc<dyn Agent>,
resource_manager: Arc<ResourceManager>, resource_manager: Arc<ResourceManager>,
@ -47,6 +48,7 @@ impl Container {
pub fn new( pub fn new(
pid: u32, pid: u32,
config: ContainerConfig, config: ContainerConfig,
spec: oci::Spec,
agent: Arc<dyn Agent>, agent: Arc<dyn Agent>,
resource_manager: Arc<ResourceManager>, resource_manager: Arc<ResourceManager>,
) -> Result<Self> { ) -> Result<Self> {
@ -67,6 +69,7 @@ impl Container {
pid, pid,
container_id, container_id,
config, config,
spec,
inner: Arc::new(RwLock::new(ContainerInner::new( inner: Arc::new(RwLock::new(ContainerInner::new(
agent.clone(), agent.clone(),
init_process, init_process,
@ -382,6 +385,14 @@ impl Container {
.context("agent update container")?; .context("agent update container")?;
Ok(()) Ok(())
} }
pub async fn config(&self) -> ContainerConfig {
self.config.clone()
}
pub async fn spec(&self) -> oci::Spec {
self.spec.clone()
}
} }
fn amend_spec(spec: &mut oci::Spec, disable_guest_seccomp: bool) -> Result<()> { fn amend_spec(spec: &mut oci::Spec, disable_guest_seccomp: bool) -> Result<()> {

View File

@ -5,11 +5,10 @@
// //
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use agent::Agent; use agent::Agent;
use async_trait::async_trait;
use common::{ use common::{
error::Error, error::Error,
types::{ types::{
@ -19,10 +18,13 @@ use common::{
}, },
ContainerManager, ContainerManager,
}; };
use hypervisor::Hypervisor;
use oci::Process as OCIProcess; use oci::Process as OCIProcess;
use resource::ResourceManager; use resource::ResourceManager;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use kata_sys_util::hooks::HookStates;
use super::{logger_with_process, Container}; use super::{logger_with_process, Container};
pub struct VirtContainerManager { pub struct VirtContainerManager {
@ -31,6 +33,7 @@ pub struct VirtContainerManager {
containers: Arc<RwLock<HashMap<String, Container>>>, containers: Arc<RwLock<HashMap<String, Container>>>,
resource_manager: Arc<ResourceManager>, resource_manager: Arc<ResourceManager>,
agent: Arc<dyn Agent>, agent: Arc<dyn Agent>,
hypervisor: Arc<dyn Hypervisor>,
} }
impl VirtContainerManager { impl VirtContainerManager {
@ -38,6 +41,7 @@ impl VirtContainerManager {
sid: &str, sid: &str,
pid: u32, pid: u32,
agent: Arc<dyn Agent>, agent: Arc<dyn Agent>,
hypervisor: Arc<dyn Hypervisor>,
resource_manager: Arc<ResourceManager>, resource_manager: Arc<ResourceManager>,
) -> Self { ) -> Self {
Self { Self {
@ -46,6 +50,7 @@ impl VirtContainerManager {
containers: Default::default(), containers: Default::default(),
resource_manager, resource_manager,
agent, agent,
hypervisor,
} }
} }
} }
@ -56,6 +61,7 @@ impl ContainerManager for VirtContainerManager {
let container = Container::new( let container = Container::new(
self.pid, self.pid,
config, config,
spec.clone(),
self.agent.clone(), self.agent.clone(),
self.resource_manager.clone(), self.resource_manager.clone(),
) )
@ -87,6 +93,26 @@ impl ContainerManager for VirtContainerManager {
let c = containers let c = containers
.remove(container_id) .remove(container_id)
.ok_or_else(|| Error::ContainerNotFound(container_id.to_string()))?; .ok_or_else(|| Error::ContainerNotFound(container_id.to_string()))?;
// Poststop Hooks:
// * should be run in runtime namespace
// * should be run after the container is deleted but before delete operation returns
// * spec details: https://github.com/opencontainers/runtime-spec/blob/c1662686cff159595277b79322d0272f5182941b/config.md#poststop
let c_spec = c.spec().await;
let vmm_master_tid = self.hypervisor.get_vmm_master_tid().await?;
let state = oci::State {
version: c_spec.version.clone(),
id: c.container_id.to_string(),
status: oci::ContainerState::Stopped,
pid: vmm_master_tid as i32,
bundle: c.config().await.bundle,
annotations: c_spec.annotations.clone(),
};
if let Some(hooks) = c_spec.hooks.as_ref() {
let mut poststop_hook_states = HookStates::new();
poststop_hook_states.execute_hooks(&hooks.poststop, Some(state))?;
}
c.state_process(process).await.context("state process") c.state_process(process).await.context("state process")
} }
ProcessType::Exec => { ProcessType::Exec => {
@ -190,6 +216,26 @@ impl ContainerManager for VirtContainerManager {
.get(container_id) .get(container_id)
.ok_or_else(|| Error::ContainerNotFound(container_id.clone()))?; .ok_or_else(|| Error::ContainerNotFound(container_id.clone()))?;
c.start(process).await.context("start")?; c.start(process).await.context("start")?;
// Poststart Hooks:
// * should be run in runtime namespace
// * should be run after user-specific command is executed but before start operation returns
// * spec details: https://github.com/opencontainers/runtime-spec/blob/c1662686cff159595277b79322d0272f5182941b/config.md#poststart
let c_spec = c.spec().await;
let vmm_master_tid = self.hypervisor.get_vmm_master_tid().await?;
let state = oci::State {
version: c_spec.version.clone(),
id: c.container_id.to_string(),
status: oci::ContainerState::Running,
pid: vmm_master_tid as i32,
bundle: c.config().await.bundle,
annotations: c_spec.annotations.clone(),
};
if let Some(hooks) = c_spec.hooks.as_ref() {
let mut poststart_hook_states = HookStates::new();
poststart_hook_states.execute_hooks(&hooks.poststart, Some(state))?;
}
Ok(PID { pid: self.pid }) Ok(PID { pid: self.pid })
} }

View File

@ -86,13 +86,18 @@ impl RuntimeHandler for VirtContainer {
sid, sid,
msg_sender, msg_sender,
agent.clone(), agent.clone(),
hypervisor, hypervisor.clone(),
resource_manager.clone(), resource_manager.clone(),
) )
.await .await
.context("new virt sandbox")?; .context("new virt sandbox")?;
let container_manager = let container_manager = container_manager::VirtContainerManager::new(
container_manager::VirtContainerManager::new(sid, pid, agent, resource_manager); sid,
pid,
agent,
hypervisor,
resource_manager,
);
Ok(RuntimeInstance { Ok(RuntimeInstance {
sandbox: Arc::new(sandbox), sandbox: Arc::new(sandbox),
container_manager: Arc::new(container_manager), container_manager: Arc::new(container_manager),

View File

@ -278,6 +278,10 @@ impl Sandbox for VirtSandbox {
self.agent.agent_sock().await self.agent.agent_sock().await
} }
async fn get_vmm_master_tid(&self) -> Result<u32> {
self.hypervisor.get_vmm_master_tid().await
}
async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>> { async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>> {
info!(sl!(), "sb: set_iptables invoked"); info!(sl!(), "sb: set_iptables invoked");
let req = SetIPTablesRequest { is_ipv6, data }; let req = SetIPTablesRequest { is_ipv6, data };