prometheus_wireguard_exporter/src/main.rs

160 lines
5 KiB
Rust
Raw Normal View History

2019-04-23 23:06:35 +02:00
extern crate serde_json;
#[macro_use]
extern crate failure;
use clap;
2019-06-09 20:09:06 +02:00
use clap::{crate_authors, crate_name, crate_version, Arg};
2019-04-23 23:06:35 +02:00
use futures::future::{done, ok, Either, Future};
2019-06-09 20:09:06 +02:00
use hyper::{Body, Request, Response};
use log::{info, trace};
2019-04-23 23:06:35 +02:00
use std::env;
mod options;
use options::Options;
mod wireguard;
use std::convert::TryFrom;
use std::process::Command;
use std::string::String;
use wireguard::WireGuard;
2019-06-09 20:09:06 +02:00
mod exporter_error;
2019-05-15 16:55:07 +02:00
mod wireguard_config;
2019-05-20 10:09:02 +02:00
use wireguard_config::peer_entry_hashmap_try_from;
2019-06-09 20:09:06 +02:00
extern crate prometheus_exporter_base;
use crate::exporter_error::ExporterError;
use prometheus_exporter_base::render_prometheus;
use std::sync::Arc;
use std::net::Ipv4Addr;
2019-04-23 23:06:35 +02:00
2019-05-20 09:45:20 +02:00
fn wg_with_text(
wg_config_str: &str,
wg_output: ::std::process::Output,
2019-07-11 15:31:25 +02:00
options: Arc<Options>,
2019-05-20 09:45:20 +02:00
) -> Result<Response<Body>, ExporterError> {
2019-05-20 10:09:02 +02:00
let pehm = peer_entry_hashmap_try_from(wg_config_str)?;
trace!("pehm == {:?}", pehm);
2019-05-20 09:45:20 +02:00
let wg_output_string = String::from_utf8(wg_output.stdout)?;
let wg = WireGuard::try_from(&wg_output_string as &str)?;
2019-07-11 15:31:25 +02:00
Ok(Response::new(Body::from(wg.render_with_names(
Some(&pehm),
options.separate_allowed_ips,
options.export_remote_ip_and_port,
2019-07-11 15:31:25 +02:00
))))
2019-05-20 09:45:20 +02:00
}
2019-04-23 23:06:35 +02:00
fn perform_request(
_req: Request<Body>,
2019-06-09 20:09:06 +02:00
options: &Arc<Options>,
) -> impl Future<Item = Response<Body>, Error = failure::Error> {
2019-04-23 23:06:35 +02:00
trace!("perform_request");
2019-05-17 19:32:35 +02:00
// this is needed to satisfy the borrow checker
let options = options.clone();
2019-04-23 23:06:35 +02:00
done(
Command::new("wg")
.arg("show")
.arg("all")
.arg("dump")
.output(),
)
.from_err()
2019-06-09 20:09:06 +02:00
.and_then(move |output| {
if let Some(extract_names_config_file) = &options.extract_names_config_file {
2019-05-17 19:32:35 +02:00
Either::A(
2019-05-20 09:45:20 +02:00
done(::std::fs::read_to_string(extract_names_config_file))
2019-05-17 19:32:35 +02:00
.from_err()
2019-07-11 15:31:25 +02:00
.and_then(|wg_config_string| {
wg_with_text(&wg_config_string as &str, output, options)
2019-05-17 19:32:35 +02:00
}),
)
2019-07-11 15:31:25 +02:00
} else {
Either::B(done(String::from_utf8(output.stdout)).from_err().and_then(
move |output_str| {
trace!("{}", output_str);
done(WireGuard::try_from(&output_str as &str))
.from_err()
.and_then(move |wg| {
ok(Response::new(Body::from(wg.render_with_names(
None,
options.separate_allowed_ips,
options.export_remote_ip_and_port,
))))
2019-07-11 15:31:25 +02:00
})
},
))
2019-05-17 19:32:35 +02:00
}
2019-04-23 23:06:35 +02:00
})
2019-06-09 20:09:06 +02:00
.from_err()
2019-04-23 23:06:35 +02:00
}
fn main() {
2019-06-09 20:09:06 +02:00
let matches = clap::App::new(crate_name!())
.version(crate_version!())
.author(crate_authors!("\n"))
.arg(
Arg::with_name("addr")
.short("l")
.help("exporter address")
.default_value("127.0.0.1")
.takes_value(true),
)
2019-04-23 23:06:35 +02:00
.arg(
Arg::with_name("port")
.short("p")
2019-05-17 19:32:35 +02:00
.help("exporter port")
2019-05-20 11:23:28 +02:00
.default_value("9586")
2019-04-23 23:06:35 +02:00
.takes_value(true),
)
.arg(
Arg::with_name("verbose")
.short("v")
.help("verbose logging")
.takes_value(false),
)
2019-05-17 19:32:35 +02:00
.arg(
2019-07-11 15:31:25 +02:00
Arg::with_name("separate_allowed_ips")
.short("s")
.help("separate allowed ips and ports")
.takes_value(false),
)
.arg(
Arg::with_name("export_remote_ip_and_port")
.short("r")
.help("exports peer's remote ip and port as labels (if available)")
.takes_value(false),
)
.arg(
2019-05-17 19:32:35 +02:00
Arg::with_name("extract_names_config_file")
.short("n")
.help("If set, the exporter will look in the specified WireGuard config file for peer names (must be in [Peer] definition and be a comment)")
.takes_value(true))
2019-04-23 23:06:35 +02:00
.get_matches();
let options = Options::from_claps(&matches);
if options.verbose {
2019-06-09 20:09:06 +02:00
env::set_var(
"RUST_LOG",
format!("{}=trace,prometheus_exporter_base=trace", crate_name!()),
);
2019-04-23 23:06:35 +02:00
} else {
2019-06-09 20:09:06 +02:00
env::set_var(
"RUST_LOG",
format!("{}=info,prometheus_exporter_base=info", crate_name!()),
);
2019-04-23 23:06:35 +02:00
}
env_logger::init();
info!("using options: {:?}", options);
let bind = matches.value_of("port").unwrap();
let bind = u16::from_str_radix(&bind, 10).expect("port must be a valid number");
let ip = matches.value_of("addr").unwrap().parse::<Ipv4Addr>().unwrap();
let addr = (ip, bind).into();
2019-04-23 23:06:35 +02:00
info!("starting exporter on http://{}/metrics", addr);
2019-04-23 23:06:35 +02:00
2019-06-09 20:09:06 +02:00
render_prometheus(&addr, options, |request, options| {
Box::new(perform_request(request, options))
});
2019-04-23 23:06:35 +02:00
}