Support for # key values in comment (friendly_name at the moment) (#44)

* Draft support for friendly_name

* updated version and readme
This commit is contained in:
Francesco Cogno 2020-10-11 16:21:51 +02:00 committed by GitHub
parent d65b8f5862
commit e77a3e26ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 27 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "prometheus_wireguard_exporter" name = "prometheus_wireguard_exporter"
version = "3.3.2" version = "3.4.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"

View file

@ -4,11 +4,11 @@
[![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.3.2) [![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.4.0)
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.3.2) [![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.4.0)
[![Rust build](https://github.com/mindflavor/prometheus_wireguard_exporter/workflows/Rust/badge.svg)](https://github.com/mindflavor/prometheus_wireguard_exporter/actions?query=workflow%3ARust) [![Rust build](https://github.com/mindflavor/prometheus_wireguard_exporter/workflows/Rust/badge.svg)](https://github.com/mindflavor/prometheus_wireguard_exporter/actions?query=workflow%3ARust)
[![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.3.2.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.3.2.svg) [![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.4.0.svg)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.4.0.svg)
## Intro ## Intro
@ -18,7 +18,7 @@ A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rus
## Changelog ## Changelog
* From release [3.3.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.2) the exporter parses the peer file in a case-insensitive manner. * **BREAKING** From release [3.4.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.4.0) the exporter requires you to specify the friendly names in a specific format (only if you want to use them of course). This allows you to use arbitrary comments in the file while keeping the friendly name functionality. Thank you [Miloš Bunčić](https://github.com/psyhomb) for this. This also paves the way for future metadata. In order to migrate you can use this sed command: `sed -i 's/#/# friendly_name=/' peers.conf`. Please make sure to do a backup before using it!
* From release [3.3.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.1) the exporter accepts multiple interfaces in the command line options. Just pass the `-i` parameter multiple times. Note the not specifying the interface is equivalent to specifying every one of them (the exporter will pass the `all` parameter to `wg show` command). * From release [3.3.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.1) the exporter accepts multiple interfaces in the command line options. Just pass the `-i` parameter multiple times. Note the not specifying the interface is equivalent to specifying every one of them (the exporter will pass the `all` parameter to `wg show` command).
* **BREAKING** Starting from release [3.3.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.0) the exporter allows you to specify a different interface from the file name. Previously if you specified the file name (the `-n` flag) the program would infer the interface name from the file name. Now the two items are decoupled: you need to specify the file name (with `-n`) and the interface name (with `-i`) separately. Thank you [Vincent Debergue](https://github.com/vdebergue) for helping with this (see issue [#22](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/22)). Upgrading from [3.2.4](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.2.4): Please note that the `-n` flag no longer infer automatically the interface name from the file name. We now have the `-i` parameter for that. In order to keep the previous behaviour (if you use the `-n` flag) please add the `-i` flag to the command line arguments as well. For example, if you had `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf` you must specify `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf -i wg0` to keep the same behaviour. * **BREAKING** Starting from release [3.3.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.3.0) the exporter allows you to specify a different interface from the file name. Previously if you specified the file name (the `-n` flag) the program would infer the interface name from the file name. Now the two items are decoupled: you need to specify the file name (with `-n`) and the interface name (with `-i`) separately. Thank you [Vincent Debergue](https://github.com/vdebergue) for helping with this (see issue [#22](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/22)). Upgrading from [3.2.4](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.2.4): Please note that the `-n` flag no longer infer automatically the interface name from the file name. We now have the `-i` parameter for that. In order to keep the previous behaviour (if you use the `-n` flag) please add the `-i` flag to the command line arguments as well. For example, if you had `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf` you must specify `prometheus_wireguard_exporter -n /etc/wireguard/wg0.conf -i wg0` to keep the same behaviour.
* 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 issue [#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 issue [#8](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/8)).
@ -136,31 +136,34 @@ wireguard_latest_handshake_seconds{interface="wg0",public_key="928vO9Lf4+Mo84cWu
wireguard_latest_handshake_seconds{interface="wg0",public_key="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowed_ips="10.70.0.5/32",friendly_name="folioarch"} 0 wireguard_latest_handshake_seconds{interface="wg0",public_key="wTjv6hS6fKfNK+SzOLo7O6BQjEb6AD1TN9GjwZ08IwA=",allowed_ips="10.70.0.5/32",friendly_name="folioarch"} 0
``` ```
In order for this to work, you need to add comments to your wireguard configuration file (below the `[Peer]` definition). The comment will be interpreted as `friendly_name` and added to the entry exported to Prometheus. Note that this is not a standard but, since it's a comment, will not interfere with WireGuard in any way. For example this is how you edit your WireGuard configuration file: In order for this to work, you need to add the `friendly_name` key value to the comments preceding a peer a specific metadata (in your wireguard configuration file). See below the `[Peer]` definition for an example.
The tag is called `friendly_name` and it will be added to the entry exported to Prometheus. Note that this is not a standard but, since it's a comment, will not interfere with WireGuard in any way. For example this is how you edit your WireGuard configuration file:
``` ```toml
[Peer] [Peer]
PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc= PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=
AllowedIPs = 10.70.0.40/32 AllowedIPs = 10.70.0.40/32
[Peer] [Peer]
# Custom comment
PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
AllowedIPs = 10.70.0.80/32 AllowedIPs = 10.70.0.80/32
``` ```
``` ```toml
[Peer] [Peer]
# frcognowin10 # friendly_name = frcognowin10
PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc= PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=
AllowedIPs = 10.70.0.40/32 AllowedIPs = 10.70.0.40/32
[Peer] [Peer]
# OnePlus 5T # friendly_name = OnePlus 5T
# Custom comment
PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
AllowedIPs = 10.70.0.80/32 AllowedIPs = 10.70.0.80/32
``` ```
As you can see, all you need to do is to add the friendly name as comment (and enable the flag since this feature is opt-in). As you can see, all you need to do is to add the friendly name in the comments preceding a peer (and enable the flag since this feature is opt-in).
This is a sample of the label split mode: This is a sample of the label split mode:

View file

@ -23,6 +23,21 @@ fn after_char(s: &str, c_split: char) -> &str {
s s
} }
fn from_pound_line_to_key_value(line: &str) -> Option<(&str, &str)> {
// since the pound sign is 1 byte the below slice will work
let line = &line[1..];
let equals_pos = line.find('=');
if let Some(equals_pos) = equals_pos {
// we should trim the key
let key = &line[..equals_pos].trim();
// we should trim the value as well? this can be debated
let value = &line[equals_pos + 1..].trim();
Some((key, value))
} else {
None
}
}
impl<'a> TryFrom<&[&'a str]> for PeerEntry<'a> { impl<'a> TryFrom<&[&'a str]> for PeerEntry<'a> {
type Error = PeerEntryParseError; type Error = PeerEntryParseError;
@ -40,9 +55,16 @@ impl<'a> TryFrom<&[&'a str]> for PeerEntry<'a> {
public_key = after_char(line, '=').trim(); public_key = after_char(line, '=').trim();
} else if line_lowercase.starts_with("allowedips") { } else if line_lowercase.starts_with("allowedips") {
allowed_ips = after_char(line, '=').trim(); allowed_ips = after_char(line, '=').trim();
} else if line.starts_with('#') { } else if line.trim().starts_with('#') {
// since the pound sign is 1 byte the below slice will work if let Some((key, value)) = from_pound_line_to_key_value(line) {
name = Some(line[1..].trim()); // if it's a supported key, let' map it
match key {
"friendly_name" => {
name = Some(value);
}
_ => {}
}
}
} }
} }
@ -129,17 +151,22 @@ PrivateKey = my_super_secret_private_key
# PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE # PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
[Peer] [Peer]
# OnePlus 6T # This is a comment
# friendly_name=OnePlus 6T
# This is a comment
# This is a comment
# This is a comment
# This is a comment
PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk= PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
AllowedIPs = 10.70.0.2/32 AllowedIPs = 10.70.0.2/32
[Peer] [Peer]
# varch.local (laptop) # friendly_name=varch.local (laptop)
PublicKey = qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU= PublicKey = qnoxQoQI8KKMupLnSSureORV0wMmH7JryZNsmGVISzU=
AllowedIPs = 10.70.0.3/32 AllowedIPs = 10.70.0.3/32
[Peer] [Peer]
# cantarch # friendly_name=cantarch
PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008= PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
AllowedIPs = 10.70.0.4/32 AllowedIPs = 10.70.0.4/32
@ -149,12 +176,14 @@ PublicKey = MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=
AllowedIPs = 10.70.0.50/32 AllowedIPs = 10.70.0.50/32
[Peer] [Peer]
# frcognowin10 # This is a comment
# friendly_name = frcognowin10
# This is something
PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc= PublicKey = lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=
AllowedIPs = 10.70.0.40/32 AllowedIPs = 10.70.0.40/32
[Peer] [Peer]
# OnePlus 5T #friendly_name = OnePlus 5T
PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk= PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
AllowedIPs = 10.70.0.80/32 AllowedIPs = 10.70.0.80/32
"; ";
@ -166,16 +195,16 @@ PrivateKey = my_super_secret_private_key
# PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE # PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
[Peer] [Peer]
# OnePlus 6T # friendly_name = OnePlus 6T
PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk= PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
AllowedIPs = 10.70.0.2/32 AllowedIPs = 10.70.0.2/32
[Peer] [Peer]
# varch.local (laptop) # friendly_name = varch.local (laptop)
AllowedIPs = 10.70.0.3/32 AllowedIPs = 10.70.0.3/32
[Peer] [Peer]
# cantarch #friendly_name= cantarch
PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008= PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
AllowedIPs = 10.70.0.4/32 AllowedIPs = 10.70.0.4/32
"; ";
@ -187,29 +216,75 @@ PrivateKey = my_super_secret_private_key
# PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE # PostDown = iptables -t nat -D POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
[Peer] [Peer]
# OnePlus 6T # friendly_name=OnePlus 6T
PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk= PublicKey = 2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
AllowedIPs = 10.70.0.2/32 AllowedIPs = 10.70.0.2/32
[Peer] [Peer]
# varch.local (laptop) # friendly_name=varch.local (laptop)
AllowedIPs = 10.70.0.3/32 AllowedIPs = 10.70.0.3/32
PublicKey = 6S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk= PublicKey = 6S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=
[Peer] [Peer]
# cantarch # friendly_name=cantarch
PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008= PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
"; ";
#[test]
fn test_from_pound_line_to_key_value() {
let a = from_pound_line_to_key_value("# ignore");
assert_eq!(None, a);
let a = from_pound_line_to_key_value("# soooo much space ");
assert_eq!(None, a);
let a = from_pound_line_to_key_value(
"# test = This can be tricky ",
);
let a = a.expect("this should have been Some!");
assert_eq!(a.0, "test");
assert_eq!(a.1, "This can be tricky");
let a = from_pound_line_to_key_value("# nasty =");
let a = a.expect("this should have been Some!");
assert_eq!(a.0, "nasty");
assert_eq!(a.1, "");
let a = from_pound_line_to_key_value("# nasty 2 = ");
let a = a.expect("this should have been Some!");
assert_eq!(a.0, "nasty 2");
assert_eq!(a.1, "");
}
#[test] #[test]
fn test_parse_ok() { fn test_parse_ok() {
let a: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT).unwrap(); let a: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT).unwrap();
println!("{:?}", a); println!("{:?}", a);
} }
#[test]
fn test_parse_friendly_name() {
let a: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT).unwrap();
let entry = a.get("2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=");
let entry = entry.expect("this should have been Some!");
assert_eq!(Some("OnePlus 6T"), entry.name);
let entry = a.get("lqYcojJMsIZXMUw1heAFbQHBoKjCEaeo7M1WXDh/KWc=");
let entry = entry.expect("this should have been Some!");
assert_eq!(Some("frcognowin10"), entry.name);
let entry = a.get("928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=");
let entry = entry.expect("this should have been Some!");
assert_eq!(Some("OnePlus 5T"), entry.name);
let entry = a.get("MdVOIPKt9K2MPj/sO2NlWQbOnFJ6L/qX80mmhQwsUlA=");
let entry = entry.expect("this should have been Some!");
assert_eq!(None, entry.name);
}
#[test] #[test]
#[should_panic( #[should_panic(
expected = "PublicKeyNotFound { lines: [\"# varch.local (laptop)\", \"AllowedIPs = 10.70.0.3/32\"] }" expected = "PublicKeyNotFound { lines: [\"# friendly_name = varch.local (laptop)\", \"AllowedIPs = 10.70.0.3/32\"] }"
)] )]
fn test_parse_no_public_key() { fn test_parse_no_public_key() {
let _: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT_NOPK).unwrap(); let _: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT_NOPK).unwrap();
@ -217,7 +292,7 @@ PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
#[test] #[test]
#[should_panic( #[should_panic(
expected = "AllowedIPsEntryNotFound { lines: [\"# cantarch\", \"PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=\"] }" expected = "AllowedIPsEntryNotFound { lines: [\"# friendly_name=cantarch\", \"PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=\"] }"
)] )]
fn test_parse_no_allowed_ips() { fn test_parse_no_allowed_ips() {
let _: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT_AIP).unwrap(); let _: PeerEntryHashMap = peer_entry_hashmap_try_from(TEXT_AIP).unwrap();