From 37179f6cd944c79820b1ac1bfabbd9de785bbdf0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:55:56 +0000 Subject: [PATCH] Refactor Service Trait to Separate Configuration from Initialization - Introduced `configure` method in `Service` trait for safe file generation. - Moved `init.sql` generation for MariaDB from `initialize` to `configure`. - Implemented `configure` for `NextcloudService` to generate `autoconfig.php`. - Updated `main.rs` to ensure `run_generate` calls `configure_services`. - Updated `.gitignore` to exclude generated artifacts. --- .gitignore | 7 +++++++ server_manager/src/main.rs | 13 ++++++++++++- server_manager/src/services/apps.rs | 27 +++++++++++++++++++++++++++ server_manager/src/services/infra.rs | 2 +- server_manager/src/services/mod.rs | 4 ++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7ebfaa8..4380506 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,10 @@ server_manager/target/ .venv/ __pycache__/ *.pyc + +# Generated artifacts +server_manager/secrets.yaml +server_manager/docker-compose.yml +server_manager/config/ +server_manager/media/ +server_manager/transcode/ diff --git a/server_manager/src/main.rs b/server_manager/src/main.rs index 078160f..86eec0a 100644 --- a/server_manager/src/main.rs +++ b/server_manager/src/main.rs @@ -73,6 +73,7 @@ async fn run_install() -> Result<()> { docker::install()?; // 6. Initialize Services + configure_services(&hw, &secrets)?; initialize_services(&hw, &secrets)?; // 7. Generate Compose @@ -118,11 +119,21 @@ async fn run_generate() -> Result<()> { // For generate, we might not be in /opt/server_manager, but let's try to load secrets from CWD. // We propagate the error because generating a compose file with empty passwords is bad. let secrets = secrets::Secrets::load_or_create().context("Failed to load or create secrets.yaml")?; + configure_services(&hw, &secrets)?; generate_compose(&hw, &secrets).await } +fn configure_services(hw: &hardware::HardwareInfo, secrets: &secrets::Secrets) -> Result<()> { + info!("Configuring services (generating config files)..."); + let services = services::get_all_services(); + for service in services { + service.configure(hw, secrets).with_context(|| format!("Failed to configure service: {}", service.name()))?; + } + Ok(()) +} + fn initialize_services(hw: &hardware::HardwareInfo, secrets: &secrets::Secrets) -> Result<()> { - info!("Initializing services..."); + info!("Initializing services (system setup)..."); let services = services::get_all_services(); for service in services { service.initialize(hw, secrets).with_context(|| format!("Failed to initialize service: {}", service.name()))?; diff --git a/server_manager/src/services/apps.rs b/server_manager/src/services/apps.rs index fc6d81b..d8554a5 100644 --- a/server_manager/src/services/apps.rs +++ b/server_manager/src/services/apps.rs @@ -2,6 +2,9 @@ use super::Service; use crate::core::hardware::{HardwareInfo, HardwareProfile}; use crate::core::secrets::Secrets; use std::collections::HashMap; +use std::fs; +use std::path::Path; +use anyhow::{Result, Context}; pub struct VaultwardenService; impl Service for VaultwardenService { @@ -98,6 +101,30 @@ impl Service for NextcloudService { fn name(&self) -> &'static str { "nextcloud" } fn image(&self) -> &'static str { "lscr.io/linuxserver/nextcloud:latest" } fn ports(&self) -> Vec { vec!["4443:443".to_string()] } + fn configure(&self, _hw: &HardwareInfo, secrets: &Secrets) -> Result<()> { + let config_dir = Path::new("./config/nextcloud"); + fs::create_dir_all(config_dir).context("Failed to create nextcloud config dir")?; + + let db_pass = secrets.nextcloud_db_password.clone().unwrap_or_default(); + let admin_pass = secrets.nextcloud_admin_password.clone().unwrap_or_default(); + + let php_config = format!(r#" "mysql", + "dbname" => "nextcloud", + "dbuser" => "nextcloud", + "dbpass" => "{}", + "dbhost" => "mariadb", + "directory" => "/data", + "adminlogin" => "admin", + "adminpass" => "{}", +); +"#, db_pass, admin_pass); + + fs::write(config_dir.join("autoconfig.php"), php_config).context("Failed to write autoconfig.php")?; + Ok(()) + } + fn env_vars(&self, _hw: &HardwareInfo, secrets: &Secrets) -> HashMap { let mut vars = HashMap::new(); vars.insert("PUID".to_string(), "1000".to_string()); diff --git a/server_manager/src/services/infra.rs b/server_manager/src/services/infra.rs index ff3cdc2..c90a49d 100644 --- a/server_manager/src/services/infra.rs +++ b/server_manager/src/services/infra.rs @@ -13,7 +13,7 @@ impl Service for MariaDBService { fn image(&self) -> &'static str { "lscr.io/linuxserver/mariadb:latest" } fn ports(&self) -> Vec { vec!["3306:3306".to_string()] } - fn initialize(&self, _hw: &HardwareInfo, secrets: &Secrets) -> Result<()> { + fn configure(&self, _hw: &HardwareInfo, secrets: &Secrets) -> Result<()> { let init_dir = Path::new("./config/mariadb/initdb.d"); fs::create_dir_all(init_dir).context("Failed to create mariadb initdb.d")?; diff --git a/server_manager/src/services/mod.rs b/server_manager/src/services/mod.rs index 6210ebc..8471c4f 100644 --- a/server_manager/src/services/mod.rs +++ b/server_manager/src/services/mod.rs @@ -13,6 +13,10 @@ pub trait Service: Send + Sync { fn name(&self) -> &'static str; fn image(&self) -> &'static str; + /// Generates configuration files (safe to run without side effects on system services) + fn configure(&self, _hw: &HardwareInfo, _secrets: &Secrets) -> Result<()> { Ok(()) } + + /// Performs system initialization (e.g., stopping conflicting services). May require root. fn initialize(&self, _hw: &HardwareInfo, _secrets: &Secrets) -> Result<()> { Ok(()) } fn ports(&self) -> Vec { vec![] }