mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-04 13:41:31 +00:00
feature(krata): implement network reservation list (#366)
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
pub mod device;
|
||||
pub mod host;
|
||||
pub mod image;
|
||||
pub mod network;
|
||||
pub mod zone;
|
||||
|
||||
use crate::cli::device::DeviceCommand;
|
||||
@ -14,6 +15,7 @@ use krata::{
|
||||
events::EventStream,
|
||||
v1::control::{control_service_client::ControlServiceClient, ResolveZoneIdRequest},
|
||||
};
|
||||
use network::NetworkCommand;
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
#[derive(Parser)]
|
||||
@ -36,6 +38,7 @@ pub struct ControlCommand {
|
||||
pub enum ControlCommands {
|
||||
Zone(ZoneCommand),
|
||||
Image(ImageCommand),
|
||||
Network(NetworkCommand),
|
||||
Device(DeviceCommand),
|
||||
Host(HostCommand),
|
||||
}
|
||||
@ -57,6 +60,8 @@ impl ControlCommands {
|
||||
match self {
|
||||
ControlCommands::Zone(zone) => zone.run(client, events).await,
|
||||
|
||||
ControlCommands::Network(network) => network.run(client, events).await,
|
||||
|
||||
ControlCommands::Image(image) => image.run(client, events).await,
|
||||
|
||||
ControlCommands::Device(device) => device.run(client, events).await,
|
||||
|
43
crates/ctl/src/cli/network/mod.rs
Normal file
43
crates/ctl/src/cli/network/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use reservation::NetworkReservationCommand;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use krata::events::EventStream;
|
||||
use krata::v1::control::control_service_client::ControlServiceClient;
|
||||
|
||||
pub mod reservation;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "Manage the network on the isolation engine")]
|
||||
pub struct NetworkCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: NetworkCommands,
|
||||
}
|
||||
|
||||
impl NetworkCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
self.subcommand.run(client, events).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum NetworkCommands {
|
||||
Reservation(NetworkReservationCommand),
|
||||
}
|
||||
|
||||
impl NetworkCommands {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
NetworkCommands::Reservation(reservation) => reservation.run(client, events).await,
|
||||
}
|
||||
}
|
||||
}
|
125
crates/ctl/src/cli/network/reservation/list.rs
Normal file
125
crates/ctl/src/cli/network/reservation/list.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use comfy_table::{presets::UTF8_FULL_CONDENSED, Cell, Table};
|
||||
use krata::{
|
||||
events::EventStream,
|
||||
v1::{
|
||||
common::NetworkReservation,
|
||||
control::{control_service_client::ControlServiceClient, ListNetworkReservationsRequest},
|
||||
},
|
||||
};
|
||||
|
||||
use serde_json::Value;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use crate::format::{kv2line, proto2dynamic, proto2kv};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum NetworkReservationListFormat {
|
||||
Table,
|
||||
Json,
|
||||
JsonPretty,
|
||||
Jsonl,
|
||||
Yaml,
|
||||
KeyValue,
|
||||
Simple,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "List network reservation information")]
|
||||
pub struct NetworkReservationListCommand {
|
||||
#[arg(short, long, default_value = "table", help = "Output format")]
|
||||
format: NetworkReservationListFormat,
|
||||
}
|
||||
|
||||
impl NetworkReservationListCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
mut client: ControlServiceClient<Channel>,
|
||||
_events: EventStream,
|
||||
) -> Result<()> {
|
||||
let reply = client
|
||||
.list_network_reservations(ListNetworkReservationsRequest {})
|
||||
.await?
|
||||
.into_inner();
|
||||
let mut reservations = reply.reservations;
|
||||
|
||||
reservations.sort_by(|a, b| a.uuid.cmp(&b.uuid));
|
||||
|
||||
match self.format {
|
||||
NetworkReservationListFormat::Table => {
|
||||
self.print_reservations_table(reservations)?;
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Simple => {
|
||||
for reservation in reservations {
|
||||
println!(
|
||||
"{}\t{}\t{}\t{}",
|
||||
reservation.uuid, reservation.ipv4, reservation.ipv6, reservation.mac
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Json
|
||||
| NetworkReservationListFormat::JsonPretty
|
||||
| NetworkReservationListFormat::Yaml => {
|
||||
let mut values = Vec::new();
|
||||
for device in reservations {
|
||||
let message = proto2dynamic(device)?;
|
||||
values.push(serde_json::to_value(message)?);
|
||||
}
|
||||
let value = Value::Array(values);
|
||||
let encoded = if self.format == NetworkReservationListFormat::JsonPretty {
|
||||
serde_json::to_string_pretty(&value)?
|
||||
} else if self.format == NetworkReservationListFormat::Yaml {
|
||||
serde_yaml::to_string(&value)?
|
||||
} else {
|
||||
serde_json::to_string(&value)?
|
||||
};
|
||||
println!("{}", encoded.trim());
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Jsonl => {
|
||||
for device in reservations {
|
||||
let message = proto2dynamic(device)?;
|
||||
println!("{}", serde_json::to_string(&message)?);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::KeyValue => {
|
||||
self.print_key_value(reservations)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_reservations_table(&self, reservations: Vec<NetworkReservation>) -> Result<()> {
|
||||
let mut table = Table::new();
|
||||
table.load_preset(UTF8_FULL_CONDENSED);
|
||||
table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
|
||||
table.set_header(vec!["uuid", "ipv4", "ipv6", "mac"]);
|
||||
for reservation in reservations {
|
||||
table.add_row(vec![
|
||||
Cell::new(reservation.uuid),
|
||||
Cell::new(reservation.ipv4),
|
||||
Cell::new(reservation.ipv6),
|
||||
Cell::new(reservation.mac),
|
||||
]);
|
||||
}
|
||||
if table.is_empty() {
|
||||
println!("no network reservations found");
|
||||
} else {
|
||||
println!("{}", table);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_key_value(&self, reservations: Vec<NetworkReservation>) -> Result<()> {
|
||||
for reservation in reservations {
|
||||
let kvs = proto2kv(reservation)?;
|
||||
println!("{}", kv2line(kvs));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
43
crates/ctl/src/cli/network/reservation/mod.rs
Normal file
43
crates/ctl/src/cli/network/reservation/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use list::NetworkReservationListCommand;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use krata::events::EventStream;
|
||||
use krata::v1::control::control_service_client::ControlServiceClient;
|
||||
|
||||
pub mod list;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "Manage network reservations")]
|
||||
pub struct NetworkReservationCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: NetworkReservationCommands,
|
||||
}
|
||||
|
||||
impl NetworkReservationCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
self.subcommand.run(client, events).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum NetworkReservationCommands {
|
||||
List(NetworkReservationListCommand),
|
||||
}
|
||||
|
||||
impl NetworkReservationCommands {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
NetworkReservationCommands::List(list) => list.run(client, events).await,
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user