wg show <interface> if specified in the command line (#17)
Using `interface` instead of `all` if specified
This commit is contained in:
parent
42ae2f5927
commit
e04a3f833b
4 changed files with 107 additions and 36 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "prometheus_wireguard_exporter"
|
name = "prometheus_wireguard_exporter"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
authors = ["Francesco Cogno <francesco.cogno@outlook.com>"]
|
authors = ["Francesco Cogno <francesco.cogno@outlook.com>"]
|
||||||
description = "Prometheus WireGuard Exporter"
|
description = "Prometheus WireGuard Exporter"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
|
|
||||||
[![Crate](https://img.shields.io/crates/v/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratedown](https://img.shields.io/crates/d/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratelastdown](https://img.shields.io/crates/dv/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter)
|
[![Crate](https://img.shields.io/crates/v/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratedown](https://img.shields.io/crates/d/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter) [![cratelastdown](https://img.shields.io/crates/dv/prometheus_wireguard_exporter.svg)](https://crates.io/crates/prometheus_wireguard_exporter)
|
||||||
|
|
||||||
[![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.1.1)
|
[![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.2.0)
|
||||||
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.1.1)
|
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.2.0)
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter.svg?branch=master)](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter)
|
[![Build Status](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter.svg?branch=master)](https://travis-ci.org/MindFlavor/prometheus_wireguard_exporter)
|
||||||
[![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.1.1.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.1.1.svg)
|
[![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.2.0.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.2.0.svg)
|
||||||
|
|
||||||
## Intro
|
## Intro
|
||||||
|
|
||||||
A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rust. This tool exports the `wg show all dump` results in a format that [Prometheus](https://prometheus.io/) can understand. The exporter is very light on your server resources, both in terms of memory and CPU usage.
|
A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rust. This tool exports the `wg show all dump` (or `wg show <interface> dump` if you specify a config file) results in a format that [Prometheus](https://prometheus.io/) can understand. The exporter is very light on your server resources, both in terms of memory and CPU usage.
|
||||||
|
|
||||||
Starting from release [2.0.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/2.0.2) this exporter supports IPv6 addressess too (thanks to [Maximilian Bosch](https://github.com/Ma27)'s PR [#5](https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/5)).
|
Starting from release [2.0.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/2.0.2) this exporter supports IPv6 addressess too (thanks to [Maximilian Bosch](https://github.com/Ma27)'s PR [#5](https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/5)).
|
||||||
From release [3.0.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.0.0) the exporter allows two label modes: one is to dump every allowed ip in a single label (called `allowed_ips`) along with their subnets. The second one is to create a pair of labels for each allowed ip/subnet pair (called `allowed_ip_0`/`allowed_subnet_0`, `allowed_ip_1`/`allowed_subnet_1` and so on for every allowed ip). The default if the single label mode but you can enable the second mode by specifying the `-s` switch at startup. Thank you [Toon Schoenmakers](https://github.com/schoentoon) for this solution (see [https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8)).
|
From release [3.0.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.0.0) the exporter allows two label modes: one is to dump every allowed ip in a single label (called `allowed_ips`) along with their subnets. The second one is to create a pair of labels for each allowed ip/subnet pair (called `allowed_ip_0`/`allowed_subnet_0`, `allowed_ip_1`/`allowed_subnet_1` and so on for every allowed ip). The default if the single label mode but you can enable the second mode by specifying the `-s` switch at startup. Thank you [Toon Schoenmakers](https://github.com/schoentoon) for this solution (see [https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8)).
|
||||||
|
|
91
src/main.rs
91
src/main.rs
|
@ -5,7 +5,7 @@ use clap;
|
||||||
use clap::{crate_authors, crate_name, crate_version, Arg};
|
use clap::{crate_authors, crate_name, crate_version, Arg};
|
||||||
use futures::future::{done, ok, Either, Future};
|
use futures::future::{done, ok, Either, Future};
|
||||||
use hyper::{Body, Request, Response};
|
use hyper::{Body, Request, Response};
|
||||||
use log::{info, trace};
|
use log::{debug, info, trace};
|
||||||
use std::env;
|
use std::env;
|
||||||
mod options;
|
mod options;
|
||||||
use options::Options;
|
use options::Options;
|
||||||
|
@ -25,14 +25,13 @@ use std::sync::Arc;
|
||||||
|
|
||||||
fn wg_with_text(
|
fn wg_with_text(
|
||||||
wg_config_str: &str,
|
wg_config_str: &str,
|
||||||
wg_output: ::std::process::Output,
|
wg_output_str: &str,
|
||||||
options: Arc<Options>,
|
options: Arc<Options>,
|
||||||
) -> Result<Response<Body>, ExporterError> {
|
) -> Result<Response<Body>, ExporterError> {
|
||||||
let pehm = peer_entry_hashmap_try_from(wg_config_str)?;
|
let pehm = peer_entry_hashmap_try_from(wg_config_str)?;
|
||||||
trace!("pehm == {:?}", pehm);
|
trace!("pehm == {:?}", pehm);
|
||||||
|
|
||||||
let wg_output_string = String::from_utf8(wg_output.stdout)?;
|
let wg = WireGuard::try_from(wg_output_str)?;
|
||||||
let wg = WireGuard::try_from(&wg_output_string as &str)?;
|
|
||||||
Ok(Response::new(Body::from(wg.render_with_names(
|
Ok(Response::new(Body::from(wg.render_with_names(
|
||||||
Some(&pehm),
|
Some(&pehm),
|
||||||
options.separate_allowed_ips,
|
options.separate_allowed_ips,
|
||||||
|
@ -45,45 +44,75 @@ fn perform_request(
|
||||||
options: &Arc<Options>,
|
options: &Arc<Options>,
|
||||||
) -> impl Future<Item = Response<Body>, Error = failure::Error> {
|
) -> impl Future<Item = Response<Body>, Error = failure::Error> {
|
||||||
trace!("perform_request");
|
trace!("perform_request");
|
||||||
|
|
||||||
// this is needed to satisfy the borrow checker
|
// this is needed to satisfy the borrow checker
|
||||||
let options = options.clone();
|
let options = options.clone();
|
||||||
|
debug!("options == {:?}", options);
|
||||||
|
|
||||||
|
//let interface = options.get_interface();
|
||||||
|
|
||||||
|
let interface_str = match options.get_interface() {
|
||||||
|
Some(interface_str) => interface_str,
|
||||||
|
None => "all",
|
||||||
|
}
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
debug!("using inteface_str {}", interface_str);
|
||||||
|
|
||||||
done(
|
done(
|
||||||
Command::new("wg")
|
Command::new("wg")
|
||||||
.arg("show")
|
.arg("show")
|
||||||
.arg("all")
|
.arg(&interface_str)
|
||||||
.arg("dump")
|
.arg("dump")
|
||||||
.output(),
|
.output(),
|
||||||
)
|
)
|
||||||
.from_err()
|
.from_err()
|
||||||
.and_then(move |output| {
|
.and_then(move |output| {
|
||||||
if let Some(extract_names_config_file) = &options.extract_names_config_file {
|
done(String::from_utf8(output.stdout))
|
||||||
Either::A(
|
.from_err()
|
||||||
done(::std::fs::read_to_string(extract_names_config_file))
|
.and_then(move |output_str| {
|
||||||
.from_err()
|
trace!("wg show output == {}", output_str);
|
||||||
.and_then(|wg_config_string| {
|
|
||||||
wg_with_text(&wg_config_string as &str, output, options)
|
// the output of wg show is different if we use all or we specify an interface.
|
||||||
}),
|
// In the first case the first column will be the interface name. In the second case
|
||||||
)
|
// the interface name will be omitted. We need to compensate for the skew somehow (one
|
||||||
} else {
|
// column less in the second case). We solve this prepending the interface name in every
|
||||||
Either::B(done(String::from_utf8(output.stdout)).from_err().and_then(
|
// line so the output of the second case will be equal to the first case.
|
||||||
move |output_str| {
|
let output_str = if interface_str != "all" {
|
||||||
trace!("{}", output_str);
|
debug!("injecting {} to the wg show output", interface_str);
|
||||||
done(WireGuard::try_from(&output_str as &str))
|
let mut result = String::new();
|
||||||
.from_err()
|
for s in output_str.lines() {
|
||||||
.and_then(move |wg| {
|
result.push_str(&format!("{}\t{}\n", interface_str, s));
|
||||||
ok(Response::new(Body::from(wg.render_with_names(
|
}
|
||||||
None,
|
result
|
||||||
options.separate_allowed_ips,
|
} else {
|
||||||
options.export_remote_ip_and_port,
|
output_str
|
||||||
))))
|
};
|
||||||
})
|
|
||||||
},
|
if let Some(extract_names_config_file) = &options.extract_names_config_file {
|
||||||
))
|
Either::A(
|
||||||
}
|
done(::std::fs::read_to_string(extract_names_config_file))
|
||||||
|
.from_err()
|
||||||
|
.and_then(move |wg_config_string| {
|
||||||
|
wg_with_text(&wg_config_string as &str, &output_str, options)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Either::B({
|
||||||
|
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,
|
||||||
|
))))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.from_err()
|
||||||
})
|
})
|
||||||
.from_err()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -24,4 +24,46 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_interface(&self) -> Option<&str> {
|
||||||
|
if let Some(config_file) = &self.extract_names_config_file {
|
||||||
|
let path = std::path::Path::new(config_file);
|
||||||
|
if let Some(file_stem) = path.file_stem() {
|
||||||
|
file_stem.to_str()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interface_some() {
|
||||||
|
let options = Options {
|
||||||
|
verbose: true,
|
||||||
|
separate_allowed_ips: false,
|
||||||
|
extract_names_config_file: Some("/etc/wireguard/wg0.conf".to_owned()),
|
||||||
|
export_remote_ip_and_port: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(options.get_interface(), Some("wg0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_interface_none() {
|
||||||
|
let options = Options {
|
||||||
|
verbose: true,
|
||||||
|
separate_allowed_ips: false,
|
||||||
|
extract_names_config_file: None,
|
||||||
|
export_remote_ip_and_port: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(options.get_interface(), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue