feature(ctl): add --format option to host status and improve cpu topology format

This commit is contained in:
Alex Zenla 2024-08-23 12:13:42 -07:00
parent adb7b29354
commit 311b771f73
No known key found for this signature in database
GPG Key ID: 067B238899B51269
6 changed files with 124 additions and 45 deletions

View File

@ -23,7 +23,7 @@ enum DeviceListFormat {
} }
#[derive(Parser)] #[derive(Parser)]
#[command(about = "List the devices on the isolation engine")] #[command(about = "List device information")]
pub struct DeviceListCommand { pub struct DeviceListCommand {
#[arg(short, long, default_value = "table", help = "Output format")] #[arg(short, long, default_value = "table", help = "Output format")]
format: DeviceListFormat, format: DeviceListFormat,

View File

@ -5,7 +5,9 @@ use comfy_table::{Cell, Table};
use krata::v1::control::{ use krata::v1::control::{
control_service_client::ControlServiceClient, GetHostCpuTopologyRequest, HostCpuTopologyClass, control_service_client::ControlServiceClient, GetHostCpuTopologyRequest, HostCpuTopologyClass,
}; };
use serde_json::Value;
use crate::format::{kv2line, proto2dynamic, proto2kv};
use tonic::{transport::Channel, Request}; use tonic::{transport::Channel, Request};
fn class_to_str(input: HostCpuTopologyClass) -> String { fn class_to_str(input: HostCpuTopologyClass) -> String {
@ -19,6 +21,11 @@ fn class_to_str(input: HostCpuTopologyClass) -> String {
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)] #[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum HostCpuTopologyFormat { enum HostCpuTopologyFormat {
Table, Table,
Json,
JsonPretty,
Jsonl,
Yaml,
KeyValue,
} }
#[derive(Parser)] #[derive(Parser)]
@ -35,24 +42,61 @@ impl HostCpuTopologyCommand {
.await? .await?
.into_inner(); .into_inner();
let mut table = Table::new(); match self.format {
table.load_preset(UTF8_FULL_CONDENSED); HostCpuTopologyFormat::Table => {
table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic); let mut table = Table::new();
table.set_header(vec!["id", "node", "socket", "core", "thread", "class"]); table.load_preset(UTF8_FULL_CONDENSED);
table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
table.set_header(vec!["id", "node", "socket", "core", "thread", "class"]);
for (i, cpu) in response.cpus.iter().enumerate() { for (i, cpu) in response.cpus.iter().enumerate() {
table.add_row(vec![ table.add_row(vec![
Cell::new(i), Cell::new(i),
Cell::new(cpu.node), Cell::new(cpu.node),
Cell::new(cpu.socket), Cell::new(cpu.socket),
Cell::new(cpu.core), Cell::new(cpu.core),
Cell::new(cpu.thread), Cell::new(cpu.thread),
Cell::new(class_to_str(cpu.class())), Cell::new(class_to_str(cpu.class())),
]); ]);
} }
if !table.is_empty() { if !table.is_empty() {
println!("{}", table); println!("{}", table);
}
}
HostCpuTopologyFormat::Json
| HostCpuTopologyFormat::JsonPretty
| HostCpuTopologyFormat::Yaml => {
let mut values = Vec::new();
for cpu in response.cpus {
let message = proto2dynamic(cpu)?;
values.push(serde_json::to_value(message)?);
}
let value = Value::Array(values);
let encoded = if self.format == HostCpuTopologyFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == HostCpuTopologyFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
};
println!("{}", encoded.trim());
}
HostCpuTopologyFormat::Jsonl => {
for cpu in response.cpus {
let message = proto2dynamic(cpu)?;
println!("{}", serde_json::to_string(&message)?);
}
}
HostCpuTopologyFormat::KeyValue => {
for cpu in response.cpus {
let kvs = proto2kv(cpu)?;
println!("{}", kv2line(kvs),);
}
}
} }
Ok(()) Ok(())

View File

@ -1,25 +0,0 @@
use anyhow::Result;
use clap::Parser;
use krata::v1::control::{control_service_client::ControlServiceClient, HostStatusRequest};
use tonic::{transport::Channel, Request};
#[derive(Parser)]
#[command(about = "Get information about the host")]
pub struct HostStatusCommand {}
impl HostStatusCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.host_status(Request::new(HostStatusRequest {}))
.await?
.into_inner();
println!("Host UUID: {}", response.host_uuid);
println!("Host Domain: {}", response.host_domid);
println!("Krata Version: {}", response.krata_version);
println!("Host IPv4: {}", response.host_ipv4);
println!("Host IPv6: {}", response.host_ipv6);
println!("Host Ethernet Address: {}", response.host_mac);
Ok(())
}
}

View File

@ -7,13 +7,13 @@ use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::host::cpu_topology::HostCpuTopologyCommand; use crate::cli::host::cpu_topology::HostCpuTopologyCommand;
use crate::cli::host::hv_console::HostHvConsoleCommand; use crate::cli::host::hv_console::HostHvConsoleCommand;
use crate::cli::host::identify::HostStatusCommand;
use crate::cli::host::idm_snoop::HostIdmSnoopCommand; use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
use crate::cli::host::status::HostStatusCommand;
pub mod cpu_topology; pub mod cpu_topology;
pub mod hv_console; pub mod hv_console;
pub mod identify;
pub mod idm_snoop; pub mod idm_snoop;
pub mod status;
#[derive(Parser)] #[derive(Parser)]
#[command(about = "Manage the host of the isolation engine")] #[command(about = "Manage the host of the isolation engine")]

View File

@ -0,0 +1,60 @@
use anyhow::Result;
use clap::{Parser, ValueEnum};
use krata::v1::control::{control_service_client::ControlServiceClient, HostStatusRequest};
use crate::format::{kv2line, proto2dynamic, proto2kv};
use tonic::{transport::Channel, Request};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum HostStatusFormat {
Simple,
Json,
JsonPretty,
Yaml,
KeyValue,
}
#[derive(Parser)]
#[command(about = "Get information about the host")]
pub struct HostStatusCommand {
#[arg(short, long, default_value = "simple", help = "Output format")]
format: HostStatusFormat,
}
impl HostStatusCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.host_status(Request::new(HostStatusRequest {}))
.await?
.into_inner();
match self.format {
HostStatusFormat::Simple => {
println!("Host UUID: {}", response.host_uuid);
println!("Host Domain: {}", response.host_domid);
println!("Krata Version: {}", response.krata_version);
println!("Host IPv4: {}", response.host_ipv4);
println!("Host IPv6: {}", response.host_ipv6);
println!("Host Ethernet Address: {}", response.host_mac);
}
HostStatusFormat::Json | HostStatusFormat::JsonPretty | HostStatusFormat::Yaml => {
let message = proto2dynamic(response)?;
let value = serde_json::to_value(message)?;
let encoded = if self.format == HostStatusFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == HostStatusFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
};
println!("{}", encoded.trim());
}
HostStatusFormat::KeyValue => {
let kvs = proto2kv(response)?;
println!("{}", kv2line(kvs),);
}
}
Ok(())
}
}

View File

@ -29,7 +29,7 @@ enum ZoneListFormat {
} }
#[derive(Parser)] #[derive(Parser)]
#[command(about = "List the zones on the isolation engine")] #[command(about = "List zone information")]
pub struct ZoneListCommand { pub struct ZoneListCommand {
#[arg(short, long, default_value = "table", help = "Output format")] #[arg(short, long, default_value = "table", help = "Output format")]
format: ZoneListFormat, format: ZoneListFormat,