mirror of
https://github.com/SeriousBug/gandi-live-dns-rust
synced 2024-12-27 23:59:56 -06:00
parent
84bef554b0
commit
5755aedc2f
119
src/config.rs
119
src/config.rs
|
@ -5,10 +5,15 @@ use serde::Deserialize;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn default_types() -> Vec<String> {
|
||||||
|
DEFAULT_TYPES.iter().map(|v| v.to_string()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
types: Option<Vec<String>>,
|
#[serde(default = "default_types")]
|
||||||
|
types: Vec<String>,
|
||||||
fqdn: Option<String>,
|
fqdn: Option<String>,
|
||||||
ttl: Option<u32>,
|
ttl: Option<u32>,
|
||||||
}
|
}
|
||||||
|
@ -54,11 +59,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types<'e>(entry: &'e Entry) -> Vec<&'e str> {
|
pub fn types<'e>(entry: &'e Entry) -> Vec<&'e str> {
|
||||||
entry
|
entry.types.iter().map(|t| t.as_str()).collect()
|
||||||
.types
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|ts| Some(ts.iter().map(|t| t.as_str()).collect()))
|
|
||||||
.unwrap_or_else(|| DEFAULT_TYPES.to_vec())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ fn load_config_from<P: std::convert::AsRef<std::path::Path>>(path: P) -> anyhow:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config(opts: &opts::Opts) -> anyhow::Result<Config> {
|
pub fn load_config(opts: &opts::Opts) -> anyhow::Result<Config> {
|
||||||
match &opts.config {
|
let mut config = match &opts.config {
|
||||||
Some(config_path) => load_config_from(&config_path),
|
Some(config_path) => load_config_from(&config_path),
|
||||||
None => {
|
None => {
|
||||||
let confpath = ProjectDirs::from("me", "kaangenc", "gandi-dynamic-dns")
|
let confpath = ProjectDirs::from("me", "kaangenc", "gandi-dynamic-dns")
|
||||||
|
@ -85,7 +86,23 @@ pub fn load_config(opts: &opts::Opts) -> anyhow::Result<Config> {
|
||||||
load_config_from(path)
|
load_config_from(path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}?;
|
||||||
|
// Filter out any types skipped in CLI opts
|
||||||
|
if opts.skip_ipv4 || opts.skip_ipv6 {
|
||||||
|
config.entry = config
|
||||||
|
.entry
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut entry| {
|
||||||
|
entry.types = entry
|
||||||
|
.types
|
||||||
|
.into_iter()
|
||||||
|
.filter(|v| (v == "A" && !opts.skip_ipv4) || (v == "AAAA" && !opts.skip_ipv6))
|
||||||
|
.collect();
|
||||||
|
entry
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_config(config: &Config) -> anyhow::Result<()> {
|
pub fn validate_config(config: &Config) -> anyhow::Result<()> {
|
||||||
|
@ -117,6 +134,9 @@ fqdn = "example.com"
|
||||||
api_key = "xxx"
|
api_key = "xxx"
|
||||||
ttl = 300
|
ttl = 300
|
||||||
|
|
||||||
|
[[entry]]
|
||||||
|
name = "www"
|
||||||
|
|
||||||
[[entry]]
|
[[entry]]
|
||||||
name = "@"
|
name = "@"
|
||||||
"#,
|
"#,
|
||||||
|
@ -125,14 +145,18 @@ name = "@"
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
config: Some(temp.to_string_lossy().to_string()),
|
config: Some(temp.to_string_lossy().to_string()),
|
||||||
|
..Opts::default()
|
||||||
};
|
};
|
||||||
let conf = load_config(&opts).expect("Failed to load config file");
|
let conf = load_config(&opts).expect("Failed to load config file");
|
||||||
|
|
||||||
assert_eq!(conf.fqdn, "example.com");
|
assert_eq!(conf.fqdn, "example.com");
|
||||||
assert_eq!(conf.api_key, "xxx");
|
assert_eq!(conf.api_key, "xxx");
|
||||||
assert_eq!(conf.ttl, 300);
|
assert_eq!(conf.ttl, 300);
|
||||||
assert_eq!(conf.entry.len(), 1);
|
assert_eq!(conf.entry.len(), 2);
|
||||||
assert_eq!(conf.entry[0].name, "@");
|
assert_eq!(conf.entry[0].name, "www");
|
||||||
|
assert_eq!(conf.entry[0].types, vec!["A".to_string()]);
|
||||||
|
assert_eq!(conf.entry[1].name, "@");
|
||||||
|
assert_eq!(conf.entry[1].types, vec!["A".to_string()]);
|
||||||
// default
|
// default
|
||||||
assert_eq!(conf.ip_source, IPSourceName::Ipify);
|
assert_eq!(conf.ip_source, IPSourceName::Ipify);
|
||||||
}
|
}
|
||||||
|
@ -161,6 +185,7 @@ name = "@"
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
config: Some(temp.to_string_lossy().to_string()),
|
config: Some(temp.to_string_lossy().to_string()),
|
||||||
|
..Opts::default()
|
||||||
};
|
};
|
||||||
let conf = load_config(&opts).expect("Failed to load config file");
|
let conf = load_config(&opts).expect("Failed to load config file");
|
||||||
|
|
||||||
|
@ -172,4 +197,80 @@ name = "@"
|
||||||
assert_eq!(conf.entry[1].name, "@");
|
assert_eq!(conf.entry[1].name, "@");
|
||||||
assert_eq!(conf.ip_source, IPSourceName::Icanhazip);
|
assert_eq!(conf.ip_source, IPSourceName::Icanhazip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_config_skip_ipv4_with_opts() {
|
||||||
|
let mut temp = temp_dir().join("gandi-live-dns-test");
|
||||||
|
fs::create_dir_all(&temp).expect("Failed to create test dir");
|
||||||
|
temp.push("test-3.toml");
|
||||||
|
fs::write(
|
||||||
|
&temp,
|
||||||
|
r#"
|
||||||
|
fqdn = "example.com"
|
||||||
|
api_key = "yyy"
|
||||||
|
|
||||||
|
[[entry]]
|
||||||
|
name = "www"
|
||||||
|
types = ["A", "AAAA"]
|
||||||
|
|
||||||
|
[[entry]]
|
||||||
|
name = "@"
|
||||||
|
types = ["A", "AAAA"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("Failed to write test config file");
|
||||||
|
|
||||||
|
let opts = Opts {
|
||||||
|
config: Some(temp.to_string_lossy().to_string()),
|
||||||
|
skip_ipv4: true,
|
||||||
|
..Opts::default()
|
||||||
|
};
|
||||||
|
let conf = load_config(&opts).expect("Failed to load config file");
|
||||||
|
|
||||||
|
assert_eq!(conf.fqdn, "example.com");
|
||||||
|
assert_eq!(conf.api_key, "yyy");
|
||||||
|
assert_eq!(conf.entry.len(), 2);
|
||||||
|
assert_eq!(conf.entry[0].name, "www");
|
||||||
|
assert_eq!(conf.entry[0].types, vec!["AAAA".to_string()]);
|
||||||
|
assert_eq!(conf.entry[1].name, "@");
|
||||||
|
assert_eq!(conf.entry[1].types, vec!["AAAA".to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_config_skip_ipv6_with_opts() {
|
||||||
|
let mut temp = temp_dir().join("gandi-live-dns-test");
|
||||||
|
fs::create_dir_all(&temp).expect("Failed to create test dir");
|
||||||
|
temp.push("test-4.toml");
|
||||||
|
fs::write(
|
||||||
|
&temp,
|
||||||
|
r#"
|
||||||
|
fqdn = "example.com"
|
||||||
|
api_key = "yyy"
|
||||||
|
|
||||||
|
[[entry]]
|
||||||
|
name = "www"
|
||||||
|
types = ["A", "AAAA"]
|
||||||
|
|
||||||
|
[[entry]]
|
||||||
|
name = "@"
|
||||||
|
types = ["A", "AAAA"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("Failed to write test config file");
|
||||||
|
|
||||||
|
let opts = Opts {
|
||||||
|
config: Some(temp.to_string_lossy().to_string()),
|
||||||
|
skip_ipv6: true,
|
||||||
|
..Opts::default()
|
||||||
|
};
|
||||||
|
let conf = load_config(&opts).expect("Failed to load config file");
|
||||||
|
|
||||||
|
assert_eq!(conf.fqdn, "example.com");
|
||||||
|
assert_eq!(conf.api_key, "yyy");
|
||||||
|
assert_eq!(conf.entry.len(), 2);
|
||||||
|
assert_eq!(conf.entry[0].name, "www");
|
||||||
|
assert_eq!(conf.entry[0].types, vec!["A".to_string()]);
|
||||||
|
assert_eq!(conf.entry[1].name, "@");
|
||||||
|
assert_eq!(conf.entry[1].types, vec!["A".to_string()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,6 +179,7 @@ mod tests {
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
config: Some(temp.to_string_lossy().to_string()),
|
config: Some(temp.to_string_lossy().to_string()),
|
||||||
|
..Opts::default()
|
||||||
};
|
};
|
||||||
let conf = config::load_config(&opts).expect("Failed to load config");
|
let conf = config::load_config(&opts).expect("Failed to load config");
|
||||||
run::<IPSourceMock>(server.base_url().as_str(), conf)
|
run::<IPSourceMock>(server.base_url().as_str(), conf)
|
||||||
|
|
12
src/opts.rs
12
src/opts.rs
|
@ -1,10 +1,20 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
/// A tool to automatically update DNS entries on Gandi, using it as a dynamic DNS system.
|
/// A tool to automatically update DNS entries on Gandi, using it as a dynamic DNS system.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug, Default)]
|
||||||
#[clap(author, version, about, long_about = None, name = "gandi-live-dns")]
|
#[clap(author, version, about, long_about = None, name = "gandi-live-dns")]
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
/// The path to the configuration file.
|
/// The path to the configuration file.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub config: Option<String>,
|
pub config: Option<String>,
|
||||||
|
/// Skip IPv4 updates.
|
||||||
|
///
|
||||||
|
/// If enabled, any IPv4 (A) records in the configuration file are ignored.
|
||||||
|
#[clap(action, long)]
|
||||||
|
pub skip_ipv4: bool,
|
||||||
|
/// Skip IPv4 updates.
|
||||||
|
///
|
||||||
|
/// If enabled, any IPv6 (AAAA) records in the configuration file are ignored.
|
||||||
|
#[clap(action, long)]
|
||||||
|
pub skip_ipv6: bool,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue