- Termination procedure optional.

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-10-26 17:13:58 -03:00
parent f1d4439f47
commit 6ad29634ea
4 changed files with 87 additions and 37 deletions

View file

@ -90,7 +90,7 @@ urlencoding = "2.1"
uuid = { version = "1.11", features = ["serde", "v4"] }
zip = "2.2"
time = "0.3.44"
aws-sdk-s3 = "1.108.0"
aws-sdk-s3 = { version = "1.108.0", features = ["behavior-version-latest"] }
headless_chrome = { version = "1.0.18", optional = true }
rand = "0.9.2"
pdf-extract = "0.10.0"

View file

@ -11,6 +11,13 @@ use diesel::RunQueryDsl;
use rand::distr::Alphanumeric;
use sha2::{Digest, Sha256};
use std::path::Path;
use std::process::Command;
use std::io::{self, Write};
pub struct ComponentInfo {
pub name: &'static str,
pub termination_command: &'static str,
}
pub struct BootstrapManager {
pub install_mode: InstallMode,
@ -33,42 +40,40 @@ impl BootstrapManager {
pub fn start_all(&mut self) -> Result<()> {
let pm = PackageManager::new(self.install_mode.clone(), self.tenant.clone())?;
let components = vec![
"tables",
"cache",
"drive",
"llm",
"email",
"proxy",
"directory",
"alm",
"alm_ci",
"dns",
"webmail",
"meeting",
"table_editor",
"doc_editor",
"desktop",
"devtools",
"bot",
"system",
"vector_db",
"host",
ComponentInfo { name: "tables", termination_command: "pg_ctl" },
ComponentInfo { name: "cache", termination_command: "valkey-server" },
ComponentInfo { name: "drive", termination_command: "minio" },
ComponentInfo { name: "llm", termination_command: "llama-server" },
ComponentInfo { name: "email", termination_command: "stalwart" },
ComponentInfo { name: "proxy", termination_command: "caddy" },
ComponentInfo { name: "directory", termination_command: "zitadel" },
ComponentInfo { name: "alm", termination_command: "forgejo" },
ComponentInfo { name: "alm_ci", termination_command: "forgejo-runner" },
ComponentInfo { name: "dns", termination_command: "coredns" },
ComponentInfo { name: "webmail", termination_command: "php" },
ComponentInfo { name: "meeting", termination_command: "livekit-server" },
ComponentInfo { name: "table_editor", termination_command: "nocodb" },
ComponentInfo { name: "doc_editor", termination_command: "coolwsd" },
ComponentInfo { name: "desktop", termination_command: "xrdp" },
ComponentInfo { name: "devtools", termination_command: "" },
ComponentInfo { name: "bot", termination_command: "" },
ComponentInfo { name: "system", termination_command: "" },
ComponentInfo { name: "vector_db", termination_command: "qdrant" },
ComponentInfo { name: "host", termination_command: "" },
];
for component in components {
if pm.is_installed(component) {
trace!("Starting component: {}", component);
pm.start(component)?;
if pm.is_installed(component.name) {
trace!("Starting component: {}", component.name);
pm.start(component.name)?;
} else {
trace!("Component {} not installed, skipping start", component);
// After installing a component, update the default bot configuration
// This is a placeholder for the logic that will write config.csv to the
// default.gbai bucket and upsert into the bot_config table.
// The actual implementation will use the AppState's S3 client to upload
// the updated CSV after each component installation.
// Now perform the actual update:
if let Err(e) = self.update_bot_config(component) {
error!("Failed to update bot config after installing {}: {}", component, e);
trace!("Component {} not installed, skipping start", component.name);
if let Err(e) = self.update_bot_config(component.name) {
error!("Failed to update bot config after installing {}: {}", component.name, e);
}
}
}
@ -127,7 +132,47 @@ Ok(())
for component in required_components {
if !pm.is_installed(component) {
// Determine termination command from package manager component config
let termination_cmd = pm.components.get(component)
.and_then(|cfg| cfg.binary_name.clone())
.unwrap_or_else(|| component.to_string());
// If a termination command is defined, check for leftover running process
if !termination_cmd.is_empty() {
let check = Command::new("pgrep")
.arg("-f")
.arg(&termination_cmd)
.output();
if let Ok(output) = check {
if !output.stdout.is_empty() {
println!("Component '{}' appears to be already running from a previous install.", component);
println!("Do you want to terminate it? (y/n)");
let mut input = String::new();
io::stdout().flush().unwrap();
io::stdin().read_line(&mut input).unwrap();
if input.trim().eq_ignore_ascii_case("y") {
let _ = Command::new("pkill")
.arg("-f")
.arg(&termination_cmd)
.status();
println!("Terminated existing '{}' process.", component);
} else {
println!("Skipping start of '{}' as it is already running.", component);
continue;
}
}
}
}
if component == "tables" {
let db_password = self.generate_secure_password(16);
let farm_password = self.generate_secure_password(32);

View file

@ -92,7 +92,9 @@ async fn main() -> std::io::Result<()> {
}
dotenv().ok();
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
.write_style(env_logger::WriteStyle::Always)
.init();
info!("Starting BotServer bootstrap process");

View file

@ -160,7 +160,7 @@ env_vars: HashMap::from([
macos_packages: vec![],
windows_packages: vec![],
download_url: Some("https://github.com/theseus-rs/postgresql-binaries/releases/download/18.0.0/postgresql-18.0.0-x86_64-unknown-linux-gnu.tar.gz".to_string()),
binary_name: None,
binary_name: Some("postgres".to_string()),
pre_install_cmds_linux: vec![],
post_install_cmds_linux: vec![
"chmod +x ./bin/*".to_string(),
@ -216,13 +216,16 @@ self.components.insert(
download_url: Some("https://download.valkey.io/releases/valkey-9.0.0-jammy-x86_64.tar.gz".to_string()),
binary_name: Some("valkey-server".to_string()),
pre_install_cmds_linux: vec![],
post_install_cmds_linux: vec![],
post_install_cmds_linux: vec![
"tar -xzf {{BIN_PATH}}/valkey-9.0.0-jammy-x86_64.tar.gz -C {{BIN_PATH}}".to_string(),
"mv {{BIN_PATH}}/valkey-9.0.0-jammy-x86_64/valkey-server {{BIN_PATH}}/valkey-server".to_string(),
],
pre_install_cmds_macos: vec![],
post_install_cmds_macos: vec![],
pre_install_cmds_windows: vec![],
post_install_cmds_windows: vec![],
env_vars: HashMap::new(),
exec_cmd: "./valkey-server --port 6379 --dir {{DATA_PATH}}".to_string(),
exec_cmd: "{{BIN_PATH}}/valkey-server --port 6379 --dir {{DATA_PATH}}".to_string(),
},
);
}