mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-05 06:01:32 +00:00
feat: implement IdmClient backend support
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1228,6 +1228,7 @@ name = "krata"
|
|||||||
version = "0.0.8"
|
version = "0.0.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use krata::{
|
use krata::{
|
||||||
idm::protocol::{idm_event::Event, IdmPacket},
|
idm::protocol::{idm_event::Event, idm_packet::Content, IdmPacket},
|
||||||
v1::common::{GuestExitInfo, GuestState, GuestStatus},
|
v1::common::{GuestExitInfo, GuestState, GuestStatus},
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
@ -117,10 +117,14 @@ impl DaemonEventGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_idm_packet(&mut self, id: Uuid, packet: IdmPacket) -> Result<()> {
|
async fn handle_idm_packet(&mut self, id: Uuid, packet: IdmPacket) -> Result<()> {
|
||||||
if let Some(Event::Exit(exit)) = packet.event.and_then(|x| x.event) {
|
match packet.content {
|
||||||
self.handle_exit_code(id, exit.code).await?;
|
Some(Content::Event(event)) => match event.event {
|
||||||
|
Some(Event::Exit(exit)) => self.handle_exit_code(id, exit.code).await,
|
||||||
|
None => Ok(()),
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_exit_code(&mut self, id: Uuid, code: i32) -> Result<()> {
|
async fn handle_exit_code(&mut self, id: Uuid, code: i32) -> Result<()> {
|
||||||
|
@ -6,7 +6,7 @@ use anyhow::Result;
|
|||||||
use cgroups_rs::Cgroup;
|
use cgroups_rs::Cgroup;
|
||||||
use krata::idm::{
|
use krata::idm::{
|
||||||
client::IdmClient,
|
client::IdmClient,
|
||||||
protocol::{idm_event::Event, IdmEvent, IdmExitEvent, IdmPacket},
|
protocol::{idm_event::Event, idm_packet::Content, IdmEvent, IdmExitEvent, IdmPacket},
|
||||||
};
|
};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
@ -59,9 +59,9 @@ impl GuestBackground {
|
|||||||
self.idm
|
self.idm
|
||||||
.sender
|
.sender
|
||||||
.send(IdmPacket {
|
.send(IdmPacket {
|
||||||
event: Some(IdmEvent {
|
content: Some(Content::Event(IdmEvent {
|
||||||
event: Some(Event::Exit(IdmExitEvent { code: event.status })),
|
event: Some(Event::Exit(IdmExitEvent { code: event.status })),
|
||||||
}),
|
})),
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
death(event.status).await?;
|
death(event.status).await?;
|
||||||
|
@ -10,6 +10,7 @@ resolver = "2"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
async-trait = { workspace = true }
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
libc = { workspace = true }
|
libc = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
@ -6,8 +6,12 @@ option java_multiple_files = true;
|
|||||||
option java_package = "dev.krata.proto.internal.idm";
|
option java_package = "dev.krata.proto.internal.idm";
|
||||||
option java_outer_classname = "IdmProto";
|
option java_outer_classname = "IdmProto";
|
||||||
|
|
||||||
message IdmExitEvent {
|
message IdmPacket {
|
||||||
int32 code = 1;
|
oneof content {
|
||||||
|
IdmEvent event = 1;
|
||||||
|
IdmRequest request = 2;
|
||||||
|
IdmResponse response = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message IdmEvent {
|
message IdmEvent {
|
||||||
@ -16,6 +20,24 @@ message IdmEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message IdmPacket {
|
message IdmExitEvent {
|
||||||
IdmEvent event = 1;
|
int32 code = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message IdmRequest {
|
||||||
|
uint64 id = 1;
|
||||||
|
oneof request {
|
||||||
|
IdmPingRequest ping = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message IdmPingRequest {}
|
||||||
|
|
||||||
|
message IdmResponse {
|
||||||
|
uint64 id = 1;
|
||||||
|
oneof response {
|
||||||
|
IdmPingResponse ping = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message IdmPingResponse {}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::path::Path;
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use super::protocol::IdmPacket;
|
use super::protocol::IdmPacket;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
@ -10,12 +10,68 @@ use tokio::{
|
|||||||
fs::File,
|
fs::File,
|
||||||
io::{unix::AsyncFd, AsyncReadExt, AsyncWriteExt},
|
io::{unix::AsyncFd, AsyncReadExt, AsyncWriteExt},
|
||||||
select,
|
select,
|
||||||
sync::mpsc::{channel, Receiver, Sender},
|
sync::{
|
||||||
|
mpsc::{channel, Receiver, Sender},
|
||||||
|
Mutex,
|
||||||
|
},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
const IDM_PACKET_QUEUE_LEN: usize = 100;
|
const IDM_PACKET_QUEUE_LEN: usize = 100;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait IdmBackend: Send {
|
||||||
|
async fn recv(&mut self) -> Result<IdmPacket>;
|
||||||
|
async fn send(&mut self, packet: IdmPacket) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdmFileBackend {
|
||||||
|
fd: Arc<Mutex<AsyncFd<File>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdmFileBackend {
|
||||||
|
pub async fn new(file: File) -> Result<IdmFileBackend> {
|
||||||
|
IdmFileBackend::set_raw_port(&file)?;
|
||||||
|
Ok(IdmFileBackend {
|
||||||
|
fd: Arc::new(Mutex::new(AsyncFd::new(file)?)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_raw_port(file: &File) -> Result<()> {
|
||||||
|
let mut termios = tcgetattr(file)?;
|
||||||
|
cfmakeraw(&mut termios);
|
||||||
|
tcsetattr(file, SetArg::TCSANOW, &termios)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl IdmBackend for IdmFileBackend {
|
||||||
|
async fn recv(&mut self) -> Result<IdmPacket> {
|
||||||
|
let mut fd = self.fd.lock().await;
|
||||||
|
let mut guard = fd.readable_mut().await?;
|
||||||
|
let size = guard.get_inner_mut().read_u16_le().await?;
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(IdmPacket::default());
|
||||||
|
}
|
||||||
|
let mut buffer = BytesMut::with_capacity(size as usize);
|
||||||
|
guard.get_inner_mut().read_exact(&mut buffer).await?;
|
||||||
|
match IdmPacket::decode(buffer) {
|
||||||
|
Ok(packet) => Ok(packet),
|
||||||
|
|
||||||
|
Err(error) => Err(anyhow!("received invalid idm packet: {}", error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send(&mut self, packet: IdmPacket) -> Result<()> {
|
||||||
|
let mut fd = self.fd.lock().await;
|
||||||
|
let data = packet.encode_to_vec();
|
||||||
|
fd.get_mut().write_u16_le(data.len() as u16).await?;
|
||||||
|
fd.get_mut().write_all(&data).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IdmClient {
|
pub struct IdmClient {
|
||||||
pub receiver: Receiver<IdmPacket>,
|
pub receiver: Receiver<IdmPacket>,
|
||||||
pub sender: Sender<IdmPacket>,
|
pub sender: Sender<IdmPacket>,
|
||||||
@ -29,18 +85,11 @@ impl Drop for IdmClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IdmClient {
|
impl IdmClient {
|
||||||
pub async fn open<P: AsRef<Path>>(path: P) -> Result<IdmClient> {
|
pub async fn new<'a>(backend: Box<dyn IdmBackend>) -> Result<IdmClient> {
|
||||||
let file = File::options()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.create(false)
|
|
||||||
.open(path)
|
|
||||||
.await?;
|
|
||||||
IdmClient::set_raw_port(&file)?;
|
|
||||||
let (rx_sender, rx_receiver) = channel(IDM_PACKET_QUEUE_LEN);
|
let (rx_sender, rx_receiver) = channel(IDM_PACKET_QUEUE_LEN);
|
||||||
let (tx_sender, tx_receiver) = channel(IDM_PACKET_QUEUE_LEN);
|
let (tx_sender, tx_receiver) = channel(IDM_PACKET_QUEUE_LEN);
|
||||||
let task = tokio::task::spawn(async move {
|
let task = tokio::task::spawn(async move {
|
||||||
if let Err(error) = IdmClient::process(file, rx_sender, tx_receiver).await {
|
if let Err(error) = IdmClient::process(backend, rx_sender, tx_receiver).await {
|
||||||
debug!("failed to handle idm client processing: {}", error);
|
debug!("failed to handle idm client processing: {}", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -51,38 +100,27 @@ impl IdmClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_raw_port(file: &File) -> Result<()> {
|
pub async fn open<P: AsRef<Path>>(path: P) -> Result<IdmClient> {
|
||||||
let mut termios = tcgetattr(file)?;
|
let file = File::options()
|
||||||
cfmakeraw(&mut termios);
|
.read(true)
|
||||||
tcsetattr(file, SetArg::TCSANOW, &termios)?;
|
.write(true)
|
||||||
Ok(())
|
.create(false)
|
||||||
|
.open(path)
|
||||||
|
.await?;
|
||||||
|
let backend = IdmFileBackend::new(file).await?;
|
||||||
|
IdmClient::new(Box::new(backend) as Box<dyn IdmBackend>).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process(
|
async fn process(
|
||||||
file: File,
|
mut backend: Box<dyn IdmBackend>,
|
||||||
sender: Sender<IdmPacket>,
|
sender: Sender<IdmPacket>,
|
||||||
mut receiver: Receiver<IdmPacket>,
|
mut receiver: Receiver<IdmPacket>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut file = AsyncFd::new(file)?;
|
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
x = file.readable_mut() => match x {
|
x = backend.recv() => match x {
|
||||||
Ok(mut guard) => {
|
Ok(packet) => {
|
||||||
let size = guard.get_inner_mut().read_u16_le().await?;
|
sender.send(packet).await?;
|
||||||
if size == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut buffer = BytesMut::with_capacity(size as usize);
|
|
||||||
guard.get_inner_mut().read_exact(&mut buffer).await?;
|
|
||||||
match IdmPacket::decode(buffer) {
|
|
||||||
Ok(packet) => {
|
|
||||||
sender.send(packet).await?;
|
|
||||||
},
|
|
||||||
|
|
||||||
Err(error) => {
|
|
||||||
error!("received invalid idm packet: {}", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
@ -91,13 +129,12 @@ impl IdmClient {
|
|||||||
},
|
},
|
||||||
x = receiver.recv() => match x {
|
x = receiver.recv() => match x {
|
||||||
Some(packet) => {
|
Some(packet) => {
|
||||||
let data = packet.encode_to_vec();
|
let length = packet.encoded_len();
|
||||||
if data.len() > u16::MAX as usize {
|
if length > u16::MAX as usize {
|
||||||
error!("unable to send idm packet, packet size exceeded (tried to send {} bytes)", data.len());
|
error!("unable to send idm packet, packet size exceeded (tried to send {} bytes)", length);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
file.get_mut().write_u16_le(data.len() as u16).await?;
|
backend.send(packet).await?;
|
||||||
file.get_mut().write_all(&data).await?;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
None => {
|
None => {
|
||||||
|
Reference in New Issue
Block a user