diff --git a/share/default/config/index.container.mysql.toml b/share/default/config/index.container.mysql.toml index 9a53efb6..b0c9aaf5 100644 --- a/share/default/config/index.container.mysql.toml +++ b/share/default/config/index.container.mysql.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/share/default/config/index.container.sqlite3.toml b/share/default/config/index.container.sqlite3.toml index 5abf23f4..43cafe68 100644 --- a/share/default/config/index.container.sqlite3.toml +++ b/share/default/config/index.container.sqlite3.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/share/default/config/index.development.sqlite3.toml b/share/default/config/index.development.sqlite3.toml index c2b8b582..07a77e56 100644 --- a/share/default/config/index.development.sqlite3.toml +++ b/share/default/config/index.development.sqlite3.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/share/default/config/index.private.e2e.container.sqlite3.toml b/share/default/config/index.private.e2e.container.sqlite3.toml index 8747c579..64f39dbe 100644 --- a/share/default/config/index.private.e2e.container.sqlite3.toml +++ b/share/default/config/index.private.e2e.container.sqlite3.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/share/default/config/index.public.e2e.container.mysql.toml b/share/default/config/index.public.e2e.container.mysql.toml index 0382c12c..56742eb4 100644 --- a/share/default/config/index.public.e2e.container.mysql.toml +++ b/share/default/config/index.public.e2e.container.mysql.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/share/default/config/index.public.e2e.container.sqlite3.toml b/share/default/config/index.public.e2e.container.sqlite3.toml index e04d0ef6..09dd725b 100644 --- a/share/default/config/index.public.e2e.container.sqlite3.toml +++ b/share/default/config/index.public.e2e.container.sqlite3.toml @@ -1,3 +1,5 @@ +version = "2" + [logging] log_level = "info" diff --git a/src/config/mod.rs b/src/config/mod.rs index 9a80d7da..dbf94d8d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,5 @@ //! Configuration for the application. -pub mod v1; +pub mod v2; pub mod validator; use std::str::FromStr; @@ -7,6 +7,7 @@ use std::sync::Arc; use std::{env, fmt}; use camino::Utf8PathBuf; +use derive_more::Display; use figment::providers::{Env, Format, Serialized, Toml}; use figment::Figment; use serde::{Deserialize, Serialize}; @@ -18,34 +19,37 @@ use url::Url; use crate::web::api::server::DynError; -pub type Settings = v1::Settings; +pub type Settings = v2::Settings; -pub type Api = v1::api::Api; +pub type Api = v2::api::Api; -pub type Auth = v1::auth::Auth; -pub type EmailOnSignup = v1::auth::EmailOnSignup; -pub type SecretKey = v1::auth::SecretKey; -pub type PasswordConstraints = v1::auth::PasswordConstraints; +pub type Auth = v2::auth::Auth; +pub type EmailOnSignup = v2::auth::EmailOnSignup; +pub type SecretKey = v2::auth::SecretKey; +pub type PasswordConstraints = v2::auth::PasswordConstraints; -pub type Database = v1::database::Database; +pub type Database = v2::database::Database; -pub type ImageCache = v1::image_cache::ImageCache; +pub type ImageCache = v2::image_cache::ImageCache; -pub type Mail = v1::mail::Mail; -pub type Smtp = v1::mail::Smtp; -pub type Credentials = v1::mail::Credentials; +pub type Mail = v2::mail::Mail; +pub type Smtp = v2::mail::Smtp; +pub type Credentials = v2::mail::Credentials; -pub type Network = v1::net::Network; +pub type Network = v2::net::Network; -pub type TrackerStatisticsImporter = v1::tracker_statistics_importer::TrackerStatisticsImporter; +pub type TrackerStatisticsImporter = v2::tracker_statistics_importer::TrackerStatisticsImporter; -pub type Tracker = v1::tracker::Tracker; -pub type ApiToken = v1::tracker::ApiToken; +pub type Tracker = v2::tracker::Tracker; +pub type ApiToken = v2::tracker::ApiToken; -pub type Logging = v1::logging::Logging; -pub type LogLevel = v1::logging::LogLevel; +pub type Logging = v2::logging::Logging; +pub type LogLevel = v2::logging::LogLevel; -pub type Website = v1::website::Website; +pub type Website = v2::website::Website; + +/// Configuration version +const VERSION_2: &str = "2"; /// Prefix for env vars that overwrite configuration options. const CONFIG_OVERRIDE_PREFIX: &str = "TORRUST_INDEX_CONFIG_OVERRIDE_"; @@ -60,6 +64,63 @@ pub const ENV_VAR_CONFIG_TOML: &str = "TORRUST_INDEX_CONFIG_TOML"; /// The `index.toml` file location. pub const ENV_VAR_CONFIG_TOML_PATH: &str = "TORRUST_INDEX_CONFIG_TOML_PATH"; +pub const LATEST_VERSION: &str = "2"; + +/// Info about the configuration specification. +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Display, Clone)] +pub struct Metadata { + #[serde(default = "Metadata::default_version")] + #[serde(flatten)] + version: Version, +} + +impl Default for Metadata { + fn default() -> Self { + Self { + version: Self::default_version(), + } + } +} + +impl Metadata { + fn default_version() -> Version { + Version::latest() + } +} + +/// The configuration version. +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Display, Clone)] +pub struct Version { + #[serde(default = "Version::default_semver")] + version: String, +} + +impl Default for Version { + fn default() -> Self { + Self { + version: Self::default_semver(), + } + } +} + +impl Version { + fn new(semver: &str) -> Self { + Self { + version: semver.to_owned(), + } + } + + fn latest() -> Self { + Self { + version: LATEST_VERSION.to_string(), + } + } + + fn default_semver() -> String { + LATEST_VERSION.to_string() + } +} + /// Information required for loading config #[derive(Debug, Default, Clone)] pub struct Info { @@ -125,6 +186,9 @@ pub enum Error { #[error("The error for errors that can never happen.")] Infallible, + + #[error("Unsupported configuration version: {version}")] + UnsupportedVersion { version: Version }, } impl From for Error { @@ -284,6 +348,12 @@ impl Configuration { let settings: Settings = figment.extract()?; + if settings.metadata.version != Version::new(VERSION_2) { + return Err(Error::UnsupportedVersion { + version: settings.metadata.version, + }); + } + Ok(settings) } @@ -335,7 +405,9 @@ mod tests { #[cfg(test)] fn default_config_toml() -> String { - let config = r#"[logging] + let config = r#"version = "2" + + [logging] log_level = "info" [website] diff --git a/src/config/v1/api.rs b/src/config/v2/api.rs similarity index 100% rename from src/config/v1/api.rs rename to src/config/v2/api.rs diff --git a/src/config/v1/auth.rs b/src/config/v2/auth.rs similarity index 100% rename from src/config/v1/auth.rs rename to src/config/v2/auth.rs diff --git a/src/config/v1/database.rs b/src/config/v2/database.rs similarity index 100% rename from src/config/v1/database.rs rename to src/config/v2/database.rs diff --git a/src/config/v1/image_cache.rs b/src/config/v2/image_cache.rs similarity index 100% rename from src/config/v1/image_cache.rs rename to src/config/v2/image_cache.rs diff --git a/src/config/v1/logging.rs b/src/config/v2/logging.rs similarity index 100% rename from src/config/v1/logging.rs rename to src/config/v2/logging.rs diff --git a/src/config/v1/mail.rs b/src/config/v2/mail.rs similarity index 100% rename from src/config/v1/mail.rs rename to src/config/v2/mail.rs diff --git a/src/config/v1/mod.rs b/src/config/v2/mod.rs similarity index 95% rename from src/config/v1/mod.rs rename to src/config/v2/mod.rs index 9e73d93e..6412a4e2 100644 --- a/src/config/v1/mod.rs +++ b/src/config/v2/mod.rs @@ -22,10 +22,15 @@ use self::tracker::{ApiToken, Tracker}; use self::tracker_statistics_importer::TrackerStatisticsImporter; use self::website::Website; use super::validator::{ValidationError, Validator}; +use super::Metadata; /// The whole configuration for the index. #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] pub struct Settings { + /// Configuration metadata. + #[serde(flatten)] + pub metadata: Metadata, + /// The logging configuration. #[serde(default)] pub logging: Logging, diff --git a/src/config/v1/net.rs b/src/config/v2/net.rs similarity index 100% rename from src/config/v1/net.rs rename to src/config/v2/net.rs diff --git a/src/config/v1/tracker.rs b/src/config/v2/tracker.rs similarity index 100% rename from src/config/v1/tracker.rs rename to src/config/v2/tracker.rs diff --git a/src/config/v1/tracker_statistics_importer.rs b/src/config/v2/tracker_statistics_importer.rs similarity index 100% rename from src/config/v1/tracker_statistics_importer.rs rename to src/config/v2/tracker_statistics_importer.rs diff --git a/src/config/v1/website.rs b/src/config/v2/website.rs similarity index 100% rename from src/config/v1/website.rs rename to src/config/v2/website.rs diff --git a/src/web/api/client/v1/contexts/settings/mod.rs b/src/web/api/client/v1/contexts/settings/mod.rs index 4c1b371f..df8433d6 100644 --- a/src/web/api/client/v1/contexts/settings/mod.rs +++ b/src/web/api/client/v1/contexts/settings/mod.rs @@ -5,7 +5,7 @@ use std::net::SocketAddr; use serde::{Deserialize, Serialize}; use url::Url; -use crate::config::v1::tracker::ApiToken; +use crate::config::v2::tracker::ApiToken; use crate::config::{ Api as DomainApi, Auth as DomainAuth, Credentials as DomainCredentials, Database as DomainDatabase, ImageCache as DomainImageCache, Mail as DomainMail, Network as DomainNetwork,