2024-03-15 15:59:18 +00:00
|
|
|
use anyhow::Result;
|
2024-03-23 04:07:48 +00:00
|
|
|
use clap::{Parser, ValueEnum};
|
|
|
|
use cli_tables::Table;
|
2024-03-15 15:59:18 +00:00
|
|
|
use krata::{
|
2024-03-23 04:07:48 +00:00
|
|
|
common::{guest_image_spec::Image, Guest},
|
2024-03-15 15:59:18 +00:00
|
|
|
control::{control_service_client::ControlServiceClient, ListGuestsRequest},
|
|
|
|
};
|
|
|
|
|
2024-03-23 04:07:48 +00:00
|
|
|
use serde_json::Value;
|
2024-03-15 15:59:18 +00:00
|
|
|
use tonic::{transport::Channel, Request};
|
|
|
|
|
2024-03-23 04:07:48 +00:00
|
|
|
use crate::{
|
|
|
|
events::EventStream,
|
2024-03-23 07:00:12 +00:00
|
|
|
format::{kv2line, proto2dynamic, proto2kv},
|
2024-03-23 04:07:48 +00:00
|
|
|
};
|
2024-03-15 15:59:18 +00:00
|
|
|
|
|
|
|
use super::pretty::guest_state_text;
|
|
|
|
|
2024-03-23 07:00:12 +00:00
|
|
|
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
2024-03-23 04:07:48 +00:00
|
|
|
enum ListFormat {
|
|
|
|
CliTable,
|
|
|
|
Json,
|
|
|
|
JsonPretty,
|
|
|
|
Jsonl,
|
|
|
|
Yaml,
|
|
|
|
KeyValue,
|
|
|
|
}
|
|
|
|
|
2024-03-15 15:59:18 +00:00
|
|
|
#[derive(Parser)]
|
2024-03-23 04:07:48 +00:00
|
|
|
pub struct ListCommand {
|
2024-03-23 07:00:12 +00:00
|
|
|
#[arg(short, long, default_value = "cli-table")]
|
2024-03-23 04:07:48 +00:00
|
|
|
format: ListFormat,
|
|
|
|
}
|
2024-03-15 15:59:18 +00:00
|
|
|
|
|
|
|
impl ListCommand {
|
|
|
|
pub async fn run(
|
|
|
|
self,
|
|
|
|
mut client: ControlServiceClient<Channel>,
|
|
|
|
_events: EventStream,
|
|
|
|
) -> Result<()> {
|
|
|
|
let response = client
|
|
|
|
.list_guests(Request::new(ListGuestsRequest {}))
|
|
|
|
.await?
|
|
|
|
.into_inner();
|
2024-03-23 04:07:48 +00:00
|
|
|
|
|
|
|
match self.format {
|
|
|
|
ListFormat::CliTable => {
|
|
|
|
self.print_guest_table(response.guests)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
ListFormat::Json | ListFormat::JsonPretty | ListFormat::Yaml => {
|
|
|
|
let mut values = Vec::new();
|
|
|
|
for guest in response.guests {
|
|
|
|
let message = proto2dynamic(guest)?;
|
|
|
|
values.push(serde_json::to_value(message)?);
|
|
|
|
}
|
|
|
|
let value = Value::Array(values);
|
|
|
|
let encoded = if self.format == ListFormat::JsonPretty {
|
|
|
|
serde_json::to_string_pretty(&value)?
|
|
|
|
} else if self.format == ListFormat::Yaml {
|
|
|
|
serde_yaml::to_string(&value)?
|
|
|
|
} else {
|
|
|
|
serde_json::to_string(&value)?
|
|
|
|
};
|
|
|
|
println!("{}", encoded.trim());
|
|
|
|
}
|
|
|
|
|
|
|
|
ListFormat::Jsonl => {
|
|
|
|
for guest in response.guests {
|
|
|
|
let message = proto2dynamic(guest)?;
|
|
|
|
println!("{}", serde_json::to_string(&message)?);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ListFormat::KeyValue => {
|
|
|
|
self.print_key_value(response.guests)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_guest_table(&self, guests: Vec<Guest>) -> Result<()> {
|
|
|
|
let mut table = Table::new();
|
2024-03-15 15:59:18 +00:00
|
|
|
let header = vec!["name", "uuid", "state", "ipv4", "ipv6", "image"];
|
|
|
|
table.push_row(&header)?;
|
2024-03-23 04:07:48 +00:00
|
|
|
for guest in guests {
|
2024-03-15 15:59:18 +00:00
|
|
|
let ipv4 = guest
|
2024-03-23 07:00:12 +00:00
|
|
|
.state
|
2024-03-15 15:59:18 +00:00
|
|
|
.as_ref()
|
2024-03-23 07:00:12 +00:00
|
|
|
.and_then(|x| x.network.as_ref())
|
2024-03-15 15:59:18 +00:00
|
|
|
.map(|x| x.ipv4.as_str())
|
|
|
|
.unwrap_or("unknown");
|
|
|
|
let ipv6 = guest
|
2024-03-23 07:00:12 +00:00
|
|
|
.state
|
2024-03-15 15:59:18 +00:00
|
|
|
.as_ref()
|
2024-03-23 07:00:12 +00:00
|
|
|
.and_then(|x| x.network.as_ref())
|
2024-03-15 15:59:18 +00:00
|
|
|
.map(|x| x.ipv6.as_str())
|
|
|
|
.unwrap_or("unknown");
|
|
|
|
let Some(spec) = guest.spec else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let image = spec
|
|
|
|
.image
|
|
|
|
.map(|x| {
|
|
|
|
x.image
|
|
|
|
.map(|y| match y {
|
|
|
|
Image::Oci(oci) => oci.image,
|
|
|
|
})
|
|
|
|
.unwrap_or("unknown".to_string())
|
|
|
|
})
|
|
|
|
.unwrap_or("unknown".to_string());
|
|
|
|
table.push_row_string(&vec![
|
|
|
|
spec.name,
|
|
|
|
guest.id,
|
2024-03-23 07:00:12 +00:00
|
|
|
format!("{}", guest_state_text(guest.state.as_ref())),
|
2024-03-15 15:59:18 +00:00
|
|
|
ipv4.to_string(),
|
|
|
|
ipv6.to_string(),
|
|
|
|
image,
|
|
|
|
])?;
|
|
|
|
}
|
|
|
|
if table.num_records() == 1 {
|
|
|
|
println!("no guests have been launched");
|
|
|
|
} else {
|
|
|
|
println!("{}", table.to_string());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-03-23 04:07:48 +00:00
|
|
|
|
|
|
|
fn print_key_value(&self, guests: Vec<Guest>) -> Result<()> {
|
|
|
|
for guest in guests {
|
|
|
|
let kvs = proto2kv(guest)?;
|
2024-03-23 07:00:12 +00:00
|
|
|
println!("{}", kv2line(kvs),);
|
2024-03-23 04:07:48 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2024-03-15 15:59:18 +00:00
|
|
|
}
|