From 8a79fbea235ef84039957c1500e3e12466bc6080 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 8 Aug 2023 10:22:12 +0100 Subject: [PATCH 1/5] refactor: [#361] extract mod for configuration --- src/bootstrap/app.rs | 31 +------------------------------ src/bootstrap/config.rs | 37 +++++++++++++++++++++++++++++++++++++ src/bootstrap/mod.rs | 1 + 3 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 src/bootstrap/config.rs diff --git a/src/bootstrap/app.rs b/src/bootstrap/app.rs index c0e688a0d..6961e15f0 100644 --- a/src/bootstrap/app.rs +++ b/src/bootstrap/app.rs @@ -11,11 +11,11 @@ //! 2. Initialize static variables. //! 3. Initialize logging. //! 4. Initialize the domain tracker. -use std::env; use std::sync::Arc; use torrust_tracker_configuration::Configuration; +use super::config::initialize_configuration; use crate::bootstrap; use crate::shared::clock::static_time; use crate::shared::crypto::ephemeral_instance_keys; @@ -55,35 +55,6 @@ pub fn initialize_static() { lazy_static::initialize(&ephemeral_instance_keys::RANDOM_SEED); } -/// It loads the application configuration from the environment. -/// -/// There are two methods to inject the configuration: -/// -/// 1. By using a config file: `config.toml`. The file must be in the same folder where you are running the tracker. -/// 2. Environment variable: `TORRUST_TRACKER_CONFIG`. The variable contains the same contents as the `config.toml` file. -/// -/// Environment variable has priority over the config file. -/// -/// Refer to the [configuration documentation](https://docs.rs/torrust-tracker-configuration) for the configuration options. -/// -/// # Panics -/// -/// Will panic if it can't load the configuration from either -/// `./config.toml` file or the env var `TORRUST_TRACKER_CONFIG`. -#[must_use] -fn initialize_configuration() -> Configuration { - const CONFIG_PATH: &str = "./config.toml"; - const CONFIG_ENV_VAR_NAME: &str = "TORRUST_TRACKER_CONFIG"; - - if env::var(CONFIG_ENV_VAR_NAME).is_ok() { - println!("Loading configuration from env var {CONFIG_ENV_VAR_NAME}"); - Configuration::load_from_env_var(CONFIG_ENV_VAR_NAME).unwrap() - } else { - println!("Loading configuration from config file {CONFIG_PATH}"); - Configuration::load_from_file(CONFIG_PATH).unwrap() - } -} - /// It builds the domain tracker /// /// The tracker is the domain layer service. It's the entrypoint to make requests to the domain layer. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs new file mode 100644 index 000000000..187fddd0b --- /dev/null +++ b/src/bootstrap/config.rs @@ -0,0 +1,37 @@ +//! Initialize configuration from file or env var. +//! +//! All environment variables are prefixed with `TORRUST_TRACKER_BACK_`. +use std::env; + +use torrust_tracker_configuration::Configuration; + +// Environment variables + +const CONFIG_PATH: &str = "./config.toml"; +const CONFIG_ENV_VAR_NAME: &str = "TORRUST_TRACKER_CONFIG"; + +/// It loads the application configuration from the environment. +/// +/// There are two methods to inject the configuration: +/// +/// 1. By using a config file: `config.toml`. The file must be in the same folder where you are running the tracker. +/// 2. Environment variable: `TORRUST_TRACKER_CONFIG`. The variable contains the same contents as the `config.toml` file. +/// +/// Environment variable has priority over the config file. +/// +/// Refer to the [configuration documentation](https://docs.rs/torrust-tracker-configuration) for the configuration options. +/// +/// # Panics +/// +/// Will panic if it can't load the configuration from either +/// `./config.toml` file or the env var `TORRUST_TRACKER_CONFIG`. +#[must_use] +pub fn initialize_configuration() -> Configuration { + if env::var(CONFIG_ENV_VAR_NAME).is_ok() { + println!("Loading configuration from env var {CONFIG_ENV_VAR_NAME}"); + Configuration::load_from_env_var(CONFIG_ENV_VAR_NAME).unwrap() + } else { + println!("Loading configuration from config file {CONFIG_PATH}"); + Configuration::load_from_file(CONFIG_PATH).unwrap() + } +} diff --git a/src/bootstrap/mod.rs b/src/bootstrap/mod.rs index e39cf3adc..22044aafd 100644 --- a/src/bootstrap/mod.rs +++ b/src/bootstrap/mod.rs @@ -6,5 +6,6 @@ //! like cleaning torrents, and other jobs because they can be enabled/disabled depending on the configuration. //! For example, you can have more than one UDP and HTTP tracker, each server is executed like a independent job. pub mod app; +pub mod config; pub mod jobs; pub mod logging; From 0adf373bca011c7985277066a7f20138785bc35f Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 8 Aug 2023 10:38:43 +0100 Subject: [PATCH 2/5] refactor: [#361] rename constants representing env vars All of then have the ENV_VAR prefix now. Like in the Index Backend. So we can identify constants that are related to env vars. --- src/bootstrap/config.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 187fddd0b..2b0740f0e 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -7,14 +7,19 @@ use torrust_tracker_configuration::Configuration; // Environment variables -const CONFIG_PATH: &str = "./config.toml"; -const CONFIG_ENV_VAR_NAME: &str = "TORRUST_TRACKER_CONFIG"; +/// The whole `config.toml` file content. It has priority over the config file. +/// Even if the file is not on the default path. +const ENV_VAR_CONFIG: &str = "TORRUST_TRACKER_CONFIG"; + +// Default values + +const ENV_VAR_DEFAULT_CONFIG_PATH: &str = "./config.toml"; /// It loads the application configuration from the environment. /// /// There are two methods to inject the configuration: /// -/// 1. By using a config file: `config.toml`. The file must be in the same folder where you are running the tracker. +/// 1. By using a config file: `config.toml`. /// 2. Environment variable: `TORRUST_TRACKER_CONFIG`. The variable contains the same contents as the `config.toml` file. /// /// Environment variable has priority over the config file. @@ -27,11 +32,13 @@ const CONFIG_ENV_VAR_NAME: &str = "TORRUST_TRACKER_CONFIG"; /// `./config.toml` file or the env var `TORRUST_TRACKER_CONFIG`. #[must_use] pub fn initialize_configuration() -> Configuration { - if env::var(CONFIG_ENV_VAR_NAME).is_ok() { - println!("Loading configuration from env var {CONFIG_ENV_VAR_NAME}"); - Configuration::load_from_env_var(CONFIG_ENV_VAR_NAME).unwrap() + if env::var(ENV_VAR_CONFIG).is_ok() { + println!("Loading configuration from env var {ENV_VAR_CONFIG}"); + + Configuration::load_from_env_var(ENV_VAR_CONFIG).unwrap() } else { - println!("Loading configuration from config file {CONFIG_PATH}"); - Configuration::load_from_file(CONFIG_PATH).unwrap() + println!("Loading configuration from config file {ENV_VAR_DEFAULT_CONFIG_PATH}"); + + Configuration::load_from_file(ENV_VAR_DEFAULT_CONFIG_PATH).unwrap() } } From 702dd1433a850090d02417b82cfb7ebc45510898 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 8 Aug 2023 10:56:45 +0100 Subject: [PATCH 3/5] feat: allow to change the config.toml file path Now you can change the deafult location for the config file with an env var: ``` TORRUST_IDX_BACK_CONFIG_PATH="./storage/config.toml" cargo run ``` The default location is still `./config.toml` --- packages/configuration/src/lib.rs | 5 +++-- src/bootstrap/config.rs | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/configuration/src/lib.rs b/packages/configuration/src/lib.rs index f785aa976..ff604fa4e 100644 --- a/packages/configuration/src/lib.rs +++ b/packages/configuration/src/lib.rs @@ -512,10 +512,11 @@ impl Configuration { if Path::new(path).exists() { config = config_builder.add_source(File::with_name(path)).build()?; } else { - warn!("No config file found."); - warn!("Creating config file.."); + warn!("No config file found. Creating config file ..."); + let config = Configuration::default(); config.save_to_file(path)?; + return Err(Error::CreatedNewConfigHalt { location: Location::caller(), path: path.to_string(), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 2b0740f0e..398d98563 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -2,6 +2,7 @@ //! //! All environment variables are prefixed with `TORRUST_TRACKER_BACK_`. use std::env; +use std::path::Path; use torrust_tracker_configuration::Configuration; @@ -11,6 +12,9 @@ use torrust_tracker_configuration::Configuration; /// Even if the file is not on the default path. const ENV_VAR_CONFIG: &str = "TORRUST_TRACKER_CONFIG"; +/// The `config.toml` file location. +pub const ENV_VAR_CONFIG_PATH: &str = "TORRUST_IDX_BACK_CONFIG_PATH"; + // Default values const ENV_VAR_DEFAULT_CONFIG_PATH: &str = "./config.toml"; @@ -37,8 +41,14 @@ pub fn initialize_configuration() -> Configuration { Configuration::load_from_env_var(ENV_VAR_CONFIG).unwrap() } else { - println!("Loading configuration from config file {ENV_VAR_DEFAULT_CONFIG_PATH}"); + let config_path = env::var(ENV_VAR_CONFIG_PATH).unwrap_or_else(|_| ENV_VAR_DEFAULT_CONFIG_PATH.to_string()); + + if Path::new(&config_path).is_file(){ + println!("Loading configuration from config file: `{config_path}`"); + } else { + println!("Creating default config file: `{config_path}`"); + } - Configuration::load_from_file(ENV_VAR_DEFAULT_CONFIG_PATH).unwrap() + Configuration::load_from_file(&config_path).expect("Error loading configuration from file") } } From 8936c6e747b7060cd01df03b711d6133fda242c6 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 8 Aug 2023 11:55:26 +0100 Subject: [PATCH 4/5] feat!: continue running the tracker after creating default config file Instead of halting the program, not the tracker continues the execution when no config.toml file is provided and the default one is created. It shows some messages: ``` Loading configuration from configuration file: `./config.toml` ... Missing configuration file. Creating a default configuration file: `./config.toml` ... Please review the config file: `./config.toml` and restart the tracker if needed. 2023-08-08T11:56:26.957162508+01:00 [torrust_tracker::bootstrap::logging][INFO] logging initialized. 2023-08-08T11:56:26.957931296+01:00 [torrust_tracker::bootstrap::jobs::tracker_apis][INFO] Starting Torrust APIs server on: http://127.0.0.1:1212 2023-08-08T11:56:26.958027355+01:00 [torrust_tracker::bootstrap::jobs::tracker_apis][INFO] Torrust APIs server started ``` --- packages/configuration/src/lib.rs | 42 +++++++++++-------------------- src/bootstrap/config.rs | 31 +++++++++++++++++------ 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/packages/configuration/src/lib.rs b/packages/configuration/src/lib.rs index ff604fa4e..6de0e3ed7 100644 --- a/packages/configuration/src/lib.rs +++ b/packages/configuration/src/lib.rs @@ -228,14 +228,11 @@ //!``` use std::collections::{HashMap, HashSet}; use std::net::IpAddr; -use std::panic::Location; -use std::path::Path; use std::str::FromStr; use std::sync::Arc; use std::{env, fs}; use config::{Config, ConfigError, File, FileFormat}; -use log::warn; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, NoneAsEmptyString}; use thiserror::Error; @@ -414,17 +411,6 @@ pub enum Error { source: LocatedError<'static, dyn std::error::Error + Send + Sync>, }, - /// If you run the tracker without providing the configuration (via the - /// `TORRUST_TRACKER_CONFIG` environment variable or configuration file), - /// the tracker will create a default configuration file but it will not - /// load it. It will return this error instead and you have to restart the - /// it. - #[error("Default configuration created at: `{path}`, please review and reload tracker, {location}")] - CreatedNewConfigHalt { - location: &'static Location<'static>, - path: String, - }, - /// Unable to load the configuration from the configuration file. #[error("Failed processing the configuration: {source}")] ConfigError { source: LocatedError<'static, ConfigError> }, @@ -502,32 +488,32 @@ impl Configuration { /// /// # Errors /// - /// Will return `Err` if `path` does not exist or has a bad configuration. + /// Will return `Err` if `path` does not exist or has a bad configuration. pub fn load_from_file(path: &str) -> Result { let config_builder = Config::builder(); #[allow(unused_assignments)] let mut config = Config::default(); - if Path::new(path).exists() { - config = config_builder.add_source(File::with_name(path)).build()?; - } else { - warn!("No config file found. Creating config file ..."); - - let config = Configuration::default(); - config.save_to_file(path)?; - - return Err(Error::CreatedNewConfigHalt { - location: Location::caller(), - path: path.to_string(), - }); - } + config = config_builder.add_source(File::with_name(path)).build()?; let torrust_config: Configuration = config.try_deserialize()?; Ok(torrust_config) } + /// Saves the default configuration at the given path. + /// + /// # Errors + /// + /// Will return `Err` if `path` is not a valid path or the configuration + /// file cannot be created. + pub fn create_default_configuration_file(path: &str) -> Result { + let config = Configuration::default(); + config.save_to_file(path)?; + Ok(config) + } + /// Loads the configuration from the environment variable. The whole /// configuration must be in the environment variable. It contains the same /// configuration as the configuration file with the same format. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 398d98563..eef3265f9 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -4,7 +4,7 @@ use std::env; use std::path::Path; -use torrust_tracker_configuration::Configuration; +use torrust_tracker_configuration::{Configuration, Error}; // Environment variables @@ -37,18 +37,33 @@ const ENV_VAR_DEFAULT_CONFIG_PATH: &str = "./config.toml"; #[must_use] pub fn initialize_configuration() -> Configuration { if env::var(ENV_VAR_CONFIG).is_ok() { - println!("Loading configuration from env var {ENV_VAR_CONFIG}"); + println!("Loading configuration from env var {ENV_VAR_CONFIG} ..."); Configuration::load_from_env_var(ENV_VAR_CONFIG).unwrap() } else { let config_path = env::var(ENV_VAR_CONFIG_PATH).unwrap_or_else(|_| ENV_VAR_DEFAULT_CONFIG_PATH.to_string()); - if Path::new(&config_path).is_file(){ - println!("Loading configuration from config file: `{config_path}`"); - } else { - println!("Creating default config file: `{config_path}`"); - } + println!("Loading configuration from configuration file: `{config_path}` ..."); - Configuration::load_from_file(&config_path).expect("Error loading configuration from file") + load_from_file_or_create_default(&config_path).unwrap() + } +} + +/// Loads the configuration from the configuration file. If the file does +/// not exist, it will create a default configuration file and return an +/// error. +/// +/// # Errors +/// +/// Will return `Err` if `path` does not exist or has a bad configuration. +fn load_from_file_or_create_default(path: &str) -> Result { + if Path::new(&path).is_file() { + Configuration::load_from_file(path) + } else { + println!("Missing configuration file."); + println!("Creating a default configuration file: `{path}` ..."); + let config = Configuration::create_default_configuration_file(path)?; + println!("Please review the config file: `{path}` and restart the tracker if needed."); + Ok(config) } } From ec7bd7d8a14e050d695941d93cd5691e28e4a4c3 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 8 Aug 2023 12:25:56 +0100 Subject: [PATCH 5/5] fix: env var name. Wrong prefix --- src/bootstrap/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index eef3265f9..727bf59f7 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -13,7 +13,7 @@ use torrust_tracker_configuration::{Configuration, Error}; const ENV_VAR_CONFIG: &str = "TORRUST_TRACKER_CONFIG"; /// The `config.toml` file location. -pub const ENV_VAR_CONFIG_PATH: &str = "TORRUST_IDX_BACK_CONFIG_PATH"; +pub const ENV_VAR_CONFIG_PATH: &str = "TORRUST_TRACKER_CONFIG_PATH"; // Default values