From 644e7079562b3218243c98c89b5bcb47c1d1ab48 Mon Sep 17 00:00:00 2001 From: LUXEY Adrien Date: Mon, 16 Aug 2021 11:19:16 +0200 Subject: [PATCH] environment.rs successfully replaced with new config/ configuration loader. No API changes, more tests, cleaner code: life is swell. --- .gitignore | 1 + src/config/options.rs | 7 +++--- src/config/runtime.rs | 15 +++++++++--- src/diplonat.rs | 28 ++++++++++++---------- src/environment.rs | 56 ------------------------------------------- src/igd_actor.rs | 4 ++-- src/main.rs | 1 - 7 files changed, 34 insertions(+), 78 deletions(-) delete mode 100644 src/environment.rs diff --git a/.gitignore b/.gitignore index 855a698..142ffb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target/ *.swp +.env diff --git a/src/config/options.rs b/src/config/options.rs index a76cf57..27b1af1 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -9,7 +9,7 @@ use crate::config::RuntimeConfig; // runtime.rs applies business logic and builds RuntimeConfig structs. /// Base configuration options -#[derive(Clone, Debug, Default, Deserialize)] +#[derive(Clone, Default, Deserialize)] pub struct ConfigOptsBase { /// This node's private IP address [default: None] pub private_ip: Option, @@ -20,7 +20,7 @@ pub struct ConfigOptsBase { } /// ACME configuration options -#[derive(Clone, Debug, Default, Deserialize)] +#[derive(Clone, Default, Deserialize)] pub struct ConfigOptsAcme { /// Whether ACME is enabled [default: false] #[serde(default)] @@ -31,7 +31,7 @@ pub struct ConfigOptsAcme { } /// Consul configuration options -#[derive(Clone, Debug, Default, Deserialize)] +#[derive(Clone, Default, Deserialize)] pub struct ConfigOptsConsul { /// Consul's node name [default: None] pub node_name: Option, @@ -40,7 +40,6 @@ pub struct ConfigOptsConsul { } /// Model of all potential configuration options -#[derive(Debug)] pub struct ConfigOpts { pub base: ConfigOptsBase, pub acme: ConfigOptsAcme, diff --git a/src/config/runtime.rs b/src/config/runtime.rs index 6649d39..58c86b9 100644 --- a/src/config/runtime.rs +++ b/src/config/runtime.rs @@ -9,25 +9,30 @@ use crate::config::{ConfigOpts, ConfigOptsAcme, ConfigOptsBase, ConfigOptsConsul // In this file, we take ConfigOpts and transform them into ready-to-use RuntimeConfig. // We apply default values and business logic. +#[derive(Debug)] pub struct RuntimeConfigAcme { pub email: String, } +#[derive(Debug)] pub struct RuntimeConfigConsul { pub node_name: String, pub url: String, } +#[derive(Debug)] pub struct RuntimeConfigFirewall { pub refresh_time: Duration, } +#[derive(Debug)] pub struct RuntimeConfigIgd { pub private_ip: String, pub expiration_time: Duration, pub refresh_time: Duration, } +#[derive(Debug)] pub struct RuntimeConfig { pub acme: Option, pub consul: RuntimeConfigConsul, @@ -57,7 +62,9 @@ impl RuntimeConfigAcme { return Ok(None); } - let email = opts.email.unwrap(); + let email = opts.email.expect( + "'DIPLONAT_ACME_EMAIL' environment variable is required \ + if 'DIPLONAT_ACME_ENABLE' == 'true'"); Ok(Some(Self { email, @@ -67,7 +74,8 @@ impl RuntimeConfigAcme { impl RuntimeConfigConsul { pub(super) fn new(opts: ConfigOptsConsul) -> Result { - let node_name = opts.node_name.unwrap(); + let node_name = opts.node_name.expect( + "'DIPLONAT_CONSUL_NODE_NAME' environment variable is required"); let url = opts.url.unwrap_or(super::CONSUL_URL.to_string()); Ok(Self { @@ -90,7 +98,8 @@ impl RuntimeConfigFirewall { impl RuntimeConfigIgd { pub(super) fn new(opts: ConfigOptsBase) -> Result { - let private_ip = opts.private_ip.unwrap(); + let private_ip = opts.private_ip.expect( + "'DIPLONAT_PRIVATE_IP' environment variable is required"); let expiration_time = Duration::from_secs( opts.expiration_time.unwrap_or(super::EXPIRATION_TIME).into()); let refresh_time = Duration::from_secs( diff --git a/src/diplonat.rs b/src/diplonat.rs index 798b779..7049530 100644 --- a/src/diplonat.rs +++ b/src/diplonat.rs @@ -1,31 +1,35 @@ use anyhow::Result; use tokio::try_join; + +use crate::config::ConfigOpts; use crate::consul_actor::ConsulActor; -use crate::igd_actor::IgdActor; -use crate::environment::Environment; use crate::fw_actor::FirewallActor; +use crate::igd_actor::IgdActor; pub struct Diplonat { consul: ConsulActor, + firewall: FirewallActor, igd: IgdActor, - firewall: FirewallActor } impl Diplonat { pub async fn new() -> Result { - let env = Environment::new()?; - let ca = ConsulActor::new(&env.consul_url, &env.consul_node_name); - let ia = IgdActor::new( - &env.private_ip, - env.refresh_time, - env.expiration_time, - &ca.rx_open_ports - ).await?; + let rt_cfg = ConfigOpts::from_env()?; + println!("{:#?}", rt_cfg); + + let ca = ConsulActor::new(&rt_cfg.consul.url, &rt_cfg.consul.node_name); let fw = FirewallActor::new( - env.refresh_time, + rt_cfg.firewall.refresh_time, &ca.rx_open_ports ).await?; + + let ia = IgdActor::new( + &rt_cfg.igd.private_ip, + rt_cfg.igd.refresh_time, + rt_cfg.igd.expiration_time, + &ca.rx_open_ports + ).await?; let ctx = Self { consul: ca, diff --git a/src/environment.rs b/src/environment.rs deleted file mode 100644 index 335fa37..0000000 --- a/src/environment.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::env; -use anyhow::{Result, Context, anyhow}; -use std::time::Duration; -use log::*; - -const epi: &'static str = "DIPLONAT_PRIVATE_IP"; -const ert: &'static str = "DIPLONAT_REFRESH_TIME"; -const eet: &'static str = "DIPLONAT_EXPIRATION_TIME"; -const ecnd: &'static str = "DIPLONAT_CONSUL_NODE_NAME"; -const ecu: &'static str = "DIPLONAT_CONSUL_URL"; - -pub struct Environment { - pub consul_node_name: String, - pub consul_url: String, - - pub refresh_time: Duration, - pub expiration_time: Duration, - - pub private_ip: String, -} - -/* @FIXME: Rewrite with Serde Envi */ -impl Environment { - pub fn new() -> Result { - let ctx = Self { - consul_url: match env::var(ecu) { Ok(e) => e, Err(_) => "http://127.0.0.1:8500".to_string() }, - consul_node_name: env::var(ecnd).with_context(|| format!("{} env var must be defined", ecnd))?, - private_ip: env::var(epi).with_context(|| format!("{} env var must be defined, eg: 192.168.0.18", epi))?, - refresh_time: Duration::from_secs(env::var(ert) - .with_context(|| format!("{} env var must be defined, eg: 60", ert))? - .parse() - .with_context(|| format!("{} env var must be an integer, eg: 60", ert))?), - expiration_time: Duration::from_secs(env::var(eet) - .with_context(|| format!("{} env var must be defined, eg: 300", eet))? - .parse() - .with_context(|| format!("{} env var must be an integer, eg: 300", eet))?), - }; - - if ctx.refresh_time.as_secs() * 2 > ctx.expiration_time.as_secs() { - return Err(anyhow!( - "Expiration time (currently: {}s) must be twice bigger than refresh time (currently: {}s)", - ctx.refresh_time.as_secs(), - ctx.expiration_time.as_secs())); - } - - info!("Consul URL: {:#?}", ctx.consul_url); - info!("Consul node name: {:#?}", ctx.consul_node_name); - info!("Private IP address: {:#?}", ctx.private_ip); - info!("Refresh time: {:#?} seconds", ctx.refresh_time.as_secs()); - info!("Expiration time: {:#?} seconds", ctx.expiration_time.as_secs()); - - return Ok(ctx); - } -} - - diff --git a/src/igd_actor.rs b/src/igd_actor.rs index 68d20df..55d9c5f 100644 --- a/src/igd_actor.rs +++ b/src/igd_actor.rs @@ -25,8 +25,8 @@ impl IgdActor { pub async fn new(priv_ip: &str, refresh: Duration, expire: Duration, rxp: &watch::Receiver) -> Result { let gw = search_gateway(Default::default()) .await - .context("Failed to find gateway")?; - info!("Gateway: {}", gw); + .context("Failed to find IGD gateway")?; + info!("IGD gateway: {}", gw); let ctx = Self { gateway: gw, diff --git a/src/main.rs b/src/main.rs index 4c4b469..720edf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ mod config; mod consul; mod consul_actor; mod diplonat; -mod environment; mod fw; mod fw_actor; mod igd_actor;