mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-04 07:39:39 +00:00 
			
		
		
		
	feature(ctl): add --format option to host status and improve cpu topology format (#355)
This commit is contained in:
		@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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(())
 | 
			
		||||
 | 
			
		||||
@ -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(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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")]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								crates/ctl/src/cli/host/status.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								crates/ctl/src/cli/host/status.rs
									
									
									
									
									
										Normal 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(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user