Add shim exit signal
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
This commit is contained in:
parent
2120de8ba8
commit
9629eac9ec
|
|
@ -10,37 +10,46 @@ API offered by containerd's shim v2 runtime implementation written in Go.
|
||||||
The API is very similar to the one offered by Go version:
|
The API is very similar to the one offered by Go version:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct Service;
|
struct Service {
|
||||||
|
exit: shim::ExitSignal,
|
||||||
|
}
|
||||||
|
|
||||||
impl shim::Shim for Service {
|
impl shim::Shim for Service {
|
||||||
fn new(_id: &str, _namespace: &str, _config: &mut shim::Config) -> Self {
|
fn new(
|
||||||
Service {}
|
_id: &str,
|
||||||
|
_namespace: &str,
|
||||||
|
_publisher: shim::RemotePublisher,
|
||||||
|
_config: &mut shim::Config,
|
||||||
|
exit: shim::ExitSignal,
|
||||||
|
) -> Self {
|
||||||
|
Service { exit }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_shim(&mut self, opts: StartOpts) -> Result<String, Box<dyn Error>> {
|
fn start_shim(&mut self, _opts: shim::StartOpts) -> Result<String, Box<dyn Error>> {
|
||||||
let address = shim::spawn(opts)?;
|
Ok("Socket address here".into())
|
||||||
Ok(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete_shim(&mut self) -> Result<api::DeleteResponse, Box<dyn Error>> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl shim::Task for Service {
|
impl shim::Task for Service {
|
||||||
fn create(
|
fn create(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TtrpcContext,
|
_ctx: &TtrpcContext,
|
||||||
req: api::CreateTaskRequest,
|
_req: api::CreateTaskRequest,
|
||||||
) -> ::ttrpc::Result<api::CreateTaskResponse> {
|
) -> TtrpcResult<api::CreateTaskResponse> {
|
||||||
debug!("Create");
|
// New task nere...
|
||||||
Ok(api::CreateTaskResponse::default())
|
Ok(api::CreateTaskResponse::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shutdown(&self, _ctx: &TtrpcContext, _req: api::ShutdownRequest) -> TtrpcResult<api::Empty> {
|
||||||
|
self.exit.signal(); // Signal to shutdown shim server
|
||||||
|
Ok(api::Empty::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
shim::run::<Service>("io.containerd.empty.v1")
|
shim::run::<Service>("io.containerd.empty.v1")
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
use containerd_shim as shim;
|
use containerd_shim as shim;
|
||||||
use shim::{api, TtrpcContext, TtrpcResult};
|
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use shim::{api, TtrpcContext, TtrpcResult};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
struct Service;
|
struct Service {
|
||||||
|
exit: shim::ExitSignal,
|
||||||
|
}
|
||||||
|
|
||||||
impl shim::Shim for Service {
|
impl shim::Shim for Service {
|
||||||
fn new(
|
fn new(
|
||||||
|
|
@ -11,8 +14,13 @@ impl shim::Shim for Service {
|
||||||
_namespace: &str,
|
_namespace: &str,
|
||||||
_publisher: shim::RemotePublisher,
|
_publisher: shim::RemotePublisher,
|
||||||
_config: &mut shim::Config,
|
_config: &mut shim::Config,
|
||||||
|
exit: shim::ExitSignal,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Service {}
|
Service { exit }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_shim(&mut self, _opts: shim::StartOpts) -> Result<String, Box<dyn Error>> {
|
||||||
|
Ok("Socket address here".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,6 +33,11 @@ impl shim::Task for Service {
|
||||||
info!("Create");
|
info!("Create");
|
||||||
Ok(api::CreateTaskResponse::default())
|
Ok(api::CreateTaskResponse::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shutdown(&self, _ctx: &TtrpcContext, _req: api::ShutdownRequest) -> TtrpcResult<api::Empty> {
|
||||||
|
self.exit.signal();
|
||||||
|
Ok(api::Empty::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ use std::hash::Hasher;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::{self, Command, Stdio};
|
use std::process::{self, Command, Stdio};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
pub use containerd_shim_protos as protos;
|
pub use containerd_shim_protos as protos;
|
||||||
|
|
||||||
use protos::protobuf::Message;
|
use protos::protobuf::Message;
|
||||||
use protos::shim::{shim::DeleteResponse, shim_ttrpc::create_task};
|
use protos::shim::{shim::DeleteResponse, shim_ttrpc::create_task};
|
||||||
use protos::ttrpc::Server;
|
use protos::ttrpc::Server;
|
||||||
|
|
@ -23,7 +25,11 @@ mod reap;
|
||||||
|
|
||||||
pub use publisher::RemotePublisher;
|
pub use publisher::RemotePublisher;
|
||||||
|
|
||||||
pub use protos::shim::shim as api;
|
pub mod api {
|
||||||
|
pub use super::protos::shim::empty::Empty;
|
||||||
|
pub use super::protos::shim::shim::*;
|
||||||
|
}
|
||||||
|
|
||||||
pub use protos::shim::shim_ttrpc::Task;
|
pub use protos::shim::shim_ttrpc::Task;
|
||||||
|
|
||||||
pub use protos::ttrpc;
|
pub use protos::ttrpc;
|
||||||
|
|
@ -39,6 +45,8 @@ pub struct Config {
|
||||||
pub no_sub_reaper: bool,
|
pub no_sub_reaper: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Startup options received from containerd to start new shim instance.
|
||||||
|
/// These will be passed via [`Shim::start_shim`] to shim.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct StartOpts {
|
pub struct StartOpts {
|
||||||
/// ID of the container.
|
/// ID of the container.
|
||||||
|
|
@ -53,17 +61,49 @@ pub struct StartOpts {
|
||||||
pub namespace: String,
|
pub namespace: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shim interface that must be implemented by clients.
|
/// Helper structure that wraps atomic bool to signal shim server when to shutdown the TTRPC server.
|
||||||
pub trait Shim: Task {
|
/// Shim implementations are responsible for calling [`Self::signal`].
|
||||||
fn new(id: &str, namespace: &str, publisher: RemotePublisher, config: &mut Config) -> Self;
|
#[derive(Clone)]
|
||||||
|
pub struct ExitSignal(Arc<AtomicBool>);
|
||||||
|
|
||||||
/// Launch new shim.
|
impl Default for ExitSignal {
|
||||||
/// See https://github.com/containerd/containerd/tree/master/runtime/v2#start
|
fn default() -> Self {
|
||||||
fn start_shim(&mut self, opts: StartOpts) -> Result<String, Box<dyn error::Error>> {
|
ExitSignal(Arc::new(AtomicBool::new(false)))
|
||||||
let address = spawn(opts)?;
|
}
|
||||||
Ok(address)
|
}
|
||||||
|
|
||||||
|
impl ExitSignal {
|
||||||
|
/// Set exit signal to shutdown shim server.
|
||||||
|
pub fn signal(&self) {
|
||||||
|
self.0.store(true, Ordering::Release)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for the exit signal to be set.
|
||||||
|
fn wait(&self) {
|
||||||
|
while !self.0.load(Ordering::Acquire) {
|
||||||
|
std::hint::spin_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main shim interface that must be implemented by all shims.
|
||||||
|
/// Start and delete routines will be called to handle containerd's shim lifecycle requests.
|
||||||
|
pub trait Shim: Task {
|
||||||
|
fn new(
|
||||||
|
id: &str,
|
||||||
|
namespace: &str,
|
||||||
|
publisher: RemotePublisher,
|
||||||
|
config: &mut Config,
|
||||||
|
exit: ExitSignal,
|
||||||
|
) -> Self;
|
||||||
|
|
||||||
|
/// Start shim will be called by containerd when launching new shim instance.
|
||||||
|
/// It expected to return TTRPC address containerd daemon can use to communicate with
|
||||||
|
/// the given shim instance.
|
||||||
|
/// See https://github.com/containerd/containerd/tree/master/runtime/v2#start
|
||||||
|
fn start_shim(&mut self, opts: StartOpts) -> Result<String, Box<dyn error::Error>>;
|
||||||
|
|
||||||
|
/// Delete shim will be called by containerd after shim shutdown to cleanup any leftovers.
|
||||||
fn delete_shim(&mut self) -> Result<DeleteResponse, Box<dyn error::Error>> {
|
fn delete_shim(&mut self) -> Result<DeleteResponse, Box<dyn error::Error>> {
|
||||||
Ok(DeleteResponse::default())
|
Ok(DeleteResponse::default())
|
||||||
}
|
}
|
||||||
|
|
@ -91,8 +131,15 @@ where
|
||||||
let publisher = publisher::RemotePublisher::new(&ttrpc_address)?;
|
let publisher = publisher::RemotePublisher::new(&ttrpc_address)?;
|
||||||
|
|
||||||
// Create shim instance
|
// Create shim instance
|
||||||
|
let exit_signal = ExitSignal::default();
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
let mut shim = T::new(id, &flags.namespace, publisher, &mut config);
|
let mut shim = T::new(
|
||||||
|
id,
|
||||||
|
&flags.namespace,
|
||||||
|
publisher,
|
||||||
|
&mut config,
|
||||||
|
exit_signal.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
if !config.no_sub_reaper {
|
if !config.no_sub_reaper {
|
||||||
reap::set_subreaper()?;
|
reap::set_subreaper()?;
|
||||||
|
|
@ -135,8 +182,7 @@ where
|
||||||
|
|
||||||
server.start()?;
|
server.start()?;
|
||||||
|
|
||||||
// TODO: define exit criteria here.
|
exit_signal.wait();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(360));
|
|
||||||
|
|
||||||
server.shutdown();
|
server.shutdown();
|
||||||
|
|
||||||
|
|
@ -208,9 +254,30 @@ pub fn spawn(opts: StartOpts) -> Result<String, Error> {
|
||||||
])
|
])
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
// This is temp HACK.
|
// TODO: This is hack: give TTRPC server some time to initialize. Need to pass fd instead.
|
||||||
// Give TTRPC server some time to initialize.
|
|
||||||
thread::sleep(time::Duration::from_secs(2));
|
thread::sleep(time::Duration::from_secs(2));
|
||||||
|
|
||||||
Ok(socket_address)
|
Ok(socket_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exit_signal() {
|
||||||
|
let signal = ExitSignal::default();
|
||||||
|
|
||||||
|
let cloned = signal.clone();
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
cloned.signal();
|
||||||
|
});
|
||||||
|
|
||||||
|
signal.wait();
|
||||||
|
|
||||||
|
if let Err(err) = handle.join() {
|
||||||
|
panic!("{:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue