Move .env configuration to config.toml

This commit is contained in:
Neshura 2023-12-29 00:36:01 +01:00
parent 4ba04706b5
commit f78f735b2c
Signed by: Neshura
GPG key ID: B6983AAA6B9A7A6C
5 changed files with 128 additions and 40 deletions

7
Cargo.lock generated
View file

@ -118,7 +118,6 @@ version = "1.1.1-rc.2"
dependencies = [
"chrono",
"confy",
"dotenv",
"ipnet",
"log",
"reqwest",
@ -178,12 +177,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
name = "encoding_rs"
version = "0.8.33"

View file

@ -20,6 +20,5 @@ strum_macros = "^0.24.3"
log = "^0.4.20"
systemd-journal-logger = "^2.1.1"
confy = "^0.5.1"
dotenv = "^0.15.0"
ipnet = "^2.9.0"
url = "2.5.0"

View file

@ -1,5 +1,4 @@
use std::collections::HashMap;
use std::env;
use std::env::VarError;
use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr};
@ -11,7 +10,7 @@ use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, IntoStaticStr};
use systemd_journal_logger::connected_to_journal;
use url::ParseError;
use crate::config::{ZoneConfig, ZoneEntry};
use crate::config::{AppConfig, ZoneConfig, ZoneEntry};
const API_BASE: &str = "https://api.cloudflare.com/client/v4";
@ -34,8 +33,8 @@ pub(crate) struct CloudflareZone {
}
impl CloudflareZone {
pub(crate) fn new(zone: &ZoneConfig) -> Result<Self, VarError> {
let key = env::var("CF_API_TOKEN")?;
pub(crate) fn new(zone: &ZoneConfig, config: &AppConfig) -> Result<Self, VarError> {
let key = config.cloudflare_api_token.clone();
Ok(Self {
name: zone.name.clone(),
email: zone.email.clone(),

View file

@ -140,3 +140,47 @@ impl Default for ZoneConfig {
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub(crate) struct AppConfig {
#[serde(alias="cf_api_token")]
pub(crate) cloudflare_api_token: String,
pub(crate) check_interval_seconds: Option<u16>,
pub(crate) uptime_url: Option<String>,
}
impl AppConfig {
pub(crate) fn load() -> Result<Self, Box<dyn Error>> {
let cfg: Self = match confy::load(env!("CARGO_PKG_NAME"),"config") {
Ok(data) => data,
Err(e) => {
match connected_to_journal() {
true => error!("[ERROR] {e}"),
false => eprintln!("[ERROR] {e}")
}
return Err(Box::new(e));
}
};
if cfg.cloudflare_api_token.is_empty() {
let err_msg = "Cloudflare api token not specified. The app cannot work without this";
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}")
}
panic!("{err_msg}");
}
Ok(cfg)
}
}
impl Default for AppConfig {
fn default() -> Self {
Self {
cloudflare_api_token: "".to_owned(),
check_interval_seconds: None,
uptime_url: None
}
}
}

View file

@ -1,16 +1,15 @@
/*use cloudflare_old::{Instance, CloudflareDnsType};*/
use reqwest::blocking::get;
use std::{env, thread::{sleep}};
use std::{thread::{sleep}};
use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use chrono::{Utc, Duration};
use dotenv::dotenv;
use log::{info, warn, error, LevelFilter};
use reqwest::StatusCode;
use systemd_journal_logger::{connected_to_journal, JournalLog};
use crate::cloudflare::{CloudflareZone, DnsRecordType};
use crate::config::{InterfaceConfig, ZoneConfig, ZoneEntry};
use crate::config::{AppConfig, InterfaceConfig, ZoneConfig, ZoneEntry};
mod config;
mod cloudflare;
@ -233,10 +232,10 @@ fn compare_zones(old_zone: &ZoneConfig, new_zone: &ZoneConfig) -> Vec<String> {
}
fn main() {
dotenv().ok();
JournalLog::new().expect("Systemd-Logger crate error").install().expect("Systemd-Logger crate error");
log::set_max_level(LevelFilter::Info);
let mut config = AppConfig::load().unwrap();
let mut ifaces = InterfaceConfig::load().unwrap();
let mut zone_cfgs = ZoneConfig::load().unwrap();
@ -248,32 +247,22 @@ fn main() {
Err(e) => panic!("{}", e)
};
let reload_interval = match env::var("CHECK_INTERVAL_SECONDS") {
Ok(interval_string) => i64::from_str(&interval_string).unwrap_or_else(|e| {
let warn_msg = format!("Expected integer number, got '{interval_string}'. Defaulting to 60");
match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"),
};
60
}),
Err(_) => {
let warn_msg = "Reload interval env not set, defaulting to 60";
let reload_interval = config.check_interval_seconds.unwrap_or_else(|| {
let warn_msg = "Reload interval option not set, defaulting to 60";
match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"),
}
60
},
};
}) as i64;
loop {
now = Utc::now();
if now >= start + Duration::seconds(reload_interval) {
start = now;
if let Ok(uptime_url) = env::var("UPTIME_URL") {
get(uptime_url);
if let Some(uptime_url) = &config.uptime_url {
let _ = get(uptime_url);
}
match InterfaceConfig::load() {
@ -353,10 +342,9 @@ fn main() {
ifaces = new_cfg
}
},
Err(e) => {
let err_msg = format!("Unable to load ínterfaces.toml with error: {}", e);
let err_msg = format!("Unable to load ínterfaces.toml with error: {e}");
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"),
@ -496,7 +484,72 @@ fn main() {
}
}
Err(e) => {
let err_msg = format!("Unable to load from zones.d with error: {}", e);
let err_msg = format!("Unable to load from zones.d with error: {e}");
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"),
}
}
}
match AppConfig::load() {
Ok(new_cfg) => {
if config != new_cfg {
if config.cloudflare_api_token != new_cfg.cloudflare_api_token {
let info_msg = "API token in config.toml changed";
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
if config.check_interval_seconds != new_cfg.check_interval_seconds {
let info_msg = match config.check_interval_seconds {
Some(old_interval) => {
match new_cfg.check_interval_seconds {
Some(new_interval) => format!("Check interval in config.toml changed from {old_interval}s to {new_interval}s"),
None => format!("Check interval in config.toml changed from {old_interval}s to 60s"),
}
},
None => {
match new_cfg.check_interval_seconds {
Some(new_interval) => format!("Check interval in config.toml changed from 60s to {new_interval}s"),
None => "This is a unicorn error, congratulations.".to_owned(),
}
}
};
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
if config.uptime_url != new_cfg.uptime_url {
let info_msg = match &config.uptime_url {
Some(old_url) => {
match &new_cfg.uptime_url {
Some(new_url) => format!("Uptime URL in config.toml changed from '{old_url}' to '{new_url}'"),
None => "Uptime URL in config.toml was removed".to_owned(),
}
},
None => {
match &new_cfg.uptime_url {
Some(new_url) => format!("Uptime URL '{new_url}' was added to config.toml"),
None => "This is a unicorn error, congratulations.".to_owned(),
}
}
};
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
config = new_cfg
}
}
Err(e) => {
let err_msg = format!("Unable to load config.toml with error: {e}");
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"),
@ -506,7 +559,7 @@ fn main() {
ips.update();
for zone in &zone_cfgs {
let cf_zone = match CloudflareZone::new(zone) {
let cf_zone = match CloudflareZone::new(zone, &config) {
Ok(data) => data,
Err(e) => {
let err_msg = format!("Cloudflare Token likely not set. Error: {}", e);