mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
krata: reconcile improvements and better kratactl error experience
This commit is contained in:
@ -94,7 +94,12 @@ async fn wait_guest_started(id: &str, events: EventStream) -> Result<()> {
|
||||
};
|
||||
|
||||
if let Some(ref error) = state.error_info {
|
||||
error!("guest error: {}", error.message);
|
||||
if state.status() == GuestStatus::Failed {
|
||||
error!("launch failed: {}", error.message);
|
||||
std::process::exit(1);
|
||||
} else {
|
||||
error!("guest error: {}", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
if state.status() == GuestStatus::Destroyed {
|
||||
|
@ -11,14 +11,13 @@ use tonic::{transport::Channel, Request};
|
||||
|
||||
use crate::{
|
||||
events::EventStream,
|
||||
format::{proto2dynamic, proto2kv},
|
||||
format::{kv2line, proto2dynamic, proto2kv},
|
||||
};
|
||||
|
||||
use super::pretty::guest_state_text;
|
||||
|
||||
#[derive(ValueEnum, Clone, Default, Debug, PartialEq, Eq)]
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum ListFormat {
|
||||
#[default]
|
||||
CliTable,
|
||||
Json,
|
||||
JsonPretty,
|
||||
@ -29,7 +28,7 @@ enum ListFormat {
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct ListCommand {
|
||||
#[arg(short, long)]
|
||||
#[arg(short, long, default_value = "cli-table")]
|
||||
format: ListFormat,
|
||||
}
|
||||
|
||||
@ -87,13 +86,15 @@ impl ListCommand {
|
||||
table.push_row(&header)?;
|
||||
for guest in guests {
|
||||
let ipv4 = guest
|
||||
.network
|
||||
.state
|
||||
.as_ref()
|
||||
.and_then(|x| x.network.as_ref())
|
||||
.map(|x| x.ipv4.as_str())
|
||||
.unwrap_or("unknown");
|
||||
let ipv6 = guest
|
||||
.network
|
||||
.state
|
||||
.as_ref()
|
||||
.and_then(|x| x.network.as_ref())
|
||||
.map(|x| x.ipv6.as_str())
|
||||
.unwrap_or("unknown");
|
||||
let Some(spec) = guest.spec else {
|
||||
@ -112,7 +113,7 @@ impl ListCommand {
|
||||
table.push_row_string(&vec![
|
||||
spec.name,
|
||||
guest.id,
|
||||
format!("{}", guest_state_text(guest.state.unwrap_or_default())),
|
||||
format!("{}", guest_state_text(guest.state.as_ref())),
|
||||
ipv4.to_string(),
|
||||
ipv6.to_string(),
|
||||
image,
|
||||
@ -129,13 +130,7 @@ impl ListCommand {
|
||||
fn print_key_value(&self, guests: Vec<Guest>) -> Result<()> {
|
||||
for guest in guests {
|
||||
let kvs = proto2kv(guest)?;
|
||||
println!(
|
||||
"{}",
|
||||
kvs.iter()
|
||||
.map(|(k, v)| format!("{}={}", k, v))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
);
|
||||
println!("{}", kv2line(kvs),);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,17 +2,19 @@ use krata::common::{GuestState, GuestStatus};
|
||||
|
||||
pub fn guest_status_text(status: GuestStatus) -> String {
|
||||
match status {
|
||||
GuestStatus::Destroy => "destroying",
|
||||
GuestStatus::Destroyed => "destroyed",
|
||||
GuestStatus::Start => "starting",
|
||||
GuestStatus::Exited => "exited",
|
||||
GuestStatus::Starting => "starting",
|
||||
GuestStatus::Started => "started",
|
||||
GuestStatus::Destroying => "destroying",
|
||||
GuestStatus::Destroyed => "destroyed",
|
||||
GuestStatus::Exited => "exited",
|
||||
GuestStatus::Failed => "failed",
|
||||
_ => "unknown",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn guest_state_text(state: GuestState) -> String {
|
||||
pub fn guest_state_text(state: Option<&GuestState>) -> String {
|
||||
let state = state.cloned().unwrap_or_default();
|
||||
let mut text = guest_status_text(state.status());
|
||||
|
||||
if let Some(exit) = state.exit_info {
|
||||
|
@ -1,11 +1,27 @@
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use krata::control::watch_events_reply::Event;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use krata::{common::Guest, control::watch_events_reply::Event};
|
||||
use prost_reflect::ReflectMessage;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{cli::pretty::guest_status_text, events::EventStream};
|
||||
use crate::{
|
||||
cli::pretty::guest_state_text,
|
||||
events::EventStream,
|
||||
format::{kv2line, proto2dynamic, proto2kv},
|
||||
};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum WatchFormat {
|
||||
Simple,
|
||||
Json,
|
||||
KeyValue,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct WatchCommand {}
|
||||
pub struct WatchCommand {
|
||||
#[arg(short, long, default_value = "simple")]
|
||||
format: WatchFormat,
|
||||
}
|
||||
|
||||
impl WatchCommand {
|
||||
pub async fn run(self, events: EventStream) -> Result<()> {
|
||||
@ -14,15 +30,46 @@ impl WatchCommand {
|
||||
let event = stream.recv().await?;
|
||||
match event {
|
||||
Event::GuestChanged(changed) => {
|
||||
if let Some(guest) = changed.guest {
|
||||
println!(
|
||||
"event=guest.changed guest={} status={}",
|
||||
guest.id,
|
||||
guest_status_text(guest.state.unwrap_or_default().status())
|
||||
);
|
||||
}
|
||||
let guest = changed.guest.clone();
|
||||
self.print_event("guest.changed", changed, guest)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_event(
|
||||
&self,
|
||||
typ: &str,
|
||||
event: impl ReflectMessage,
|
||||
guest: Option<Guest>,
|
||||
) -> Result<()> {
|
||||
match self.format {
|
||||
WatchFormat::Simple => {
|
||||
if let Some(guest) = guest {
|
||||
println!(
|
||||
"{} guest={} status=\"{}\"",
|
||||
typ,
|
||||
guest.id,
|
||||
guest_state_text(guest.state.as_ref()).replace('"', "\\\"")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
WatchFormat::Json => {
|
||||
let message = proto2dynamic(event)?;
|
||||
let mut value = serde_json::to_value(&message)?;
|
||||
if let Value::Object(ref mut map) = value {
|
||||
map.insert("event.type".to_string(), Value::String(typ.to_string()));
|
||||
}
|
||||
println!("{}", serde_json::to_string(&value)?);
|
||||
}
|
||||
|
||||
WatchFormat::KeyValue => {
|
||||
let mut map = proto2kv(event)?;
|
||||
map.insert("event.type".to_string(), typ.to_string());
|
||||
println!("{}", kv2line(map),);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ impl StdioConsoleStream {
|
||||
}
|
||||
|
||||
let status = state.status();
|
||||
if status == GuestStatus::Destroy || status == GuestStatus::Destroyed {
|
||||
if status == GuestStatus::Destroying || status == GuestStatus::Destroyed {
|
||||
return Some(10);
|
||||
}
|
||||
}
|
||||
|
@ -49,3 +49,10 @@ pub fn proto2kv(proto: impl ReflectMessage) -> Result<HashMap<String, String>> {
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
pub fn kv2line(map: HashMap<String, String>) -> String {
|
||||
map.iter()
|
||||
.map(|(k, v)| format!("{}=\"{}\"", k, v.replace('"', "\\\"")))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
Reference in New Issue
Block a user