mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 13:11:31 +00:00
kratactl: implement guest resolution and rename console to attach
This commit is contained in:
@ -7,24 +7,26 @@ use tonic::transport::Channel;
|
||||
|
||||
use crate::{console::StdioConsoleStream, events::EventStream};
|
||||
|
||||
use super::resolve_guest;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct ConsoleCommand {
|
||||
pub struct AttachCommand {
|
||||
#[arg()]
|
||||
guest: String,
|
||||
}
|
||||
|
||||
impl ConsoleCommand {
|
||||
impl AttachCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
mut client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
let input = StdioConsoleStream::stdin_stream(self.guest.clone()).await;
|
||||
let guest_id: String = resolve_guest(&mut client, &self.guest).await?;
|
||||
let input = StdioConsoleStream::stdin_stream(guest_id.clone()).await;
|
||||
let output = client.console_data(input).await?.into_inner();
|
||||
let stdout_handle =
|
||||
tokio::task::spawn(async move { StdioConsoleStream::stdout(output).await });
|
||||
let exit_hook_task =
|
||||
StdioConsoleStream::guest_exit_hook(self.guest.clone(), events).await?;
|
||||
let exit_hook_task = StdioConsoleStream::guest_exit_hook(guest_id.clone(), events).await?;
|
||||
let code = select! {
|
||||
x = stdout_handle => {
|
||||
x??;
|
@ -4,7 +4,7 @@ use krata::control::{control_service_client::ControlServiceClient, DestroyGuestR
|
||||
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
use crate::events::EventStream;
|
||||
use crate::cli::resolve_guest;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct DestroyCommand {
|
||||
@ -13,15 +13,10 @@ pub struct DestroyCommand {
|
||||
}
|
||||
|
||||
impl DestroyCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
mut client: ControlServiceClient<Channel>,
|
||||
_events: EventStream,
|
||||
) -> Result<()> {
|
||||
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
|
||||
let guest_id: String = resolve_guest(&mut client, &self.guest).await?;
|
||||
let _ = client
|
||||
.destroy_guest(Request::new(DestroyGuestRequest {
|
||||
guest_id: self.guest.clone(),
|
||||
}))
|
||||
.destroy_guest(Request::new(DestroyGuestRequest { guest_id }))
|
||||
.await?
|
||||
.into_inner();
|
||||
println!("destroyed guest: {}", self.guest);
|
||||
|
@ -11,11 +11,9 @@ use tonic::{transport::Channel, Request};
|
||||
|
||||
use crate::{
|
||||
events::EventStream,
|
||||
format::{kv2line, proto2dynamic, proto2kv},
|
||||
format::{guest_state_text, kv2line, proto2dynamic, proto2kv},
|
||||
};
|
||||
|
||||
use super::pretty::guest_state_text;
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum ListFormat {
|
||||
CliTable,
|
||||
|
@ -1,19 +1,22 @@
|
||||
pub mod console;
|
||||
pub mod attach;
|
||||
pub mod destroy;
|
||||
pub mod launch;
|
||||
pub mod list;
|
||||
pub mod pretty;
|
||||
pub mod resolve;
|
||||
pub mod watch;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::{Parser, Subcommand};
|
||||
use krata::control::WatchEventsRequest;
|
||||
use krata::control::{
|
||||
control_service_client::ControlServiceClient, ResolveGuestRequest, WatchEventsRequest,
|
||||
};
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
use crate::{client::ControlClientProvider, events::EventStream};
|
||||
|
||||
use self::{
|
||||
console::ConsoleCommand, destroy::DestroyCommand, launch::LauchCommand, list::ListCommand,
|
||||
watch::WatchCommand,
|
||||
attach::AttachCommand, destroy::DestroyCommand, launch::LauchCommand, list::ListCommand,
|
||||
resolve::ResolveCommand, watch::WatchCommand,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
@ -31,8 +34,9 @@ pub enum Commands {
|
||||
Launch(LauchCommand),
|
||||
Destroy(DestroyCommand),
|
||||
List(ListCommand),
|
||||
Console(ConsoleCommand),
|
||||
Attach(AttachCommand),
|
||||
Watch(WatchCommand),
|
||||
Resolve(ResolveCommand),
|
||||
}
|
||||
|
||||
impl ControlCommand {
|
||||
@ -52,11 +56,11 @@ impl ControlCommand {
|
||||
}
|
||||
|
||||
Commands::Destroy(destroy) => {
|
||||
destroy.run(client, events).await?;
|
||||
destroy.run(client).await?;
|
||||
}
|
||||
|
||||
Commands::Console(console) => {
|
||||
console.run(client, events).await?;
|
||||
Commands::Attach(attach) => {
|
||||
attach.run(client, events).await?;
|
||||
}
|
||||
|
||||
Commands::List(list) => {
|
||||
@ -66,7 +70,29 @@ impl ControlCommand {
|
||||
Commands::Watch(watch) => {
|
||||
watch.run(events).await?;
|
||||
}
|
||||
|
||||
Commands::Resolve(resolve) => {
|
||||
resolve.run(client).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn resolve_guest(
|
||||
client: &mut ControlServiceClient<Channel>,
|
||||
name: &str,
|
||||
) -> Result<String> {
|
||||
let reply = client
|
||||
.resolve_guest(Request::new(ResolveGuestRequest {
|
||||
name: name.to_string(),
|
||||
}))
|
||||
.await?
|
||||
.into_inner();
|
||||
|
||||
if let Some(guest) = reply.guest {
|
||||
Ok(guest.id)
|
||||
} else {
|
||||
Err(anyhow!("unable to resolve guest {}", name))
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
use krata::common::{GuestState, GuestStatus};
|
||||
|
||||
pub fn guest_status_text(status: GuestStatus) -> String {
|
||||
match status {
|
||||
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: 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 {
|
||||
text.push_str(&format!(" (exit code: {})", exit.code));
|
||||
}
|
||||
|
||||
if let Some(error) = state.error_info {
|
||||
text.push_str(&format!(" (error: {})", error.message));
|
||||
}
|
||||
text
|
||||
}
|
28
crates/kratactl/src/cli/resolve.rs
Normal file
28
crates/kratactl/src/cli/resolve.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use krata::control::{control_service_client::ControlServiceClient, ResolveGuestRequest};
|
||||
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct ResolveCommand {
|
||||
#[arg()]
|
||||
guest: String,
|
||||
}
|
||||
|
||||
impl ResolveCommand {
|
||||
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
|
||||
let reply = client
|
||||
.resolve_guest(Request::new(ResolveGuestRequest {
|
||||
name: self.guest.clone(),
|
||||
}))
|
||||
.await?
|
||||
.into_inner();
|
||||
if let Some(guest) = reply.guest {
|
||||
println!("{}", guest.id);
|
||||
} else {
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -5,9 +5,8 @@ use prost_reflect::ReflectMessage;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
cli::pretty::guest_state_text,
|
||||
events::EventStream,
|
||||
format::{kv2line, proto2dynamic, proto2kv},
|
||||
format::{guest_state_text, kv2line, proto2dynamic, proto2kv},
|
||||
};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use krata::common::{GuestState, GuestStatus};
|
||||
use prost_reflect::{DynamicMessage, ReflectMessage, Value};
|
||||
|
||||
pub fn proto2dynamic(proto: impl ReflectMessage) -> Result<DynamicMessage> {
|
||||
@ -56,3 +57,30 @@ pub fn kv2line(map: HashMap<String, String>) -> String {
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub fn guest_status_text(status: GuestStatus) -> String {
|
||||
match status {
|
||||
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: 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 {
|
||||
text.push_str(&format!(" (exit code: {})", exit.code));
|
||||
}
|
||||
|
||||
if let Some(error) = state.error_info {
|
||||
text.push_str(&format!(" (error: {})", error.message));
|
||||
}
|
||||
text
|
||||
}
|
||||
|
Reference in New Issue
Block a user