feature(kratactl): rework cli to use subcommands (#268)

This commit is contained in:
Alex Zenla
2024-07-18 23:13:29 -07:00
committed by GitHub
parent 04665ce690
commit 75901233b1
25 changed files with 418 additions and 249 deletions

View File

@ -1,46 +0,0 @@
use anyhow::Result;
use clap::Parser;
use krata::v1::control::{control_service_client::ControlServiceClient, HostCpuTopologyRequest};
use tonic::{transport::Channel, Request};
fn class_to_str(input: i32) -> String {
match input {
0 => "Standard".to_string(),
1 => "Performance".to_string(),
2 => "Efficiency".to_string(),
_ => "???".to_string(),
}
}
#[derive(Parser)]
#[command(about = "Display information about a host's CPU topology")]
pub struct CpuTopologyCommand {}
impl CpuTopologyCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
println!(
"{0:<10} {1:<10} {2:<10} {3:<10} {4:<10} {5:<10}",
"CPUID", "Node", "Socket", "Core", "Thread", "Class"
);
let response = client
.get_host_cpu_topology(Request::new(HostCpuTopologyRequest {}))
.await?
.into_inner();
for (i, cpu) in response.cpus.iter().enumerate() {
println!(
"{0:<10} {1:<10} {2:<10} {3:<10} {4:<10} {5:<10}",
i,
cpu.node,
cpu.socket,
cpu.core,
cpu.thread,
class_to_str(cpu.class)
);
}
Ok(())
}
}

View File

@ -12,7 +12,7 @@ use tonic::transport::Channel;
use crate::format::{kv2line, proto2dynamic, proto2kv};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum ListDevicesFormat {
enum DeviceListFormat {
Table,
Json,
JsonPretty,
@ -24,12 +24,12 @@ enum ListDevicesFormat {
#[derive(Parser)]
#[command(about = "List the devices on the isolation engine")]
pub struct ListDevicesCommand {
pub struct DeviceListCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: ListDevicesFormat,
format: DeviceListFormat,
}
impl ListDevicesCommand {
impl DeviceListCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,
@ -44,26 +44,26 @@ impl ListDevicesCommand {
devices.sort_by(|a, b| a.name.cmp(&b.name));
match self.format {
ListDevicesFormat::Table => {
DeviceListFormat::Table => {
self.print_devices_table(devices)?;
}
ListDevicesFormat::Simple => {
DeviceListFormat::Simple => {
for device in devices {
println!("{}\t{}\t{}", device.name, device.claimed, device.owner);
}
}
ListDevicesFormat::Json | ListDevicesFormat::JsonPretty | ListDevicesFormat::Yaml => {
DeviceListFormat::Json | DeviceListFormat::JsonPretty | DeviceListFormat::Yaml => {
let mut values = Vec::new();
for device in devices {
let message = proto2dynamic(device)?;
values.push(serde_json::to_value(message)?);
}
let value = Value::Array(values);
let encoded = if self.format == ListDevicesFormat::JsonPretty {
let encoded = if self.format == DeviceListFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == ListDevicesFormat::Yaml {
} else if self.format == DeviceListFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
@ -71,14 +71,14 @@ impl ListDevicesCommand {
println!("{}", encoded.trim());
}
ListDevicesFormat::Jsonl => {
DeviceListFormat::Jsonl => {
for device in devices {
let message = proto2dynamic(device)?;
println!("{}", serde_json::to_string(&message)?);
}
}
ListDevicesFormat::KeyValue => {
DeviceListFormat::KeyValue => {
self.print_key_value(devices)?;
}
}

View File

@ -0,0 +1,44 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use tonic::transport::Channel;
use krata::events::EventStream;
use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::device::list::DeviceListCommand;
pub mod list;
#[derive(Parser)]
#[command(about = "Manage the devices on the isolation engine")]
pub struct DeviceCommand {
#[command(subcommand)]
subcommand: DeviceCommands,
}
impl DeviceCommand {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
self.subcommand.run(client, events).await
}
}
#[derive(Subcommand)]
pub enum DeviceCommands {
List(DeviceListCommand),
}
impl DeviceCommands {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
match self {
DeviceCommands::List(list) => list.run(client, events).await,
}
}
}

View File

@ -0,0 +1,60 @@
use anyhow::Result;
use clap::{Parser, ValueEnum};
use comfy_table::presets::UTF8_FULL_CONDENSED;
use comfy_table::{Cell, Table};
use krata::v1::control::{
control_service_client::ControlServiceClient, HostCpuTopologyClass, HostCpuTopologyRequest,
};
use tonic::{transport::Channel, Request};
fn class_to_str(input: HostCpuTopologyClass) -> String {
match input {
HostCpuTopologyClass::Standard => "Standard".to_string(),
HostCpuTopologyClass::Performance => "Performance".to_string(),
HostCpuTopologyClass::Efficiency => "Efficiency".to_string(),
}
}
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum HostCpuTopologyFormat {
Table,
}
#[derive(Parser)]
#[command(about = "Display information about the host CPU topology")]
pub struct HostCpuTopologyCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: HostCpuTopologyFormat,
}
impl HostCpuTopologyCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.get_host_cpu_topology(Request::new(HostCpuTopologyRequest {}))
.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"]);
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);
}
Ok(())
}
}

View File

@ -6,9 +6,9 @@ use tonic::{transport::Channel, Request};
#[derive(Parser)]
#[command(about = "Identify information about the host")]
pub struct IdentifyHostCommand {}
pub struct HostIdentifyCommand {}
impl IdentifyHostCommand {
impl HostIdentifyCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.identify_host(Request::new(IdentifyHostRequest {}))

View File

@ -15,7 +15,7 @@ use tonic::transport::Channel;
use crate::format::{kv2line, proto2dynamic, value2kv};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum IdmSnoopFormat {
enum HostIdmSnoopFormat {
Simple,
Jsonl,
KeyValue,
@ -23,12 +23,12 @@ enum IdmSnoopFormat {
#[derive(Parser)]
#[command(about = "Snoop on the IDM bus")]
pub struct IdmSnoopCommand {
pub struct HostIdmSnoopCommand {
#[arg(short, long, default_value = "simple", help = "Output format")]
format: IdmSnoopFormat,
format: HostIdmSnoopFormat,
}
impl IdmSnoopCommand {
impl HostIdmSnoopCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,
@ -43,16 +43,16 @@ impl IdmSnoopCommand {
};
match self.format {
IdmSnoopFormat::Simple => {
HostIdmSnoopFormat::Simple => {
self.print_simple(line)?;
}
IdmSnoopFormat::Jsonl => {
HostIdmSnoopFormat::Jsonl => {
let encoded = serde_json::to_string(&line)?;
println!("{}", encoded.trim());
}
IdmSnoopFormat::KeyValue => {
HostIdmSnoopFormat::KeyValue => {
self.print_key_value(line)?;
}
}

View File

@ -0,0 +1,54 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use tonic::transport::Channel;
use krata::events::EventStream;
use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::host::cpu_topology::HostCpuTopologyCommand;
use crate::cli::host::identify::HostIdentifyCommand;
use crate::cli::host::idm_snoop::HostIdmSnoopCommand;
pub mod cpu_topology;
pub mod identify;
pub mod idm_snoop;
#[derive(Parser)]
#[command(about = "Manage the host of the isolation engine")]
pub struct HostCommand {
#[command(subcommand)]
subcommand: HostCommands,
}
impl HostCommand {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
self.subcommand.run(client, events).await
}
}
#[derive(Subcommand)]
pub enum HostCommands {
CpuTopology(HostCpuTopologyCommand),
Identify(HostIdentifyCommand),
IdmSnoop(HostIdmSnoopCommand),
}
impl HostCommands {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
match self {
HostCommands::CpuTopology(cpu_topology) => cpu_topology.run(client).await,
HostCommands::Identify(identify) => identify.run(client).await,
HostCommands::IdmSnoop(snoop) => snoop.run(client, events).await,
}
}
}

View File

@ -0,0 +1,44 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use tonic::transport::Channel;
use krata::events::EventStream;
use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::image::pull::ImagePullCommand;
pub mod pull;
#[derive(Parser)]
#[command(about = "Manage the images on the isolation engine")]
pub struct ImageCommand {
#[command(subcommand)]
subcommand: ImageCommands,
}
impl ImageCommand {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
self.subcommand.run(client, events).await
}
}
#[derive(Subcommand)]
pub enum ImageCommands {
Pull(ImagePullCommand),
}
impl ImageCommands {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
_events: EventStream,
) -> Result<()> {
match self {
ImageCommands::Pull(pull) => pull.run(client).await,
}
}
}

View File

@ -10,7 +10,7 @@ use tonic::transport::Channel;
use crate::pull::pull_interactive_progress;
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
pub enum PullImageFormat {
pub enum ImagePullImageFormat {
Squashfs,
Erofs,
Tar,
@ -18,24 +18,24 @@ pub enum PullImageFormat {
#[derive(Parser)]
#[command(about = "Pull an image into the cache")]
pub struct PullCommand {
pub struct ImagePullCommand {
#[arg(help = "Image name")]
image: String,
#[arg(short = 's', long, default_value = "squashfs", help = "Image format")]
image_format: PullImageFormat,
image_format: ImagePullImageFormat,
#[arg(short = 'o', long, help = "Overwrite image cache")]
overwrite_cache: bool,
}
impl PullCommand {
impl ImagePullCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let response = client
.pull_image(PullImageRequest {
image: self.image.clone(),
format: match self.image_format {
PullImageFormat::Squashfs => OciImageFormat::Squashfs.into(),
PullImageFormat::Erofs => OciImageFormat::Erofs.into(),
PullImageFormat::Tar => OciImageFormat::Tar.into(),
ImagePullImageFormat::Squashfs => OciImageFormat::Squashfs.into(),
ImagePullImageFormat::Erofs => OciImageFormat::Erofs.into(),
ImagePullImageFormat::Tar => OciImageFormat::Tar.into(),
},
overwrite_cache: self.overwrite_cache,
})

View File

@ -1,21 +1,14 @@
pub mod attach;
pub mod cpu_topology;
pub mod destroy;
pub mod exec;
pub mod identify_host;
pub mod idm_snoop;
pub mod launch;
pub mod list;
pub mod list_devices;
pub mod logs;
pub mod metrics;
pub mod pull;
pub mod resolve;
pub mod top;
pub mod watch;
pub mod device;
pub mod host;
pub mod image;
pub mod zone;
use crate::cli::device::DeviceCommand;
use crate::cli::host::HostCommand;
use crate::cli::image::ImageCommand;
use crate::cli::zone::ZoneCommand;
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use clap::Parser;
use krata::{
client::ControlClientProvider,
events::EventStream,
@ -23,14 +16,6 @@ use krata::{
};
use tonic::{transport::Channel, Request};
use self::{
attach::AttachCommand, cpu_topology::CpuTopologyCommand, destroy::DestroyCommand,
exec::ExecCommand, identify_host::IdentifyHostCommand, idm_snoop::IdmSnoopCommand,
launch::LaunchCommand, list::ListCommand, list_devices::ListDevicesCommand, logs::LogsCommand,
metrics::MetricsCommand, pull::PullCommand, resolve::ResolveCommand, top::TopCommand,
watch::WatchCommand,
};
#[derive(Parser)]
#[command(version, about = "Control the krata isolation engine")]
pub struct ControlCommand {
@ -43,26 +28,15 @@ pub struct ControlCommand {
connection: String,
#[command(subcommand)]
command: Commands,
command: ControlCommands,
}
#[derive(Subcommand)]
pub enum Commands {
Launch(LaunchCommand),
Destroy(DestroyCommand),
List(ListCommand),
ListDevices(ListDevicesCommand),
Attach(AttachCommand),
Pull(PullCommand),
Logs(LogsCommand),
Watch(WatchCommand),
Resolve(ResolveCommand),
Metrics(MetricsCommand),
IdmSnoop(IdmSnoopCommand),
Top(TopCommand),
IdentifyHost(IdentifyHostCommand),
Exec(ExecCommand),
CpuTopology(CpuTopologyCommand),
#[derive(Parser)]
pub enum ControlCommands {
Zone(ZoneCommand),
Image(ImageCommand),
Device(DeviceCommand),
Host(HostCommand),
}
impl ControlCommand {
@ -71,67 +45,14 @@ impl ControlCommand {
let events = EventStream::open(client.clone()).await?;
match self.command {
Commands::Launch(launch) => {
launch.run(client, events).await?;
}
ControlCommands::Zone(zone) => zone.run(client, events).await,
Commands::Destroy(destroy) => {
destroy.run(client, events).await?;
}
ControlCommands::Image(image) => image.run(client, events).await,
Commands::Attach(attach) => {
attach.run(client, events).await?;
}
ControlCommands::Device(device) => device.run(client, events).await,
Commands::Logs(logs) => {
logs.run(client, events).await?;
}
Commands::List(list) => {
list.run(client, events).await?;
}
Commands::Watch(watch) => {
watch.run(events).await?;
}
Commands::Resolve(resolve) => {
resolve.run(client).await?;
}
Commands::Metrics(metrics) => {
metrics.run(client, events).await?;
}
Commands::IdmSnoop(snoop) => {
snoop.run(client, events).await?;
}
Commands::Top(top) => {
top.run(client, events).await?;
}
Commands::Pull(pull) => {
pull.run(client).await?;
}
Commands::IdentifyHost(identify) => {
identify.run(client).await?;
}
Commands::Exec(exec) => {
exec.run(client).await?;
}
Commands::ListDevices(list) => {
list.run(client, events).await?;
}
Commands::CpuTopology(cpu_topology) => {
cpu_topology.run(client).await?;
}
ControlCommands::Host(snoop) => snoop.run(client, events).await,
}
Ok(())
}
}

View File

@ -7,16 +7,16 @@ use tonic::transport::Channel;
use crate::console::StdioConsoleStream;
use super::resolve_zone;
use crate::cli::resolve_zone;
#[derive(Parser)]
#[command(about = "Attach to the zone console")]
pub struct AttachCommand {
pub struct ZoneAttachCommand {
#[arg(help = "Zone to attach to, either the name or the uuid")]
zone: String,
}
impl AttachCommand {
impl ZoneAttachCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,

View File

@ -18,7 +18,7 @@ use crate::cli::resolve_zone;
#[derive(Parser)]
#[command(about = "Destroy a zone")]
pub struct DestroyCommand {
pub struct ZoneDestroyCommand {
#[arg(
short = 'W',
long,
@ -29,7 +29,7 @@ pub struct DestroyCommand {
zone: String,
}
impl DestroyCommand {
impl ZoneDestroyCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,

View File

@ -12,11 +12,11 @@ use tonic::{transport::Channel, Request};
use crate::console::StdioConsoleStream;
use super::resolve_zone;
use crate::cli::resolve_zone;
#[derive(Parser)]
#[command(about = "Execute a command inside the zone")]
pub struct ExecCommand {
pub struct ZoneExecCommand {
#[arg[short, long, help = "Environment variables"]]
env: Option<Vec<String>>,
#[arg(short = 'w', long, help = "Working directory")]
@ -31,7 +31,7 @@ pub struct ExecCommand {
command: Vec<String>,
}
impl ExecCommand {
impl ZoneExecCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let zone_id: String = resolve_zone(&mut client, &self.zone).await?;
let initial = ExecZoneRequest {

View File

@ -29,7 +29,7 @@ pub enum LaunchImageFormat {
#[derive(Parser)]
#[command(about = "Launch a new zone")]
pub struct LaunchCommand {
pub struct ZoneLaunchCommand {
#[arg(long, default_value = "squashfs", help = "Image format")]
image_format: LaunchImageFormat,
#[arg(long, help = "Overwrite image cache on pull")]
@ -77,7 +77,7 @@ pub struct LaunchCommand {
command: Vec<String>,
}
impl LaunchCommand {
impl ZoneLaunchCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,

View File

@ -17,7 +17,7 @@ use tonic::{transport::Channel, Request};
use crate::format::{kv2line, proto2dynamic, proto2kv, zone_simple_line, zone_status_text};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum ListFormat {
enum ZoneListFormat {
Table,
Json,
JsonPretty,
@ -29,14 +29,14 @@ enum ListFormat {
#[derive(Parser)]
#[command(about = "List the zones on the isolation engine")]
pub struct ListCommand {
pub struct ZoneListCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: ListFormat,
format: ZoneListFormat,
#[arg(help = "Limit to a single zone, either the name or the uuid")]
zone: Option<String>,
}
impl ListCommand {
impl ZoneListCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,
@ -69,26 +69,26 @@ impl ListCommand {
});
match self.format {
ListFormat::Table => {
ZoneListFormat::Table => {
self.print_zone_table(zones)?;
}
ListFormat::Simple => {
ZoneListFormat::Simple => {
for zone in zones {
println!("{}", zone_simple_line(&zone));
}
}
ListFormat::Json | ListFormat::JsonPretty | ListFormat::Yaml => {
ZoneListFormat::Json | ZoneListFormat::JsonPretty | ZoneListFormat::Yaml => {
let mut values = Vec::new();
for zone in zones {
let message = proto2dynamic(zone)?;
values.push(serde_json::to_value(message)?);
}
let value = Value::Array(values);
let encoded = if self.format == ListFormat::JsonPretty {
let encoded = if self.format == ZoneListFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == ListFormat::Yaml {
} else if self.format == ZoneListFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
@ -96,14 +96,14 @@ impl ListCommand {
println!("{}", encoded.trim());
}
ListFormat::Jsonl => {
ZoneListFormat::Jsonl => {
for zone in zones {
let message = proto2dynamic(zone)?;
println!("{}", serde_json::to_string(&message)?);
}
}
ListFormat::KeyValue => {
ZoneListFormat::KeyValue => {
self.print_key_value(zones)?;
}
}

View File

@ -12,18 +12,18 @@ use tonic::transport::Channel;
use crate::console::StdioConsoleStream;
use super::resolve_zone;
use crate::cli::resolve_zone;
#[derive(Parser)]
#[command(about = "View the logs of a zone")]
pub struct LogsCommand {
pub struct ZoneLogsCommand {
#[arg(short, long, help = "Follow output from the zone")]
follow: bool,
#[arg(help = "Zone to show logs for, either the name or the uuid")]
zone: String,
}
impl LogsCommand {
impl ZoneLogsCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,

View File

@ -12,10 +12,10 @@ use tonic::transport::Channel;
use crate::format::{kv2line, metrics_flat, metrics_tree, proto2dynamic};
use super::resolve_zone;
use crate::cli::resolve_zone;
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum MetricsFormat {
enum ZoneMetricsFormat {
Tree,
Json,
JsonPretty,
@ -25,14 +25,14 @@ enum MetricsFormat {
#[derive(Parser)]
#[command(about = "Read metrics from the zone")]
pub struct MetricsCommand {
pub struct ZoneMetricsCommand {
#[arg(short, long, default_value = "tree", help = "Output format")]
format: MetricsFormat,
format: ZoneMetricsFormat,
#[arg(help = "Zone to read metrics for, either the name or the uuid")]
zone: String,
}
impl MetricsCommand {
impl ZoneMetricsCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,
@ -46,15 +46,15 @@ impl MetricsCommand {
.root
.unwrap_or_default();
match self.format {
MetricsFormat::Tree => {
ZoneMetricsFormat::Tree => {
self.print_metrics_tree(root)?;
}
MetricsFormat::Json | MetricsFormat::JsonPretty | MetricsFormat::Yaml => {
ZoneMetricsFormat::Json | ZoneMetricsFormat::JsonPretty | ZoneMetricsFormat::Yaml => {
let value = serde_json::to_value(proto2dynamic(root)?)?;
let encoded = if self.format == MetricsFormat::JsonPretty {
let encoded = if self.format == ZoneMetricsFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == MetricsFormat::Yaml {
} else if self.format == ZoneMetricsFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
@ -62,7 +62,7 @@ impl MetricsCommand {
println!("{}", encoded.trim());
}
MetricsFormat::KeyValue => {
ZoneMetricsFormat::KeyValue => {
self.print_key_value(root)?;
}
}

View File

@ -0,0 +1,89 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use tonic::transport::Channel;
use krata::events::EventStream;
use krata::v1::control::control_service_client::ControlServiceClient;
use crate::cli::zone::attach::ZoneAttachCommand;
use crate::cli::zone::destroy::ZoneDestroyCommand;
use crate::cli::zone::exec::ZoneExecCommand;
use crate::cli::zone::launch::ZoneLaunchCommand;
use crate::cli::zone::list::ZoneListCommand;
use crate::cli::zone::logs::ZoneLogsCommand;
use crate::cli::zone::metrics::ZoneMetricsCommand;
use crate::cli::zone::resolve::ZoneResolveCommand;
use crate::cli::zone::top::ZoneTopCommand;
use crate::cli::zone::watch::ZoneWatchCommand;
pub mod attach;
pub mod destroy;
pub mod exec;
pub mod launch;
pub mod list;
pub mod logs;
pub mod metrics;
pub mod resolve;
pub mod top;
pub mod watch;
#[derive(Parser)]
#[command(about = "Manage the zones on the isolation engine")]
pub struct ZoneCommand {
#[command(subcommand)]
subcommand: ZoneCommands,
}
impl ZoneCommand {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
self.subcommand.run(client, events).await
}
}
#[derive(Subcommand)]
pub enum ZoneCommands {
Attach(ZoneAttachCommand),
List(ZoneListCommand),
Launch(ZoneLaunchCommand),
Destroy(ZoneDestroyCommand),
Exec(ZoneExecCommand),
Logs(ZoneLogsCommand),
Metrics(ZoneMetricsCommand),
Resolve(ZoneResolveCommand),
Top(ZoneTopCommand),
Watch(ZoneWatchCommand),
}
impl ZoneCommands {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
events: EventStream,
) -> Result<()> {
match self {
ZoneCommands::Launch(launch) => launch.run(client, events).await,
ZoneCommands::Destroy(destroy) => destroy.run(client, events).await,
ZoneCommands::Attach(attach) => attach.run(client, events).await,
ZoneCommands::Logs(logs) => logs.run(client, events).await,
ZoneCommands::List(list) => list.run(client, events).await,
ZoneCommands::Watch(watch) => watch.run(events).await,
ZoneCommands::Resolve(resolve) => resolve.run(client).await,
ZoneCommands::Metrics(metrics) => metrics.run(client, events).await,
ZoneCommands::Top(top) => top.run(client, events).await,
ZoneCommands::Exec(exec) => exec.run(client).await,
}
}
}

View File

@ -6,12 +6,12 @@ use tonic::{transport::Channel, Request};
#[derive(Parser)]
#[command(about = "Resolve a zone name to a uuid")]
pub struct ResolveCommand {
pub struct ZoneResolveCommand {
#[arg(help = "Zone name")]
zone: String,
}
impl ResolveCommand {
impl ZoneResolveCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let reply = client
.resolve_zone(Request::new(ResolveZoneRequest {

View File

@ -32,11 +32,11 @@ use crate::{
#[derive(Parser)]
#[command(about = "Dashboard for running zones")]
pub struct TopCommand {}
pub struct ZoneTopCommand {}
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
impl TopCommand {
impl ZoneTopCommand {
pub async fn run(
self,
client: ControlServiceClient<Channel>,
@ -44,14 +44,14 @@ impl TopCommand {
) -> Result<()> {
let collector = MultiMetricCollector::new(client, events, Duration::from_millis(200))?;
let collector = collector.launch().await?;
let mut tui = TopCommand::init()?;
let mut app = TopApp {
let mut tui = ZoneTopCommand::init()?;
let mut app = ZoneTopApp {
metrics: MultiMetricState { zones: vec![] },
exit: false,
table: TableState::new(),
};
app.run(collector, &mut tui).await?;
TopCommand::restore()?;
ZoneTopCommand::restore()?;
Ok(())
}
@ -68,13 +68,13 @@ impl TopCommand {
}
}
pub struct TopApp {
pub struct ZoneTopApp {
table: TableState,
metrics: MultiMetricState,
exit: bool,
}
impl TopApp {
impl ZoneTopApp {
pub async fn run(
&mut self,
mut collector: MultiMetricCollectorHandle,
@ -136,7 +136,7 @@ impl TopApp {
}
}
impl Widget for &mut TopApp {
impl Widget for &mut ZoneTopApp {
fn render(self, area: Rect, buf: &mut Buffer) {
let title = Title::from(" krata isolation engine ".bold());
let instructions = Title::from(vec![" Quit ".into(), "<Q> ".blue().bold()]);

View File

@ -10,7 +10,7 @@ use serde_json::Value;
use crate::format::{kv2line, proto2dynamic, proto2kv, zone_simple_line};
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum WatchFormat {
enum ZoneWatchFormat {
Simple,
Json,
KeyValue,
@ -18,12 +18,12 @@ enum WatchFormat {
#[derive(Parser)]
#[command(about = "Watch for zone changes")]
pub struct WatchCommand {
pub struct ZoneWatchCommand {
#[arg(short, long, default_value = "simple", help = "Output format")]
format: WatchFormat,
format: ZoneWatchFormat,
}
impl WatchCommand {
impl ZoneWatchCommand {
pub async fn run(self, events: EventStream) -> Result<()> {
let mut stream = events.subscribe();
loop {
@ -37,13 +37,13 @@ impl WatchCommand {
fn print_event(&self, typ: &str, event: impl ReflectMessage, zone: Option<Zone>) -> Result<()> {
match self.format {
WatchFormat::Simple => {
ZoneWatchFormat::Simple => {
if let Some(zone) = zone {
println!("{}", zone_simple_line(&zone));
}
}
WatchFormat::Json => {
ZoneWatchFormat::Json => {
let message = proto2dynamic(event)?;
let mut value = serde_json::to_value(&message)?;
if let Value::Object(ref mut map) = value {
@ -52,7 +52,7 @@ impl WatchCommand {
println!("{}", serde_json::to_string(&value)?);
}
WatchFormat::KeyValue => {
ZoneWatchFormat::KeyValue => {
let mut map = proto2kv(event)?;
map.insert("event.type".to_string(), typ.to_string());
println!("{}", kv2line(map),);

View File

@ -205,9 +205,9 @@ message ListDevicesReply {
}
enum HostCpuTopologyClass {
CPU_CLASS_STANDARD = 0;
CPU_CLASS_PERFORMANCE = 1;
CPU_CLASS_EFFICIENCY = 2;
HOST_CPU_TOPOLOGY_CLASS_STANDARD = 0;
HOST_CPU_TOPOLOGY_CLASS_PERFORMANCE = 1;
HOST_CPU_TOPOLOGY_CLASS_EFFICIENCY = 2;
}
message HostCpuTopologyInfo {