krata: rework into daemon / controller structure

This commit is contained in:
Alex Zenla
2024-03-05 11:35:25 +00:00
parent 17889d1c64
commit 8653fd6249
45 changed files with 1597 additions and 493 deletions

View File

@ -0,0 +1,91 @@
use anyhow::{anyhow, Result};
use krata::control::{ConsoleStreamResponse, ConsoleStreamUpdate, Request, Response, StreamUpdate};
use log::warn;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
select,
};
use crate::{
listen::DaemonRequestHandler,
runtime::{console::XenConsole, Runtime},
};
use krata::stream::{ConnectionStreams, StreamContext};
pub struct ConsoleStreamRequestHandler {}
impl Default for ConsoleStreamRequestHandler {
fn default() -> Self {
Self::new()
}
}
impl ConsoleStreamRequestHandler {
pub fn new() -> Self {
Self {}
}
async fn link_console_stream(mut stream: StreamContext, mut console: XenConsole) -> Result<()> {
loop {
let mut buffer = vec![0u8; 256];
select! {
x = console.read_handle.read(&mut buffer) => match x {
Ok(size) => {
let data = buffer[0..size].to_vec();
let update = StreamUpdate::ConsoleStream(ConsoleStreamUpdate {
data,
});
stream.send(update).await?;
},
Err(error) => {
return Err(error.into());
}
},
x = stream.receiver.recv() => match x {
Some(StreamUpdate::ConsoleStream(update)) => {
console.write_handle.write_all(&update.data).await?;
}
None => {
break;
}
}
};
}
Ok(())
}
}
#[async_trait::async_trait]
impl DaemonRequestHandler for ConsoleStreamRequestHandler {
fn accepts(&self, request: &Request) -> bool {
matches!(request, Request::ConsoleStream(_))
}
async fn handle(
&self,
streams: ConnectionStreams,
runtime: Runtime,
request: Request,
) -> Result<Response> {
let console_stream = match request {
Request::ConsoleStream(stream) => stream,
_ => return Err(anyhow!("unknown request")),
};
let console = runtime.console(&console_stream.guest).await?;
let stream = streams.open().await?;
let id = stream.id;
tokio::task::spawn(async move {
if let Err(error) =
ConsoleStreamRequestHandler::link_console_stream(stream, console).await
{
warn!("failed to process console stream: {}", error);
}
});
Ok(Response::ConsoleStream(ConsoleStreamResponse {
stream: id,
}))
}
}

View File

@ -0,0 +1,44 @@
use anyhow::{anyhow, Result};
use krata::{
control::{DestroyResponse, Request, Response},
stream::ConnectionStreams,
};
use crate::{listen::DaemonRequestHandler, runtime::Runtime};
pub struct DestroyRequestHandler {}
impl Default for DestroyRequestHandler {
fn default() -> Self {
Self::new()
}
}
impl DestroyRequestHandler {
pub fn new() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl DaemonRequestHandler for DestroyRequestHandler {
fn accepts(&self, request: &Request) -> bool {
matches!(request, Request::Destroy(_))
}
async fn handle(
&self,
_: ConnectionStreams,
runtime: Runtime,
request: Request,
) -> Result<Response> {
let destroy = match request {
Request::Destroy(destroy) => destroy,
_ => return Err(anyhow!("unknown request")),
};
let guest = runtime.destroy(&destroy.guest).await?;
Ok(Response::Destroy(DestroyResponse {
guest: guest.to_string(),
}))
}
}

View File

@ -0,0 +1,55 @@
use anyhow::{anyhow, Result};
use krata::{
control::{GuestInfo, LaunchResponse, Request, Response},
stream::ConnectionStreams,
};
use crate::{
listen::DaemonRequestHandler,
runtime::{launch::GuestLaunchRequest, Runtime},
};
pub struct LaunchRequestHandler {}
impl Default for LaunchRequestHandler {
fn default() -> Self {
Self::new()
}
}
impl LaunchRequestHandler {
pub fn new() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl DaemonRequestHandler for LaunchRequestHandler {
fn accepts(&self, request: &Request) -> bool {
matches!(request, Request::Launch(_))
}
async fn handle(
&self,
_: ConnectionStreams,
runtime: Runtime,
request: Request,
) -> Result<Response> {
let launch = match request {
Request::Launch(launch) => launch,
_ => return Err(anyhow!("unknown request")),
};
let guest: GuestInfo = runtime
.launch(GuestLaunchRequest {
image: &launch.image,
vcpus: launch.vcpus,
mem: launch.mem,
env: launch.env,
run: launch.run,
debug: false,
})
.await?
.into();
Ok(Response::Launch(LaunchResponse { guest }))
}
}

View File

@ -0,0 +1,37 @@
use anyhow::Result;
use krata::{
control::{GuestInfo, ListResponse, Request, Response},
stream::ConnectionStreams,
};
use crate::{listen::DaemonRequestHandler, runtime::Runtime};
pub struct ListRequestHandler {}
impl Default for ListRequestHandler {
fn default() -> Self {
Self::new()
}
}
impl ListRequestHandler {
pub fn new() -> Self {
Self {}
}
}
#[async_trait::async_trait]
impl DaemonRequestHandler for ListRequestHandler {
fn accepts(&self, request: &Request) -> bool {
matches!(request, Request::List(_))
}
async fn handle(&self, _: ConnectionStreams, runtime: Runtime, _: Request) -> Result<Response> {
let guests = runtime.list().await?;
let guests = guests
.into_iter()
.map(GuestInfo::from)
.collect::<Vec<GuestInfo>>();
Ok(Response::List(ListResponse { guests }))
}
}

View File

@ -0,0 +1,15 @@
pub mod console;
pub mod destroy;
pub mod launch;
pub mod list;
impl From<crate::runtime::GuestInfo> for krata::control::GuestInfo {
fn from(value: crate::runtime::GuestInfo) -> Self {
krata::control::GuestInfo {
id: value.uuid.to_string(),
image: value.image.clone(),
ipv4: value.ipv4.map(|x| x.ip().to_string()),
ipv6: value.ipv6.map(|x| x.ip().to_string()),
}
}
}