Skip to content

Commit 90ef14d

Browse files
committed
feat!: [#938] add mandatory config options
Some configuration options are mandatory. The tracker will panic if the user doesn't provide an explicit value for them from one of the configuration sources: TOML or ENV VARS. The mandatory options are: ```toml [metadata] schema_version = "2.0.0" [logging] threshold = "info" [core] private = false listed = false ```
1 parent f95b16a commit 90ef14d

7 files changed

Lines changed: 133 additions & 12 deletions

File tree

packages/configuration/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ pub enum Error {
303303

304304
#[error("Unsupported configuration version: {version}")]
305305
UnsupportedVersion { version: Version },
306+
307+
#[error("Missing mandatory configuration option. Option path: {path}")]
308+
MissingMandatoryOption { path: String },
306309
}
307310

308311
impl From<figment::Error> for Error {

packages/configuration/src/v2_0_0/mod.rs

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -313,27 +313,33 @@ impl Configuration {
313313
}
314314

315315
/// Loads the configuration from the `Info` struct. The whole
316-
/// configuration in toml format is included in the `info.tracker_toml` string.
316+
/// configuration in toml format is included in the `info.tracker_toml`
317+
/// string.
317318
///
318-
/// Optionally will override the admin api token.
319+
/// Configuration provided via env var has priority over config file path.
319320
///
320321
/// # Errors
321322
///
322323
/// Will return `Err` if the environment variable does not exist or has a bad configuration.
323324
pub fn load(info: &Info) -> Result<Configuration, Error> {
325+
// Load configuration provided by the user, prioritizing env vars
324326
let figment = if let Some(config_toml) = &info.config_toml {
325-
// Config in env var has priority over config file path
326-
Figment::from(Serialized::defaults(Configuration::default()))
327-
.merge(Toml::string(config_toml))
328-
.merge(Env::prefixed(CONFIG_OVERRIDE_PREFIX).split(CONFIG_OVERRIDE_SEPARATOR))
327+
Figment::from(Toml::string(config_toml)).merge(Env::prefixed(CONFIG_OVERRIDE_PREFIX).split(CONFIG_OVERRIDE_SEPARATOR))
329328
} else {
330-
Figment::from(Serialized::defaults(Configuration::default()))
331-
.merge(Toml::file(&info.config_toml_path))
329+
Figment::from(Toml::file(&info.config_toml_path))
332330
.merge(Env::prefixed(CONFIG_OVERRIDE_PREFIX).split(CONFIG_OVERRIDE_SEPARATOR))
333331
};
334332

333+
// Make sure user has provided the mandatory options.
334+
Self::check_mandatory_options(&figment)?;
335+
336+
// Fill missing options with default values.
337+
let figment = figment.join(Serialized::defaults(Configuration::default()));
338+
339+
// Build final configuration.
335340
let config: Configuration = figment.extract()?;
336341

342+
// Make sure the provided schema version matches this version.
337343
if config.metadata.schema_version != Version::new(VERSION_2_0_0) {
338344
return Err(Error::UnsupportedVersion {
339345
version: config.metadata.schema_version,
@@ -343,6 +349,28 @@ impl Configuration {
343349
Ok(config)
344350
}
345351

352+
/// Some configuration options are mandatory. The tracker will panic if
353+
/// the user doesn't provide an explicit value for them from one of the
354+
/// configuration sources: TOML or ENV VARS.
355+
///
356+
/// # Errors
357+
///
358+
/// Will return an error if a mandatory configuration option is only
359+
/// obtained by default value (code), meaning the user hasn't overridden it.
360+
fn check_mandatory_options(figment: &Figment) -> Result<(), Error> {
361+
let mandatory_options = ["metadata.schema_version", "logging.threshold", "core.private", "core.listed"];
362+
363+
for mandatory_option in mandatory_options {
364+
figment
365+
.find_value(mandatory_option)
366+
.map_err(|_err| Error::MissingMandatoryOption {
367+
path: mandatory_option.to_owned(),
368+
})?;
369+
}
370+
371+
Ok(())
372+
}
373+
346374
/// Saves the configuration to the configuration file.
347375
///
348376
/// # Errors
@@ -496,14 +524,25 @@ mod tests {
496524
}
497525

498526
#[test]
499-
fn configuration_should_use_the_default_values_when_an_empty_configuration_is_provided_by_the_user() {
527+
fn configuration_should_use_the_default_values_when_only_the_mandatory_options_are_provided_by_the_user_via_toml_file() {
500528
figment::Jail::expect_with(|jail| {
501-
jail.create_file("tracker.toml", "")?;
529+
jail.create_file(
530+
"tracker.toml",
531+
r#"
532+
[metadata]
533+
schema_version = "2.0.0"
534+
535+
[logging]
536+
threshold = "info"
502537
503-
let empty_configuration = String::new();
538+
[core]
539+
listed = false
540+
private = false
541+
"#,
542+
)?;
504543

505544
let info = Info {
506-
config_toml: Some(empty_configuration),
545+
config_toml: None,
507546
config_toml_path: "tracker.toml".to_string(),
508547
};
509548

@@ -515,10 +554,49 @@ mod tests {
515554
});
516555
}
517556

557+
#[test]
558+
fn configuration_should_use_the_default_values_when_only_the_mandatory_options_are_provided_by_the_user_via_toml_content() {
559+
figment::Jail::expect_with(|_jail| {
560+
let config_toml = r#"
561+
[metadata]
562+
schema_version = "2.0.0"
563+
564+
[logging]
565+
threshold = "info"
566+
567+
[core]
568+
listed = false
569+
private = false
570+
"#
571+
.to_string();
572+
573+
let info = Info {
574+
config_toml: Some(config_toml),
575+
config_toml_path: String::new(),
576+
};
577+
578+
let configuration = Configuration::load(&info).expect("Could not load configuration from file");
579+
580+
assert_eq!(configuration, Configuration::default());
581+
582+
Ok(())
583+
});
584+
}
585+
518586
#[test]
519587
fn default_configuration_could_be_overwritten_from_a_single_env_var_with_toml_contents() {
520588
figment::Jail::expect_with(|_jail| {
521589
let config_toml = r#"
590+
[metadata]
591+
schema_version = "2.0.0"
592+
593+
[logging]
594+
threshold = "info"
595+
596+
[core]
597+
listed = false
598+
private = false
599+
522600
[core.database]
523601
path = "OVERWRITTEN DEFAULT DB PATH"
524602
"#
@@ -543,6 +621,16 @@ mod tests {
543621
jail.create_file(
544622
"tracker.toml",
545623
r#"
624+
[metadata]
625+
schema_version = "2.0.0"
626+
627+
[logging]
628+
threshold = "info"
629+
630+
[core]
631+
listed = false
632+
private = false
633+
546634
[core.database]
547635
path = "OVERWRITTEN DEFAULT DB PATH"
548636
"#,

share/default/config/tracker.container.mysql.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ app = "torrust-tracker"
33
purpose = "configuration"
44
schema_version = "2.0.0"
55

6+
[logging]
7+
threshold = "info"
8+
9+
[core]
10+
listed = false
11+
private = false
12+
613
[core.database]
714
driver = "mysql"
815
path = "mysql://db_user:db_user_secret_password@mysql:3306/torrust_tracker"

share/default/config/tracker.container.sqlite3.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ app = "torrust-tracker"
33
purpose = "configuration"
44
schema_version = "2.0.0"
55

6+
[logging]
7+
threshold = "info"
8+
9+
[core]
10+
listed = false
11+
private = false
12+
613
[core.database]
714
path = "/var/lib/torrust/tracker/database/sqlite3.db"
815

share/default/config/tracker.development.sqlite3.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ app = "torrust-tracker"
33
purpose = "configuration"
44
schema_version = "2.0.0"
55

6+
[logging]
7+
threshold = "info"
8+
9+
[core]
10+
listed = false
11+
private = false
12+
613
[[udp_trackers]]
714
bind_address = "0.0.0.0:6969"
815

share/default/config/tracker.e2e.container.sqlite3.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ app = "torrust-tracker"
33
purpose = "configuration"
44
schema_version = "2.0.0"
55

6+
[logging]
7+
threshold = "info"
8+
9+
[core]
10+
listed = false
11+
private = false
12+
613
[core.database]
714
path = "/var/lib/torrust/tracker/database/sqlite3.db"
815

share/default/config/tracker.udp.benchmarking.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ schema_version = "2.0.0"
77
threshold = "error"
88

99
[core]
10+
listed = false
11+
private = false
1012
remove_peerless_torrents = false
1113
tracker_usage_statistics = false
1214

0 commit comments

Comments
 (0)