From d138740bbd7e1ba101b472d4c0e05b36b037430b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 3 Jun 2026 15:28:25 +0200 Subject: [PATCH] allow exec'ing service containers --- README.md | 5 +++- src/args.rs | 9 +++++++ src/main.rs | 55 ++++++++++++++++++++++++++++++------------ src/service.rs | 9 +++++++ src/service/redis.rs | 4 +++ src/service/smb.rs | 4 +++ src/service/webhook.rs | 4 +++ 7 files changed, 74 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 026c190..aa538d2 100644 --- a/README.md +++ b/README.md @@ -151,11 +151,14 @@ haze [match] db #### Execute a command on an instance ```bash -haze [match] exec [cmd] +haze [match] [service] [cmd] ``` If no `cmd` is specified it will launch `bash` +If a service name or `db` is provided, the command will be in the container of +the service or database. + #### Create a new instance and run a command ```bash diff --git a/src/args.rs b/src/args.rs index 9b7a2cc..59bca87 100644 --- a/src/args.rs +++ b/src/args.rs @@ -165,6 +165,7 @@ impl LogService { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ExecService { Db, + Service(Service), } impl HazeArgs { @@ -232,6 +233,14 @@ impl HazeArgs { args.next(); Some(ExecService::Db) } + Some(arg) => Service::from_type(&[], arg.as_ref()) + .into_iter() + .filter_map(|services| services.into_iter().next()) + .next() + .map(|service| { + args.next(); + ExecService::Service(service) + }), _ => None, }; diff --git a/src/main.rs b/src/main.rs index a58e922..d999b7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -148,6 +148,9 @@ async fn main() -> Result { root, } => { let cloud = Cloud::get_by_filter(&docker, filter, &config).await?; + let env = get_forward_env(); + let tty = atty::is(atty::Stream::Stdout); + match service { None => { let command = if command.is_empty() { @@ -155,8 +158,7 @@ async fn main() -> Result { } else { command }; - let env = get_forward_env(); - let tty = atty::is(atty::Stream::Stdout); + let user = if root { "root" } else { "haze" }; if tty { exec_tty(&docker, &cloud.id, user, command, env).await?; @@ -165,19 +167,42 @@ async fn main() -> Result { } } Some(ExecService::Db) => { - cloud - .db() - .exec_sh( - &docker, - &cloud.id, - if command.is_empty() { - vec!["bash".to_string()] - } else { - command - }, - atty::is(atty::Stream::Stdout), - ) - .await?; + let command = if command.is_empty() { + vec!["bash".to_string()] + } else { + command + }; + + cloud.db().exec_sh(&docker, &cloud.id, command, tty).await?; + } + Some(ExecService::Service(service)) => { + let Some(container) = service.container_name(&cloud.id) else { + eprintln!( + "Service {} can't be exec'ed as it has no associated container", + service.name() + ); + return Ok(ExitCode::FAILURE); + }; + if service.exec_shell() == "" && command.is_empty() { + eprintln!( + "Service {} can't be exec'ed as it has no shell", + service.name() + ); + return Ok(ExitCode::FAILURE); + } + + let command = if command.is_empty() { + vec![service.exec_shell().to_string()] + } else { + command + }; + + let user = if root { "root" } else { service.exec_user() }; + if tty { + exec_tty(&docker, &container, user, command, env).await?; + } else { + exec(&docker, &container, user, command, env, Some(stdout())).await?; + } } } } diff --git a/src/service.rs b/src/service.rs index cb517cb..c514449 100644 --- a/src/service.rs +++ b/src/service.rs @@ -194,6 +194,14 @@ pub trait ServiceTrait { fn proxy_port(&self) -> u16 { 80 } + + fn exec_user(&self) -> &'static str { + "root" + } + + fn exec_shell(&self) -> &'static str { + "bash" + } } #[derive(Clone, Eq, PartialEq, Debug)] @@ -242,6 +250,7 @@ pub enum ServiceType { /// Ldap admin interface LdapAdmin, /// OnlyOffice + #[strum(serialize = "onlyoffice", serialize = "only-office")] OnlyOffice, /// Libre office online Office, diff --git a/src/service/redis.rs b/src/service/redis.rs index db69667..6d5d5e6 100644 --- a/src/service/redis.rs +++ b/src/service/redis.rs @@ -75,4 +75,8 @@ impl ServiceTrait for Redis { "occ config:system:set redis host --value redis", )]) } + + fn exec_shell(&self) -> &'static str { + "sh" + } } diff --git a/src/service/smb.rs b/src/service/smb.rs index be1143b..08f69bd 100644 --- a/src/service/smb.rs +++ b/src/service/smb.rs @@ -90,4 +90,8 @@ impl ServiceTrait for Smb { split_cmnd("occ files_external:config 1 share test"), ]) } + + fn exec_shell(&self) -> &'static str { + "sh" + } } diff --git a/src/service/webhook.rs b/src/service/webhook.rs index 3967483..e7ebae0 100644 --- a/src/service/webhook.rs +++ b/src/service/webhook.rs @@ -68,4 +68,8 @@ impl ServiceTrait for Webhook { fn proxy_port(&self) -> u16 { 8080 } + + fn exec_shell(&self) -> &'static str { + "" + } }