tricot/src/main.rs

150 lines
3.9 KiB
Rust
Raw Normal View History

#[macro_use]
extern crate anyhow;
use futures::TryFutureExt;
2021-12-07 17:19:51 +00:00
use std::net::SocketAddr;
2021-12-07 16:56:15 +00:00
use structopt::StructOpt;
2021-12-07 12:50:44 +00:00
mod cert;
mod cert_store;
mod consul;
2021-12-07 12:50:44 +00:00
mod http;
2021-12-07 14:20:45 +00:00
mod https;
mod proxy_config;
2021-12-07 14:20:45 +00:00
mod reverse_proxy;
mod tls_util;
use log::*;
2021-12-07 16:56:15 +00:00
#[derive(StructOpt, Debug)]
#[structopt(name = "tricot")]
struct Opt {
/// Address of consul server
#[structopt(
long = "consul-addr",
env = "TRICOT_CONSUL_HOST",
2021-12-08 11:10:58 +00:00
default_value = "http://127.0.0.1:8500"
)]
2021-12-07 16:56:15 +00:00
pub consul_addr: String,
2021-12-30 19:08:10 +00:00
/// CA certificate for Consul server with TLS
#[structopt(long = "consul-ca-cert", env = "TRICOT_CONSUL_CA_CERT")]
pub consul_ca_cert: Option<String>,
/// Client certificate for Consul server with TLS
#[structopt(long = "consul-client-cert", env = "TRICOT_CONSUL_CLIENT_CERT")]
pub consul_client_cert: Option<String>,
/// Client key for Consul server with TLS
#[structopt(long = "consul-client-key", env = "TRICOT_CONSUL_CLIENT_KEY")]
pub consul_client_key: Option<String>,
2021-12-07 16:56:15 +00:00
/// Prefix of Tricot's entries in Consul KV space
#[structopt(
long = "consul-kv-prefix",
env = "TRICOT_CONSUL_KV_PREFIX",
default_value = "tricot/"
)]
2021-12-07 16:56:15 +00:00
pub consul_kv_prefix: String,
/// Node name
#[structopt(long = "node-name", env = "TRICOT_NODE_NAME", default_value = "<none>")]
pub node_name: String,
2021-12-07 17:19:51 +00:00
/// Bind address for HTTP server
#[structopt(
long = "http-bind-addr",
env = "TRICOT_HTTP_BIND_ADDR",
default_value = "0.0.0.0:80"
)]
2021-12-07 17:19:51 +00:00
pub http_bind_addr: SocketAddr,
/// Bind address for HTTPS server
#[structopt(
long = "https-bind-addr",
env = "TRICOT_HTTPS_BIND_ADDR",
default_value = "0.0.0.0:443"
)]
2021-12-07 17:19:51 +00:00
pub https_bind_addr: SocketAddr,
/// E-mail address for Let's Encrypt certificate requests
2021-12-08 12:28:07 +00:00
#[structopt(long = "letsencrypt-email", env = "TRICOT_LETSENCRYPT_EMAIL")]
pub letsencrypt_email: String,
2021-12-09 14:43:19 +00:00
/// Enable compression of responses
#[structopt(long = "enable-compression", env = "TRICOT_ENABLE_COMPRESSION")]
pub enable_compression: bool,
/// Mime types for which to enable compression (comma-separated list)
#[structopt(
long = "compress-mime-types",
env = "TRICOT_COMPRESS_MIME_TYPES",
2021-12-09 15:09:41 +00:00
default_value = "text/html,text/plain,text/css,text/javascript,text/xml,application/javascript,application/json,application/xml,image/svg+xml,font/ttf"
2021-12-09 14:43:19 +00:00
)]
pub compress_mime_types: String,
2021-12-07 16:56:15 +00:00
}
2021-12-07 14:20:45 +00:00
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
2021-12-07 12:50:44 +00:00
if std::env::var("RUST_LOG").is_err() {
2021-12-08 10:24:25 +00:00
std::env::set_var("RUST_LOG", "tricot=info")
2021-12-07 12:50:44 +00:00
}
pretty_env_logger::init();
2021-12-07 16:56:15 +00:00
// Abort on panic (same behavior as in Go)
std::panic::set_hook(Box::new(|panic_info| {
error!("{}", panic_info.to_string());
std::process::abort();
}));
2021-12-07 16:56:15 +00:00
let opt = Opt::from_args();
info!("Starting Tricot");
2021-12-30 19:45:28 +00:00
let consul_config = consul::ConsulConfig {
2021-12-30 19:08:10 +00:00
addr: opt.consul_addr.clone(),
ca_cert: opt.consul_ca_cert.clone(),
client_cert: opt.consul_client_cert.clone(),
client_key: opt.consul_client_key.clone(),
};
let consul = consul::Consul::new(consul_config, &opt.consul_kv_prefix, &opt.node_name)
.expect("Error creating Consul client");
let mut rx_proxy_config = proxy_config::spawn_proxy_config_task(consul.clone());
2021-12-08 12:28:07 +00:00
let cert_store = cert_store::CertStore::new(
consul.clone(),
rx_proxy_config.clone(),
opt.letsencrypt_email.clone(),
);
tokio::spawn(http::serve_http(opt.http_bind_addr, consul.clone()).map_err(exit_on_err));
2021-12-09 14:43:19 +00:00
let https_config = https::HttpsConfig {
bind_addr: opt.https_bind_addr,
enable_compression: opt.enable_compression,
compress_mime_types: opt
.compress_mime_types
2021-12-09 22:38:56 +00:00
.split(',')
2021-12-09 14:43:19 +00:00
.map(|x| x.to_string())
.collect(),
};
tokio::spawn(
2021-12-09 14:43:19 +00:00
https::serve_https(https_config, cert_store.clone(), rx_proxy_config.clone())
.map_err(exit_on_err),
);
2021-12-06 22:40:41 +00:00
while rx_proxy_config.changed().await.is_ok() {
println!("---- PROXY CONFIGURATION ----");
2021-12-07 17:19:51 +00:00
for ent in rx_proxy_config.borrow().entries.iter() {
println!(" {}", ent);
2021-12-07 17:19:51 +00:00
}
println!();
}
}
2021-12-09 11:20:37 +00:00
fn exit_on_err(e: anyhow::Error) {
error!("{}", e);
std::process::exit(1);
}