pub mod catalog; mod kv; pub mod locking; mod with_index; use std::fs::File; use std::io::Read; use anyhow::{bail, Result}; pub use with_index::WithIndex; /// Configuration parameters to talk to a Consul server pub struct Config { /// HTTP address of the Consul server, with `http://` or `https://` prefix pub addr: String, /// CA certificate of the Consul CA, when using TLS pub ca_cert: Option, /// Client certificate for client auth when using TLS pub client_cert: Option, /// Client key for client auth when using TLS pub client_key: Option, /// Skip verification of consul server TLS certificates pub tls_skip_verify: bool, } /// Client used to talk to a Consul server. /// All calls to the key/value API are automatically prefixed with an arbitrary string /// that is constructed at client creation. #[derive(Clone)] pub struct Consul { client: reqwest::Client, url: String, kv_prefix: String, } impl Consul { pub fn new(config: Config, kv_prefix: &str) -> Result { let client = match (&config.client_cert, &config.client_key) { (Some(client_cert), Some(client_key)) => { let mut client_cert_buf = vec![]; File::open(client_cert)?.read_to_end(&mut client_cert_buf)?; let mut client_key_buf = vec![]; File::open(client_key)?.read_to_end(&mut client_key_buf)?; let identity = reqwest::Identity::from_pem( &[&client_cert_buf[..], &client_key_buf[..]].concat()[..], )?; if config.tls_skip_verify { reqwest::Client::builder() .use_rustls_tls() .danger_accept_invalid_certs(true) .identity(identity) .build()? } else if let Some(ca_cert) = &config.ca_cert { let mut ca_cert_buf = vec![]; File::open(ca_cert)?.read_to_end(&mut ca_cert_buf)?; reqwest::Client::builder() .use_rustls_tls() .add_root_certificate(reqwest::Certificate::from_pem(&ca_cert_buf[..])?) .identity(identity) .build()? } else { reqwest::Client::builder() .use_rustls_tls() .identity(identity) .build()? } } (None, None) => reqwest::Client::new(), _ => bail!("Incomplete Consul TLS configuration parameters"), }; Ok(Self { client, url: config.addr.trim_end_matches('/').to_string(), kv_prefix: kv_prefix.to_string(), }) } }