mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 13:11:31 +00:00
feat: idm snooping (#71)
Implement IDM snooping, a new feature that lets you snoop on messages between guests and the host. The feature exposes the IDM packets send and receives to the API, allowing kratactl to now listen for messages and feed them to a user for debugging purposes.
This commit is contained in:
74
crates/ctl/src/cli/idm_snoop.rs
Normal file
74
crates/ctl/src/cli/idm_snoop.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use krata::{
|
||||
events::EventStream,
|
||||
v1::control::{control_service_client::ControlServiceClient, SnoopIdmReply, SnoopIdmRequest},
|
||||
};
|
||||
|
||||
use tokio_stream::StreamExt;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use crate::format::{kv2line, proto2dynamic, proto2kv};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum IdmSnoopFormat {
|
||||
Simple,
|
||||
Jsonl,
|
||||
KeyValue,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "Snoop on the IDM bus")]
|
||||
pub struct IdmSnoopCommand {
|
||||
#[arg(short, long, default_value = "simple", help = "Output format")]
|
||||
format: IdmSnoopFormat,
|
||||
}
|
||||
|
||||
impl IdmSnoopCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
mut client: ControlServiceClient<Channel>,
|
||||
_events: EventStream,
|
||||
) -> Result<()> {
|
||||
let mut stream = client.snoop_idm(SnoopIdmRequest {}).await?.into_inner();
|
||||
|
||||
while let Some(reply) = stream.next().await {
|
||||
let reply = reply?;
|
||||
match self.format {
|
||||
IdmSnoopFormat::Simple => {
|
||||
self.print_simple(reply)?;
|
||||
}
|
||||
|
||||
IdmSnoopFormat::Jsonl => {
|
||||
let value = serde_json::to_value(proto2dynamic(reply)?)?;
|
||||
let encoded = serde_json::to_string(&value)?;
|
||||
println!("{}", encoded.trim());
|
||||
}
|
||||
|
||||
IdmSnoopFormat::KeyValue => {
|
||||
self.print_key_value(reply)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_simple(&self, reply: SnoopIdmReply) -> Result<()> {
|
||||
let from = reply.from;
|
||||
let to = reply.to;
|
||||
let Some(packet) = reply.packet else {
|
||||
return Ok(());
|
||||
};
|
||||
let value = serde_json::to_value(proto2dynamic(packet)?)?;
|
||||
let encoded = serde_json::to_string(&value)?;
|
||||
println!("({} -> {}) {}", from, to, encoded);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_key_value(&self, reply: SnoopIdmReply) -> Result<()> {
|
||||
let kvs = proto2kv(reply)?;
|
||||
println!("{}", kv2line(kvs));
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
pub mod attach;
|
||||
pub mod destroy;
|
||||
pub mod idm_snoop;
|
||||
pub mod launch;
|
||||
pub mod list;
|
||||
pub mod logs;
|
||||
@ -17,8 +18,9 @@ use krata::{
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
use self::{
|
||||
attach::AttachCommand, destroy::DestroyCommand, launch::LauchCommand, list::ListCommand,
|
||||
logs::LogsCommand, metrics::MetricsCommand, resolve::ResolveCommand, watch::WatchCommand,
|
||||
attach::AttachCommand, destroy::DestroyCommand, idm_snoop::IdmSnoopCommand,
|
||||
launch::LauchCommand, list::ListCommand, logs::LogsCommand, metrics::MetricsCommand,
|
||||
resolve::ResolveCommand, watch::WatchCommand,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
@ -49,6 +51,7 @@ pub enum Commands {
|
||||
Watch(WatchCommand),
|
||||
Resolve(ResolveCommand),
|
||||
Metrics(MetricsCommand),
|
||||
IdmSnoop(IdmSnoopCommand),
|
||||
}
|
||||
|
||||
impl ControlCommand {
|
||||
@ -88,6 +91,10 @@ impl ControlCommand {
|
||||
Commands::Metrics(metrics) => {
|
||||
metrics.run(client, events).await?;
|
||||
}
|
||||
|
||||
Commands::IdmSnoop(snoop) => {
|
||||
snoop.run(client, events).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user