mirror of
https://github.com/moghtech/komodo.git
synced 2026-03-11 17:44:19 -05:00
km exec
This commit is contained in:
@@ -18,7 +18,7 @@ pub mod container;
|
||||
pub mod database;
|
||||
pub mod execute;
|
||||
pub mod list;
|
||||
pub mod ssh;
|
||||
pub mod terminal;
|
||||
pub mod update;
|
||||
|
||||
async fn komodo_client() -> anyhow::Result<&'static KomodoClient> {
|
||||
|
||||
@@ -4,19 +4,73 @@ use colored::Colorize;
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use komodo_client::{
|
||||
api::write::{CreateTerminal, TerminalRecreateMode},
|
||||
entities::config::cli::args::ssh::Ssh,
|
||||
entities::config::cli::args::terminal::{Connect, Exec},
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt as _, AsyncWriteExt as _},
|
||||
net::TcpStream,
|
||||
};
|
||||
use tokio_tungstenite::{
|
||||
MaybeTlsStream, WebSocketStream, tungstenite,
|
||||
};
|
||||
use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
|
||||
use tokio_tungstenite::tungstenite;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
pub async fn handle(
|
||||
Ssh {
|
||||
pub async fn handle_connect(
|
||||
Connect {
|
||||
server,
|
||||
name,
|
||||
command,
|
||||
recreate,
|
||||
}: &Ssh,
|
||||
}: &Connect,
|
||||
) -> anyhow::Result<()> {
|
||||
handle_terminal_forwarding(async {
|
||||
let client = super::komodo_client().await?;
|
||||
// Init the terminal if it doesn't exist already.
|
||||
client
|
||||
.write(CreateTerminal {
|
||||
server: server.to_string(),
|
||||
name: name.to_string(),
|
||||
command: command.clone(),
|
||||
recreate: if *recreate {
|
||||
TerminalRecreateMode::Always
|
||||
} else {
|
||||
TerminalRecreateMode::DifferentCommand
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
client.connect_terminal_websocket(server, name).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn handle_exec(
|
||||
Exec {
|
||||
server,
|
||||
container,
|
||||
shell,
|
||||
recreate,
|
||||
}: &Exec,
|
||||
) -> anyhow::Result<()> {
|
||||
handle_terminal_forwarding(async {
|
||||
super::komodo_client()
|
||||
.await?
|
||||
.connect_container_websocket(
|
||||
server,
|
||||
container,
|
||||
shell,
|
||||
recreate.then_some(TerminalRecreateMode::Always),
|
||||
)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
type WsStream = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
|
||||
async fn handle_terminal_forwarding<
|
||||
C: Future<Output = anyhow::Result<WsStream>>,
|
||||
>(
|
||||
connect: C,
|
||||
) -> anyhow::Result<()> {
|
||||
// Need to forward multiple sources into ws write
|
||||
let (write_tx, mut write_rx) =
|
||||
@@ -84,26 +138,7 @@ pub async fn handle(
|
||||
// CONNECT AND FORWARD
|
||||
// =====================
|
||||
|
||||
let client = super::komodo_client().await?;
|
||||
|
||||
// Init the terminal if it doesn't exist already.
|
||||
client
|
||||
.write(CreateTerminal {
|
||||
server: server.to_string(),
|
||||
name: name.to_string(),
|
||||
command: command.clone(),
|
||||
recreate: if *recreate {
|
||||
TerminalRecreateMode::Always
|
||||
} else {
|
||||
TerminalRecreateMode::DifferentCommand
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
|
||||
let (mut ws_write, mut ws_read) = client
|
||||
.connect_terminal_websocket(server, name)
|
||||
.await?
|
||||
.split();
|
||||
let (mut ws_write, mut ws_read) = connect.await?.split();
|
||||
|
||||
let forward_write = async {
|
||||
while let Some(bytes) =
|
||||
@@ -54,7 +54,12 @@ async fn app() -> anyhow::Result<()> {
|
||||
args::Command::Update { command } => {
|
||||
command::update::handle(command).await
|
||||
}
|
||||
args::Command::Ssh(ssh) => command::ssh::handle(ssh).await,
|
||||
args::Command::Connect(connect) => {
|
||||
command::terminal::handle_connect(connect).await
|
||||
}
|
||||
args::Command::Exec(exec) => {
|
||||
command::terminal::handle_exec(exec).await
|
||||
}
|
||||
args::Command::Key { command } => {
|
||||
noise::key::command::handle(command).await
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use derive_empty_traits::EmptyTraits;
|
||||
use resolver_api::Resolve;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::AsRefStr;
|
||||
use typeshare::typeshare;
|
||||
|
||||
use crate::entities::{
|
||||
@@ -134,7 +135,9 @@ pub struct CreateNetwork {
|
||||
/// Configures the behavior of [CreateTerminal] if the
|
||||
/// specified terminal name already exists.
|
||||
#[typeshare]
|
||||
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Default, Serialize, Deserialize, AsRefStr,
|
||||
)]
|
||||
pub enum TerminalRecreateMode {
|
||||
/// Never kill the old terminal if it already exists.
|
||||
/// If the command is different, returns error.
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::api::execute::Execution;
|
||||
pub mod container;
|
||||
pub mod database;
|
||||
pub mod list;
|
||||
pub mod ssh;
|
||||
pub mod terminal;
|
||||
pub mod update;
|
||||
|
||||
#[derive(Debug, clap::Parser)]
|
||||
@@ -81,7 +81,12 @@ pub enum Command {
|
||||
command: update::UpdateCommand,
|
||||
},
|
||||
|
||||
Ssh(ssh::Ssh),
|
||||
/// Connect to Server Terminals. (alias: `ssh`)
|
||||
#[clap(alias = "ssh")]
|
||||
Connect(terminal::Connect),
|
||||
|
||||
/// Connect to Container Terminals.
|
||||
Exec(terminal::Exec),
|
||||
|
||||
/// Private-Public key utilities. (alias: `k`)
|
||||
#[clap(alias = "k")]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#[derive(Debug, Clone, clap::Parser)]
|
||||
pub struct Ssh {
|
||||
pub struct Connect {
|
||||
/// The server to connect to.
|
||||
pub server: String,
|
||||
|
||||
@@ -15,3 +15,17 @@ pub struct Ssh {
|
||||
#[arg(long, short = 'r', default_value_t = false)]
|
||||
pub recreate: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, clap::Parser)]
|
||||
pub struct Exec {
|
||||
/// Specify Server
|
||||
pub server: String,
|
||||
/// The container (name) to connect to.
|
||||
/// Will error if matches multiple containers but no Server is defined.
|
||||
pub container: String,
|
||||
/// The shell, eg `bash`.
|
||||
pub shell: String,
|
||||
/// Force fresh terminal to replace existing one.
|
||||
#[arg(long, short = 'r', default_value_t = false)]
|
||||
pub recreate: bool,
|
||||
}
|
||||
@@ -9,7 +9,7 @@ use tokio_tungstenite::{
|
||||
};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use crate::KomodoClient;
|
||||
use crate::{KomodoClient, api::write::TerminalRecreateMode};
|
||||
|
||||
pub mod update;
|
||||
|
||||
@@ -47,6 +47,26 @@ impl KomodoClient {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn connect_container_websocket(
|
||||
&self,
|
||||
server: &str,
|
||||
container: &str,
|
||||
shell: &str,
|
||||
recreate: Option<TerminalRecreateMode>,
|
||||
) -> anyhow::Result<WebSocketStream<MaybeTlsStream<TcpStream>>> {
|
||||
let mut query =
|
||||
format!("server={server}&container={container}&shell={shell}");
|
||||
if let Some(recreate) = recreate {
|
||||
let _ = write!(&mut query, "&recreate={}", recreate.as_ref());
|
||||
}
|
||||
self
|
||||
.connect_login_user_websocket(
|
||||
"/container/terminal",
|
||||
Some(&query),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn connect_login_user_websocket(
|
||||
&self,
|
||||
path: &str,
|
||||
|
||||
Reference in New Issue
Block a user