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)]
#[command(about = "List the devices on the isolation engine")]
#[command(about = "List device information")]
pub struct DeviceListCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: DeviceListFormat,

View File

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

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::hv_console::HostHvConsoleCommand;
use crate::cli::host::identify::HostStatusCommand;
use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
use crate::cli::host::status::HostStatusCommand;
pub mod cpu_topology;
pub mod hv_console;
pub mod identify;
pub mod idm_snoop;
pub mod status;
#[derive(Parser)]
#[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)]
#[command(about = "List the zones on the isolation engine")]
#[command(about = "List zone information")]
pub struct ZoneListCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: ZoneListFormat,