aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..a55f271
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,143 @@
+use std::sync::Arc;
+
+use log::*;
+use structopt::StructOpt;
+use tokio::select;
+use tokio::sync::watch;
+
+mod dns_config;
+mod dns_updater;
+mod provider;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "d53")]
+pub struct Opt {
+ /// Address of consul server
+ #[structopt(
+ long = "consul-addr",
+ env = "D53_CONSUL_HOST",
+ default_value = "http://127.0.0.1:8500"
+ )]
+ pub consul_addr: String,
+
+ /// CA certificate for Consul server with TLS
+ #[structopt(long = "consul-ca-cert", env = "D53_CONSUL_CA_CERT")]
+ pub consul_ca_cert: Option<String>,
+
+ /// Skip TLS verification for Consul
+ #[structopt(long = "consul-tls-skip-verify", env = "D53_CONSUL_TLS_SKIP_VERIFY")]
+ pub consul_tls_skip_verify: bool,
+
+ /// Client certificate for Consul server with TLS
+ #[structopt(long = "consul-client-cert", env = "D53_CONSUL_CLIENT_CERT")]
+ pub consul_client_cert: Option<String>,
+
+ /// Client key for Consul server with TLS
+ #[structopt(long = "consul-client-key", env = "D53_CONSUL_CLIENT_KEY")]
+ pub consul_client_key: Option<String>,
+
+ /// DNS provider
+ #[structopt(long = "provider", env = "D53_PROVIDER")]
+ pub provider: String,
+
+ /// Allowed domains
+ #[structopt(long = "allowed-domains", env = "D53_ALLOWED_DOMAINS")]
+ pub allowed_domains: String,
+
+ /// API key for Gandi DNS provider
+ #[structopt(long = "gandi-api-key", env = "D53_GANDI_API_KEY")]
+ pub gandi_api_key: Option<String>,
+}
+
+#[tokio::main]
+async fn main() {
+ if std::env::var("RUST_LOG").is_err() {
+ std::env::set_var("RUST_LOG", "tricot=info")
+ }
+ pretty_env_logger::init();
+
+ // Abort on panic (same behavior as in Go)
+ std::panic::set_hook(Box::new(|panic_info| {
+ error!("{}", panic_info.to_string());
+ std::process::abort();
+ }));
+
+ let opt = Opt::from_args();
+
+ info!("Starting D53");
+
+ let (exit_signal, _) = watch_ctrl_c();
+
+ let consul_config = df_consul::ConsulConfig {
+ addr: opt.consul_addr.clone(),
+ ca_cert: opt.consul_ca_cert.clone(),
+ tls_skip_verify: opt.consul_tls_skip_verify,
+ client_cert: opt.consul_client_cert.clone(),
+ client_key: opt.consul_client_key.clone(),
+ };
+
+ let consul = df_consul::Consul::new(consul_config, "").expect("Cannot build Consul");
+
+ let provider: Box<dyn provider::DnsProvider> = match opt.provider.as_str() {
+ "gandi" => Box::new(
+ provider::gandi::GandiProvider::new(&opt).expect("Cannot initialize Gandi provier"),
+ ),
+ p => panic!("Unsupported DNS provider: {}", p),
+ };
+
+ let allowed_domains = opt
+ .allowed_domains
+ .split(',')
+ .map(ToString::to_string)
+ .collect::<Vec<_>>();
+
+ let rx_dns_config = dns_config::spawn_dns_config_task(consul.clone(), exit_signal.clone());
+
+ let updater_task = tokio::spawn(dns_updater::dns_updater_task(
+ rx_dns_config.clone(),
+ provider,
+ allowed_domains,
+ exit_signal.clone(),
+ ));
+ let dump_task = tokio::spawn(dump_config_on_change(rx_dns_config, exit_signal));
+
+ updater_task.await.expect("Tokio task await failure");
+ dump_task.await.expect("Tokio task await failure");
+}
+
+async fn dump_config_on_change(
+ mut rx_dns_config: watch::Receiver<Arc<dns_config::DnsConfig>>,
+ mut must_exit: watch::Receiver<bool>,
+) {
+ while !*must_exit.borrow() {
+ select!(
+ c = rx_dns_config.changed() => {
+ if c.is_err() {
+ break;
+ }
+ }
+ _ = must_exit.changed() => continue,
+ );
+ println!("---- DNS CONFIGURATION ----");
+ for (k, v) in rx_dns_config.borrow().entries.iter() {
+ println!(" {} {}", k, v);
+ }
+ println!();
+ }
+}
+
+/// Creates a watch that contains `false`, and that changes
+/// to `true` when a Ctrl+C signal is received.
+pub fn watch_ctrl_c() -> (watch::Receiver<bool>, Arc<watch::Sender<bool>>) {
+ let (send_cancel, watch_cancel) = watch::channel(false);
+ let send_cancel = Arc::new(send_cancel);
+ let send_cancel_2 = send_cancel.clone();
+ tokio::spawn(async move {
+ tokio::signal::ctrl_c()
+ .await
+ .expect("failed to install CTRL+C signal handler");
+ info!("Received CTRL+C, shutting down.");
+ send_cancel.send(true).unwrap();
+ });
+ (watch_cancel, send_cancel_2)
+}