Compare commits

..

No commits in common. "02d4b5ab139c8e3b967f3ce39bca11207131fcfb" and "86cc2519541d4367fe3ab7c4bd27bab4cbc2a8ab" have entirely different histories.

11 changed files with 604 additions and 550 deletions

View file

@ -23,3 +23,6 @@ linker = "s390x-linux-musl-gcc"
[target.riscv64gc-unknown-linux-musl] [target.riscv64gc-unknown-linux-musl]
linker = "riscv64-linux-musl-gcc" linker = "riscv64-linux-musl-gcc"
[target.x86_64-unknown-freebsd]
image = "docker.io/rustembedded/cross:x86_64-unknown-freebsd"

View file

@ -1,58 +0,0 @@
name: CI
on:
push:
branches: [ master ]
tags: [ '*' ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
channel: [stable]
target:
# https://doc.rust-lang.org/nightly/rustc/platform-support.html
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- armv7-unknown-linux-gnueabihf # rpi
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-musl
- armv7-unknown-linux-musleabihf # rpi
- x86_64-unknown-freebsd
# - aarch64-unknown-freebsd <- std not precompiled
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.channel }}
target: ${{ matrix.target }}
override: true
- run: cargo install --git https://github.com/cross-rs/cross.git # cross in crates.io is too old
- name: Build
continue-on-error: ${{ matrix.channel != 'stable' }}
run: cross build --release --target ${{ matrix.target }}
- name: Rename binary
run: mv target/${{ matrix.target }}/release/prometheus_wireguard_exporter prometheus_wireguard_exporter_${{ matrix.target }}
- uses: actions/upload-artifact@v2
if: ${{ matrix.channel == 'stable' }}
with:
name: prometheus_wireguard_exporter_${{ matrix.target }}
path: prometheus_wireguard_exporter_${{ matrix.target }}
- uses: alexellis/upload-assets@0.3.0
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ github.token }}
with:
asset_paths: '["prometheus_wireguard_exporter_${{ matrix.target }}"]'

188
.github/workflows/release-binaries.yml vendored Normal file
View file

@ -0,0 +1,188 @@
name: Deploy binaries and create release
on:
release:
types:
- published
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
github_build:
name: Build release binaries
strategy:
fail-fast: true
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
name: prometheus_wireguard_exporter-x86_64-unknown-linux-gnu
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
name: prometheus_wireguard_exporter-x86_64-unknown-linux-musl
- target: i686-unknown-linux-musl
os: ubuntu-latest
name: prometheus_wireguard_exporter-i686-unknown-linux-musl
- target: aarch64-unknown-linux-musl
os: ubuntu-latest
name: prometheus_wireguard_exporter-aarch64-unknown-linux-musl
- target: arm-unknown-linux-musleabi
os: ubuntu-latest
name: prometheus_wireguard_exporter-arm-unknown-linux-musleabi
# - target: armv7-unknown-linux-musleabi
# os: ubuntu-latest
# name: prometheus_wireguard_exporter-armv7-unknown-linux-musleabi
- target: x86_64-apple-darwin
os: macOS-latest
name: prometheus_wireguard_exporter-x86_64-apple-darwin
# - target: aarch64-apple-darwin
# os: macOS-latest
# name: prometheus_wireguard_exporter-aarch64-apple-darwin
- target: x86_64-pc-windows-msvc
os: windows-latest
name: prometheus_wireguard_exporter-x86_64-pc-windows-msvc.exe
- target: i686-pc-windows-msvc
os: windows-latest
name: prometheus_wireguard_exporter-i686-pc-windows-msvc.exe
# - target: aarch64-pc-windows-msvc
# os: windows-latest
# name: prometheus_wireguard_exporter-aarch64-pc-windows-msvc.exe
- target: x86_64-unknown-freebsd
os: ubuntu-latest
name: prometheus_wireguard_exporter-x86_64-unknown-freebsd
runs-on: ${{ matrix.os }}
continue-on-error: false
steps:
- name: Setup | Checkout
uses: actions/checkout@v2.3.4
- name: Setup | Cache Cargo
uses: actions/cache@v2.1.6
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Setup | Rust
uses: actions-rs/toolchain@v1.0.7
with:
toolchain: stable
override: true
profile: minimal
target: ${{ matrix.target }}
- name: Build | Ubuntu
if: matrix.os != 'macOS-latest'
uses: actions-rs/cargo@v1.0.3
with:
command: build
args: --release --locked --target ${{ matrix.target }}
use-cross: ${{ matrix.os == 'ubuntu-latest' }}
- name: Build | macOS
if: matrix.os == 'macOS-latest'
uses: actions-rs/cargo@v1.0.3
with:
command: build
args: --release --locked --target ${{ matrix.target }}
- name: Post Build | Prepare artifacts [Windows]
if: matrix.os == 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
strip prometheus_wireguard_exporter.exe
mv prometheus_wireguard_exporter.exe ../../../${{ matrix.name }}
cd -
- name: Post Build | Prepare artifacts [-nix]
if: matrix.os != 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
strip prometheus_wireguard_exporter || true
mv prometheus_wireguard_exporter ../../../${{ matrix.name }}
cd -
- name: Display structure of downloaded files
run: ls -R
- name: Deploy | Upload artifacts
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.name }}
path: ${{ matrix.name }}
# Create GitHub release with Rust build targets and release notes
github_release:
name: Create GitHub Release
needs: github_build
runs-on: ubuntu-latest
steps:
- name: Setup | Checkout
uses: actions/checkout@v2.3.4
with:
fetch-depth: 0
- name: Setup | Go
uses: actions/setup-go@v2
with:
go-version: "^1.15.7"
- name: Setup | Download Artifacts
uses: actions/download-artifact@v2
- name: Display structure of downloaded files
run: ls -R
- name: Setup | Create Checksum files
run: |
for DIR in prometheus_wireguard_exporter-*
do
pushd "$DIR" || continue
FILE="$(echo prometheus_wireguard_exporter-*)"
sha256sum "$FILE" > "$FILE.sha256"
popd || exit
done
# - name: Setup | Release notes
# run: |
# GO111MODULE=on go get github.com/git-chglog/git-chglog/cmd/git-chglog@0.14.2
# git-chglog -c .github/chglog/release.yml $(git describe --tags) > RELEASE.md
- name: Build | Publish binaries
uses: alexellis/upload-assets@0.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["prometheus_wireguard_exporter-*/prometheus_wireguard_exporter-*"]'
# Publish prometheus_wireguard_exporter to Crates.io
# cargo_publish:
# name: Publish Cargo Package
# runs-on: ubuntu-latest
# needs: github_release
# steps:
# - name: Setup | Checkout
# uses: actions/checkout@v2.3.4
# - name: Setup | Rust
# uses: actions-rs/toolchain@v1.0.7
# with:
# toolchain: stable
# profile: minimal
# override: true
# - name: Build | Publish
# run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}

572
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package] [package]
name = "prometheus_wireguard_exporter" name = "prometheus_wireguard_exporter"
version = "3.6.6" version = "3.6.2"
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"
@ -19,18 +19,18 @@ default = []
leaky_log = [] leaky_log = []
[dependencies] [dependencies]
log = "0.4.17" log = "0.4.14"
env_logger = "0.9.3" env_logger = "0.9.0"
clap = { version = "4.0.26", features = ["cargo", "env"] } clap = { version = "3.1.0", features = ["cargo", "env"] }
serde_json = "1.0.88" serde_json = "1.0"
serde = "1.0.147" serde = "1.0"
thiserror = "1.0.37" thiserror = "1.0"
anyhow = "1.0.66" anyhow = "1.0"
hyper = { version = "0.14.23", features = ["stream"] } hyper = { version = "0.14", features = ["stream"] }
http = "0.2.8" http = "0.2"
tokio = { version = "1.22.0", features = ["macros", "rt"] } tokio = { version = "1.0", features = ["macros", "rt"] }
prometheus_exporter_base = { version = "1.3.0", features = ["hyper_server"] } prometheus_exporter_base = { version = "1.3", features = ["hyper_server"] }
regex = "1.7.0" regex = "1.5.4"
[dev-dependencies] [dev-dependencies]
clippy = "0.0.302" clippy = "0.0"

View file

@ -1,7 +1,7 @@
ARG BUILDPLATFORM=linux/amd64 ARG BUILDPLATFORM=linux/amd64
ARG ALPINE_VERSION=3.14 ARG ALPINE_VERSION=3.14
ARG RUST_VERSION=1.69-bullseye ARG RUST_VERSION=1-slim-bullseye
FROM --platform=${BUILDPLATFORM} rust:${RUST_VERSION} AS base FROM --platform=${BUILDPLATFORM} rust:${RUST_VERSION} AS base
WORKDIR /usr/src/prometheus_wireguard_exporter WORKDIR /usr/src/prometheus_wireguard_exporter
@ -129,7 +129,6 @@ RUN adduser prometheus-wireguard-exporter -s /bin/sh -D -u 1000 1000 && \
chmod 0440 /etc/sudoers.d/prometheus-wireguard-exporter chmod 0440 /etc/sudoers.d/prometheus-wireguard-exporter
RUN apk add --update -q --no-cache wireguard-tools-wg sudo RUN apk add --update -q --no-cache wireguard-tools-wg sudo
USER prometheus-wireguard-exporter USER prometheus-wireguard-exporter
#USER root
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/prometheus_wireguard_exporter"] ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/prometheus_wireguard_exporter"]
CMD [ "-a" ] CMD [ "-a" ]
COPY --from=build --chown=prometheus-wireguard-exporter /tmp/binary ./prometheus_wireguard_exporter COPY --from=build --chown=prometheus-wireguard-exporter /tmp/binary ./prometheus_wireguard_exporter

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.6.6) [![release](https://img.shields.io/github/release/MindFlavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.6.2)
[![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.6.6) [![tag](https://img.shields.io/github/tag/mindflavor/prometheus_wireguard_exporter.svg)](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.6.2)
[![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.6.6)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.6.6) [![commitssince](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.6.2)](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.6.2)
[![Docker build](https://github.com/MindFlavor/prometheus_wireguard_exporter/actions/workflows/docker.yml/badge.svg)](https://github.com/qdm12/godevcontainer/actions/workflows/docker.yml) [![Docker build](https://github.com/MindFlavor/prometheus_wireguard_exporter/actions/workflows/docker.yml/badge.svg)](https://github.com/qdm12/godevcontainer/actions/workflows/docker.yml)
@ -22,8 +22,6 @@ A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rus
## Changelog ## Changelog
* From release [3.6.4](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.6.4) the exporter optionally calculates the delta, in seconds, since the last handshake. The metric is `wireguard_latest_handshake_delay_seconds`. Thanks to [mmahacek](https://github.com/mmahacek) for the [idea](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/100).
* From release [3.6.3](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.6.3) the exporter automatically parses the systemd-networkd's peer syntax too (`[WireGuardPeer]` rather than `[Peer]`). Thanks to [mbonino](https://github.com/mbonino) for the PR (see https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/92).
* From release [3.6.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.6.1) the exporter correctly escapes the double quotes in `friendly_name`. Thanks to [Steven Wood](https://github.com/stvnw) for finding the bug in #82. * From release [3.6.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.6.1) the exporter correctly escapes the double quotes in `friendly_name`. Thanks to [Steven Wood](https://github.com/stvnw) for finding the bug in #82.
* **BREAKING** From version `3.6.0` the exporter takes fallback configuration values from the environment variables. Thanks to [j_r0dd](https://github.com/jr0dd) for the idea. This changes how the exporter evaluates the command line parameters: make sure to consult the documentation on how to convert your command line to the new format. Basically every switch (for example verbose `-v`) not expect values, either `true` or `false`. This is necessary because there is no way to discriminate between an empty environment variable and one that has not been set. * **BREAKING** From version `3.6.0` the exporter takes fallback configuration values from the environment variables. Thanks to [j_r0dd](https://github.com/jr0dd) for the idea. This changes how the exporter evaluates the command line parameters: make sure to consult the documentation on how to convert your command line to the new format. Basically every switch (for example verbose `-v`) not expect values, either `true` or `false`. This is necessary because there is no way to discriminate between an empty environment variable and one that has not been set.
* From release [3.5.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.5.1) the exporter supports multiple peer files. Thanks to [Tobias Krischer](https://github.com/tobikris) for the idea. * From release [3.5.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.5.1) the exporter supports multiple peer files. Thanks to [Tobias Krischer](https://github.com/tobikris) for the idea.
@ -106,15 +104,7 @@ docker build -t mindflavor/prometheus_wireguard_exporter https://github.com/Mind
### Flags available ### Flags available
Start the binary with `-h` to get the complete syntax. The parameters are below. Start the binary with `-h` to get the complete syntax. The parameters are:
❗**Important** ❗: since 3.6.0, every parameter requires a value. In other words, even the `-v` (verbose) parameter requires `true` or `false` after it. Passing a parameter without value (for example `-v`) is the same of not passing the parameter at all: the default value will be used instead (in the case of the verbose option, it means `false`).
For example, if you want to enable the verbose mode and enable the *prepend sudo* option you would use the following command line:
```bash
prometheus_wireguard_exporter -a true -v true <...>
```
| Parameter | Env | Mandatory | Valid values | Default | Accepts multiple occurrences? | Description | | Parameter | Env | Mandatory | Valid values | Default | Accepts multiple occurrences? | Description |
| -- | -- | -- | -- | -- | -- | -- | | -- | -- | -- | -- | -- | -- | -- |
@ -126,7 +116,6 @@ prometheus_wireguard_exporter -a true -v true <...>
| `-s` | `PROMETHEUS_WIREGUARD_EXPORTER_SEPARATE_ALLOWED_IPS_ENABLED` | No | `true` or `false` | `false` | No | Enable the allowed ip + subnet split mode for the labels. | `-s` | `PROMETHEUS_WIREGUARD_EXPORTER_SEPARATE_ALLOWED_IPS_ENABLED` | No | `true` or `false` | `false` | No | Enable the allowed ip + subnet split mode for the labels.
| `-r` | `PROMETHEUS_WIREGUARD_EXPORTER_EXPORT_REMOTE_IP_AND_PORT_ENABLED` | No | `true` or `false` | `false` | No | Exports peer's remote ip and port as labels (if available). | `-r` | `PROMETHEUS_WIREGUARD_EXPORTER_EXPORT_REMOTE_IP_AND_PORT_ENABLED` | No | `true` or `false` | `false` | No | Exports peer's remote ip and port as labels (if available).
| `-i` | `PROMETHEUS_WIREGUARD_EXPORTER_INTERFACES` | No | Your interface name(s) | `all` | Yes | Specifies the interface(s) passed to the `wg show <interface> dump` parameter. Multiple parameters are allowed. | `-i` | `PROMETHEUS_WIREGUARD_EXPORTER_INTERFACES` | No | Your interface name(s) | `all` | Yes | Specifies the interface(s) passed to the `wg show <interface> dump` parameter. Multiple parameters are allowed.
| `-d` | `EXPORT_LATEST_HANDSHAKE_DELAY` | No | `true` or `false` | `false` | No | Adds the `wireguard_latest_handshake_delay_seconds` metric that automatically calculates the seconds passed since the last handshake.
Keep in mind that command line values take precedence over environment variables. Keep in mind that command line values take precedence over environment variables.
@ -264,7 +253,7 @@ wireguard_latest_handshake_seconds{interface="wg0",public_key="wTjv6hS6fKfNK+SzO
### Systemd service file ### Systemd service file
Now add the exporter to the Prometheus exporters as usual. I recommend to start it as a service. It's necessary to run it as root or configure a sudo rule (if there is a non-root way to call `wg show all dump` please let me know). My systemd service file is like this one: Now add the exporter to the Prometheus exporters as usual. I recommend to start it as a service. It's necessary to run it as root (if there is a non-root way to call `wg show all dump` please let me know). My systemd service file is like this one:
```ini ```ini
[Unit] [Unit]
@ -282,46 +271,6 @@ ExecStart=/usr/local/bin/prometheus_wireguard_exporter -n /etc/wireguard/peers.c
WantedBy=multi-user.target WantedBy=multi-user.target
``` ```
Running it as normal user + hardening:
```ini
[Unit]
Description=Prometheus WireGuard Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=wireguard_exporter
Group=wireguard_exporter
Type=simple
Restart=on-failure
EnvironmentFile=-/etc/conf.d/prometheus-wireguard-exporter
ExecStart=/usr/local/bin/prometheus-wireguard-exporter $WIREGUARD_EXPORTER_ARGS
PrivateTmp=yes
ProtectHome=yes
ProtectControlGroups=yes
UMask=077
RemoveIPC=yes
BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ProtectSystem=strict
ProtectProc=noaccess
[Install]
WantedBy=multi-user.target
```
Most of the other systemd hardening options won't work because they block sudo. With the above unit, you can use the following sudo rule:
```
wireguard_exporter ALL=(root) NOPASSWD: /usr/bin/wg
```
If you're interested in more hardening, you can analyze the unit with:
```
systemd-analyze security prometheus-wireguard-exporter.service
```
## Development ## Development
### Locally ### Locally

View file

@ -1,8 +1,8 @@
use anyhow::Context; use anyhow::Context;
use clap::{crate_authors, crate_name, crate_version, value_parser, Arg}; //extern crate serde_json;
use clap::{crate_authors, crate_name, crate_version, Arg};
use hyper::{Body, Request}; use hyper::{Body, Request};
use log::{debug, info, trace}; use log::{debug, info, trace};
use prometheus_exporter_base::prelude::{Authorization, ServerOptions};
use std::env; use std::env;
mod options; mod options;
use options::Options; use options::Options;
@ -105,7 +105,11 @@ async fn perform_request(
} }
if let Some(wg_accumulator) = wg_accumulator { if let Some(wg_accumulator) = wg_accumulator {
Ok(wg_accumulator.render_with_names(peer_entry_hashmap.as_ref(), &options)) Ok(wg_accumulator.render_with_names(
peer_entry_hashmap.as_ref(),
options.separate_allowed_ips,
options.export_remote_ip_and_port,
))
} else { } else {
panic!(); panic!();
} }
@ -121,81 +125,74 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.short('l') .short('l')
.long("address") .long("address")
.env("PROMETHEUS_WIREGUARD_EXPORTER_ADDRESS") .env("PROMETHEUS_WIREGUARD_EXPORTER_ADDRESS")
.value_parser(value_parser!(IpAddr))
.help("exporter address") .help("exporter address")
.default_value("0.0.0.0") .default_value("0.0.0.0")
.takes_value(true),
) )
.arg( .arg(
Arg::new("port") Arg::new("port")
.short('p') .short('p')
.long("port") .long("port")
.env("PROMETHEUS_WIREGUARD_EXPORTER_PORT") .env("PROMETHEUS_WIREGUARD_EXPORTER_PORT")
.value_parser(value_parser!(u16))
.help("exporter port") .help("exporter port")
.default_value("9586") .default_value("9586")
.takes_value(true),
) )
.arg( .arg(
Arg::new("verbose") Arg::new("verbose")
.short('v') .short('v')
.long("verbose") .long("verbose")
.env("PROMETHEUS_WIREGUARD_EXPORTER_VERBOSE_ENABLED") .env("PROMETHEUS_WIREGUARD_EXPORTER_VERBOSE_ENABLED")
.value_parser(value_parser!(bool))
.help("verbose logging") .help("verbose logging")
.default_value("false") .default_value("false")
.takes_value(true),
) )
.arg( .arg(
Arg::new("prepend_sudo") Arg::new("prepend_sudo")
.short('a') .short('a')
.long("prepend_sudo") .long("prepend_sudo")
.env("PROMETHEUS_WIREGUARD_EXPORTER_PREPEND_SUDO_ENABLED") .env("PROMETHEUS_WIREGUARD_EXPORTER_PREPEND_SUDO_ENABLED")
.value_parser(value_parser!(bool))
.help("Prepend sudo to the wg show commands") .help("Prepend sudo to the wg show commands")
.default_value("false") .default_value("false")
.takes_value(true),
) )
.arg( .arg(
Arg::new("separate_allowed_ips") Arg::new("separate_allowed_ips")
.short('s') .short('s')
.long("separate_allowed_ips") .long("separate_allowed_ips")
.env("PROMETHEUS_WIREGUARD_EXPORTER_SEPARATE_ALLOWED_IPS_ENABLED") .env("PROMETHEUS_WIREGUARD_EXPORTER_SEPARATE_ALLOWED_IPS_ENABLED")
.value_parser(value_parser!(bool))
.help("separate allowed ips and ports") .help("separate allowed ips and ports")
.default_value("false") .default_value("false")
.takes_value(true),
) )
.arg( .arg(
Arg::new("export_remote_ip_and_port") Arg::new("export_remote_ip_and_port")
.short('r') .short('r')
.long("export_remote_ip_and_port") .long("export_remote_ip_and_port")
.env("PROMETHEUS_WIREGUARD_EXPORTER_EXPORT_REMOTE_IP_AND_PORT_ENABLED") .env("PROMETHEUS_WIREGUARD_EXPORTER_EXPORT_REMOTE_IP_AND_PORT_ENABLED")
.value_parser(value_parser!(bool))
.help("exports peer's remote ip and port as labels (if available)") .help("exports peer's remote ip and port as labels (if available)")
.default_value("false") .default_value("false")
.takes_value(true),
) )
.arg( .arg(
Arg::new("extract_names_config_files") Arg::new("extract_names_config_files")
.short('n') .short('n')
.long("extract_names_config_files") .long("extract_names_config_files")
.num_args(0..)
.env("PROMETHEUS_WIREGUARD_EXPORTER_CONFIG_FILE_NAMES") .env("PROMETHEUS_WIREGUARD_EXPORTER_CONFIG_FILE_NAMES")
.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). Multiple files are supported.") .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). Multiple files are supported.")
.use_value_delimiter(false)) .multiple_values(true)
.use_value_delimiter(true)
.takes_value(true))
.arg( .arg(
Arg::new("interfaces") Arg::new("interfaces")
.short('i') .short('i')
.long("interfaces") .long("interfaces")
.num_args(0..)
.env("PROMETHEUS_WIREGUARD_EXPORTER_INTERFACES") .env("PROMETHEUS_WIREGUARD_EXPORTER_INTERFACES")
.help("If set specifies the interface passed to the wg show command. It is relative to the same position config_file. In not specified, all will be passed.") .help("If set specifies the interface passed to the wg show command. It is relative to the same position config_file. In not specified, all will be passed.")
.use_value_delimiter(false)) .multiple_values(true)
.arg( .use_value_delimiter(true)
Arg::new("export_latest_handshake_delay") .takes_value(true))
.short('d') .get_matches();
.long("export_latest_handshake_delay")
.env("EXPORT_LATEST_HANDSHAKE_DELAY")
.value_parser(value_parser!(bool))
.help("exports runtime calculated latest handshake delay")
.default_value("false")
)
.get_matches();
let options = Options::from_claps(&matches); let options = Options::from_claps(&matches);
@ -219,18 +216,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
); );
info!("using options: {:?}", options); info!("using options: {:?}", options);
let bind: u16 = *matches.get_one("port").unwrap(); let bind = matches.value_of("port").unwrap();
let ip: IpAddr = *matches.get_one("addr").unwrap(); let bind = bind.parse::<u16>().expect("port must be a valid number");
let addr: std::net::SocketAddr = (ip, bind).into(); let ip = matches.value_of("addr").unwrap().parse::<IpAddr>().unwrap();
let addr = (ip, bind).into();
info!("starting exporter on http://{}/metrics", addr); info!("starting exporter on http://{}/metrics", addr);
let server_options = ServerOptions { render_prometheus(addr, options, |request, options| {
addr,
authorization: Authorization::None,
};
render_prometheus(server_options, options, |request, options| {
Box::pin(perform_request(request, options)) Box::pin(perform_request(request, options))
}) })
.await; .await;

View file

@ -1,5 +1,3 @@
use clap::parser::ValuesRef;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Options { pub(crate) struct Options {
pub verbose: bool, pub verbose: bool,
@ -8,27 +6,49 @@ pub(crate) struct Options {
pub extract_names_config_files: Option<Vec<String>>, pub extract_names_config_files: Option<Vec<String>>,
pub interfaces: Option<Vec<String>>, pub interfaces: Option<Vec<String>>,
pub export_remote_ip_and_port: bool, pub export_remote_ip_and_port: bool,
pub export_latest_handshake_delay: bool,
} }
impl Options { impl Options {
pub fn from_claps(matches: &clap::ArgMatches) -> Options { pub fn from_claps(matches: &clap::ArgMatches) -> Options {
let options = Options { let options = Options {
verbose: *matches.get_one("verbose").unwrap_or(&false), verbose: matches
prepend_sudo: *matches.get_one("prepend_sudo").unwrap_or(&false), .value_of("verbose")
separate_allowed_ips: *matches.get_one("separate_allowed_ips").unwrap_or(&false), .map(|e| {
e.to_lowercase()
.parse()
.expect("cannot parse verbose as a bool")
})
.unwrap_or_default(),
prepend_sudo: matches
.value_of("prepend_sudo")
.map(|e| {
e.to_lowercase()
.parse()
.expect("cannot parse prepend_sudo as a bool")
})
.unwrap_or_default(),
separate_allowed_ips: matches
.value_of("separate_allowed_ips")
.map(|e| {
e.to_lowercase()
.parse()
.expect("cannot parse separate_allowed_ips as a bool")
})
.unwrap_or_default(),
extract_names_config_files: matches extract_names_config_files: matches
.get_many("extract_names_config_files") .values_of("extract_names_config_files")
.map(|e: ValuesRef<'_, String>| e.into_iter().map(|a| a.to_owned()).collect()), .map(|e| e.into_iter().map(|e| e.to_owned()).collect()),
interfaces: matches interfaces: matches
.get_many("interfaces") .values_of("interfaces")
.map(|e: ValuesRef<'_, String>| e.into_iter().map(|a| a.to_string()).collect()), .map(|e| e.into_iter().map(|a| a.to_owned()).collect()),
export_remote_ip_and_port: *matches export_remote_ip_and_port: matches
.get_one("export_remote_ip_and_port") .value_of("export_remote_ip_and_port")
.unwrap_or(&false), .map(|e| {
export_latest_handshake_delay: *matches e.to_lowercase()
.get_one("export_latest_handshake_delay") .parse()
.unwrap_or(&false), .expect("cannot parse export_remote_ip_and_port as a bool")
})
.unwrap_or_default(),
}; };
options options

View file

@ -1,5 +1,4 @@
use crate::exporter_error::ExporterError; use crate::exporter_error::ExporterError;
use crate::options::Options;
use crate::wireguard_config::PeerEntryHashMap; use crate::wireguard_config::PeerEntryHashMap;
use crate::FriendlyDescription; use crate::FriendlyDescription;
use log::{debug, trace}; use log::{debug, trace};
@ -9,7 +8,6 @@ use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::Debug; use std::fmt::Debug;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const EMPTY: &str = "(none)"; const EMPTY: &str = "(none)";
@ -36,7 +34,6 @@ impl From<&str> for SecureString {
} }
} }
#[allow(dead_code)]
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub(crate) struct LocalEndpoint { pub(crate) struct LocalEndpoint {
pub public_key: String, pub public_key: String,
@ -54,7 +51,6 @@ pub(crate) struct RemoteEndpoint {
pub latest_handshake: u64, pub latest_handshake: u64,
pub sent_bytes: u128, pub sent_bytes: u128,
pub received_bytes: u128, pub received_bytes: u128,
#[allow(dead_code)]
pub persistent_keepalive: bool, pub persistent_keepalive: bool,
} }
@ -169,12 +165,10 @@ impl WireGuard {
pub(crate) fn render_with_names( pub(crate) fn render_with_names(
&self, &self,
pehm: Option<&PeerEntryHashMap>, pehm: Option<&PeerEntryHashMap>,
options: &Options, split_allowed_ips: bool,
export_remote_ip_and_port: bool,
) -> String { ) -> String {
debug!( debug!("WireGuard::render_with_names(self == {:?}, pehm == {:?}, split_allowed_ips == {:?}, export_remote_ip_and_port == {:?} called", self, pehm, split_allowed_ips,export_remote_ip_and_port);
"WireGuard::render_with_names(self == {:?}, pehm == {:?}, options == {:?} called",
self, pehm, options
);
// these are the exported counters // these are the exported counters
let mut pc_sent_bytes_total = PrometheusMetric::build() let mut pc_sent_bytes_total = PrometheusMetric::build()
@ -190,19 +184,8 @@ impl WireGuard {
let mut pc_latest_handshake = PrometheusMetric::build() let mut pc_latest_handshake = PrometheusMetric::build()
.with_name("wireguard_latest_handshake_seconds") .with_name("wireguard_latest_handshake_seconds")
.with_metric_type(MetricType::Gauge) .with_metric_type(MetricType::Gauge)
.with_help("UNIX timestamp seconds of the last handshake") .with_help("Seconds from the last handshake")
.build(); .build();
let mut pc_latest_handshake_delay = if options.export_latest_handshake_delay {
Some(
PrometheusMetric::build()
.with_name("wireguard_latest_handshake_delay_seconds")
.with_metric_type(MetricType::Gauge)
.with_help("Seconds from the last handshake")
.build(),
)
} else {
None
};
// Here we make sure we process the interfaces in the // Here we make sure we process the interfaces in the
// lexicographical order. // lexicographical order.
@ -231,7 +214,7 @@ impl WireGuard {
let mut attributes: Vec<(&str, &str)> = let mut attributes: Vec<(&str, &str)> =
vec![("interface", interface), ("public_key", &ep.public_key)]; vec![("interface", interface), ("public_key", &ep.public_key)];
if options.separate_allowed_ips { if split_allowed_ips {
let v_ip_and_subnet: Vec<(&str, &str)> = ep let v_ip_and_subnet: Vec<(&str, &str)> = ep
.allowed_ips .allowed_ips
.split(',') .split(',')
@ -303,7 +286,7 @@ impl WireGuard {
} }
} }
if options.export_remote_ip_and_port { if export_remote_ip_and_port {
if let Some(r_ip) = &ep.remote_ip { if let Some(r_ip) = &ep.remote_ip {
attributes.push(("remote_ip", r_ip)); attributes.push(("remote_ip", r_ip));
} }
@ -321,18 +304,6 @@ impl WireGuard {
instance = instance.with_label(h, v); instance = instance.with_label(h, v);
} }
pc_latest_handshake_delay
.as_mut()
.map(|pc_latest_handshake_delay| {
let earlier = UNIX_EPOCH + Duration::from_secs(ep.latest_handshake);
let delta = SystemTime::now()
.duration_since(earlier)
.expect("time went backwards");
pc_latest_handshake_delay.render_and_append_instance(
&instance.clone().with_value(delta.as_secs() as u128),
)
});
pc_sent_bytes_total pc_sent_bytes_total
.render_and_append_instance(&instance.clone().with_value(ep.sent_bytes)) .render_and_append_instance(&instance.clone().with_value(ep.sent_bytes))
.render(); .render();
@ -349,15 +320,10 @@ impl WireGuard {
} }
format!( format!(
"{}\n{}\n{}{}", "{}\n{}\n{}",
pc_sent_bytes_total.render(), pc_sent_bytes_total.render(),
pc_received_bytes_total.render(), pc_received_bytes_total.render(),
pc_latest_handshake.render(), pc_latest_handshake.render()
pc_latest_handshake_delay.map_or_else(
// this row adds pc_latest_handshake_delay only if configured
|| "".to_owned(),
|pc_latest_handshake_delay| format!("\n{}", pc_latest_handshake_delay.render())
)
) )
} }
} }
@ -431,17 +397,7 @@ wg0\tsUsR6xufQQ8Tf0FuyY9tfEeYdhVMeFelr4ZMUrj+B0E=\t(none)\t10.211.123.128:51820\
let pe = PeerEntryHashMap::new(); let pe = PeerEntryHashMap::new();
let options = Options { let s = a.render_with_names(Some(&pe), true, true);
verbose: true,
prepend_sudo: true,
separate_allowed_ips: true,
extract_names_config_files: None,
interfaces: None,
export_remote_ip_and_port: true,
export_latest_handshake_delay: false,
};
let s = a.render_with_names(Some(&pe), &options);
println!("{}", s); println!("{}", s);
let s_ok = "# HELP wireguard_sent_bytes_total Bytes sent to the peer let s_ok = "# HELP wireguard_sent_bytes_total Bytes sent to the peer
@ -484,7 +440,7 @@ wireguard_received_bytes_total{interface=\"wg0\",public_key=\"yjeBkrZqUThSSHySFz
wireguard_received_bytes_total{interface=\"wg0\",public_key=\"HtOSi37ALMnSkeAFqeWYZqlBnZqAJERhb5o/i3ZPEFI=\",remote_ip=\"10.211.123.127\",allowed_ip_0=\"10.90.0.17\",allowed_subnet_0=\"32\",remote_port=\"51820\"} 62592693520 wireguard_received_bytes_total{interface=\"wg0\",public_key=\"HtOSi37ALMnSkeAFqeWYZqlBnZqAJERhb5o/i3ZPEFI=\",remote_ip=\"10.211.123.127\",allowed_ip_0=\"10.90.0.17\",allowed_subnet_0=\"32\",remote_port=\"51820\"} 62592693520
wireguard_received_bytes_total{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0FuyY9tfEeYdhVMeFelr4ZMUrj+B0E=\",remote_ip=\"10.211.123.128\",allowed_ip_0=\"10.90.0.18\",allowed_subnet_0=\"32\",remote_port=\"51820\"} 75066288152 wireguard_received_bytes_total{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0FuyY9tfEeYdhVMeFelr4ZMUrj+B0E=\",remote_ip=\"10.211.123.128\",allowed_ip_0=\"10.90.0.18\",allowed_subnet_0=\"32\",remote_port=\"51820\"} 75066288152
# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake # HELP wireguard_latest_handshake_seconds Seconds from the last handshake
# TYPE wireguard_latest_handshake_seconds gauge # TYPE wireguard_latest_handshake_seconds gauge
wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"923V/iAdcz8BcqB0Xo6pDJzARGBJCQ6fWe+peixQyB4=\",remote_ip=\"10.211.123.112\",allowed_ip_0=\"10.90.0.10\",allowed_subnet_0=\"32\",allowed_ip_1=\"10.0.1.0\",allowed_subnet_1=\"24\",remote_port=\"51820\"} 0 wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"923V/iAdcz8BcqB0Xo6pDJzARGBJCQ6fWe+peixQyB4=\",remote_ip=\"10.211.123.112\",allowed_ip_0=\"10.90.0.10\",allowed_subnet_0=\"32\",allowed_ip_1=\"10.0.1.0\",allowed_subnet_1=\"24\",remote_port=\"51820\"} 0
wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"9M1fhLa9sIlT39z+SI/0a5H3mNSHYmM+NGA6sirD2nU=\",remote_ip=\"10.211.123.113\",allowed_ip_0=\"10.90.0.3\",allowed_subnet_0=\"32\",allowed_ip_1=\"10.198.171.0\",allowed_subnet_1=\"24\",remote_port=\"51820\"} 0 wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"9M1fhLa9sIlT39z+SI/0a5H3mNSHYmM+NGA6sirD2nU=\",remote_ip=\"10.211.123.113\",allowed_ip_0=\"10.90.0.3\",allowed_subnet_0=\"32\",allowed_ip_1=\"10.198.171.0\",allowed_subnet_1=\"24\",remote_port=\"51820\"} 0
@ -531,24 +487,13 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
#[test] #[test]
fn test_parse_and_serialize() { fn test_parse_and_serialize() {
let a = WireGuard::try_from(TEXT).unwrap(); let a = WireGuard::try_from(TEXT).unwrap();
let s = a.render_with_names(None, false, true);
let options = Options {
verbose: true,
prepend_sudo: true,
separate_allowed_ips: false,
extract_names_config_files: None,
interfaces: None,
export_remote_ip_and_port: true,
export_latest_handshake_delay: true,
};
let s = a.render_with_names(None, &options);
println!("{}", s); println!("{}", s);
} }
#[test] #[test]
fn test_render_to_prometheus_simple() { fn test_render_to_prometheus_simple() {
const REF : &str= "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\n\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\n"; const REF : &str= "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\n\n# HELP wireguard_latest_handshake_seconds Seconds from the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\n";
let re = Endpoint::Remote(RemoteEndpoint { let re = Endpoint::Remote(RemoteEndpoint {
public_key: "test".to_owned(), public_key: "test".to_owned(),
@ -564,20 +509,11 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
interfaces: HashMap::new(), interfaces: HashMap::new(),
}; };
let v = vec![re]; let mut v = Vec::new();
v.push(re);
wg.interfaces.insert("Pippo".to_owned(), v); wg.interfaces.insert("Pippo".to_owned(), v);
let options = Options { let prometheus = wg.render_with_names(None, false, true);
verbose: true,
prepend_sudo: true,
separate_allowed_ips: false,
extract_names_config_files: None,
interfaces: None,
export_remote_ip_and_port: true,
export_latest_handshake_delay: false,
};
let prometheus = wg.render_with_names(None, &options);
assert_eq!(prometheus, REF); assert_eq!(prometheus, REF);
} }
@ -586,13 +522,13 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
fn test_render_to_prometheus_complex() { fn test_render_to_prometheus_complex() {
use crate::wireguard_config::PeerEntry; use crate::wireguard_config::PeerEntry;
const REF :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 50\n"; const REF :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds Seconds from the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",remote_port=\"100\"} 50\n";
const REF_SPLIT :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 50\n"; const REF_SPLIT :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds Seconds from the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",remote_ip=\"remote_ip\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\",remote_port=\"100\"} 50\n";
const REF_SPLIT_NO_REMOTE :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 50\n"; const REF_SPLIT_NO_REMOTE :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds Seconds from the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ip_0=\"10.0.0.2\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",friendly_name=\"this is my friendly name\",allowed_ip_0=\"10.0.0.4\",allowed_subnet_0=\"32\",allowed_ip_1=\"fd86:ea04:::4\",allowed_subnet_1=\"128\",allowed_ip_2=\"192.168.0.0\",allowed_subnet_2=\"16\"} 50\n";
const REF_JSON :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 50\n"; const REF_JSON :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer\n# TYPE wireguard_sent_bytes_total counter\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000\nwireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 14\n\n# HELP wireguard_received_bytes_total Bytes received from the peer\n# TYPE wireguard_received_bytes_total counter\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000\nwireguard_received_bytes_total{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 1000000000\n\n# HELP wireguard_latest_handshake_seconds Seconds from the last handshake\n# TYPE wireguard_latest_handshake_seconds gauge\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"10.0.0.2/32,fd86:ea04:::4/128\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500\nwireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"second_test\",allowed_ips=\"10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16\",remote_ip=\"remote_ip\",auth_date=\"1614869789\",first_name=\"Coordinator\",id=\"482217555\",last_name=\"DrProxy.me\",username=\"DrProxyMeCoordinator\",remote_port=\"100\"} 50\n";
let re1 = Endpoint::Remote(RemoteEndpoint { let re1 = Endpoint::Remote(RemoteEndpoint {
public_key: "test".to_owned(), public_key: "test".to_owned(),
@ -619,7 +555,9 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
interfaces: HashMap::new(), interfaces: HashMap::new(),
}; };
let v = vec![re1, re2]; let mut v = Vec::new();
v.push(re1);
v.push(re2);
wg.interfaces.insert("Pippo".to_owned(), v); wg.interfaces.insert("Pippo".to_owned(), v);
let mut pehm = PeerEntryHashMap::new(); let mut pehm = PeerEntryHashMap::new();
@ -632,27 +570,13 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
}; };
pehm.insert(pe.public_key, pe.clone()); pehm.insert(pe.public_key, pe.clone());
let mut options = Options { let prometheus = wg.render_with_names(Some(&pehm), false, true);
verbose: true,
prepend_sudo: true,
separate_allowed_ips: false,
extract_names_config_files: None,
interfaces: None,
export_remote_ip_and_port: true,
export_latest_handshake_delay: false,
};
let prometheus = wg.render_with_names(Some(&pehm), &options);
assert_eq!(prometheus, REF); assert_eq!(prometheus, REF);
options.separate_allowed_ips = true; let prometheus = wg.render_with_names(Some(&pehm), true, true);
let prometheus = wg.render_with_names(Some(&pehm), &options);
assert_eq!(prometheus, REF_SPLIT); assert_eq!(prometheus, REF_SPLIT);
options.export_remote_ip_and_port = false; let prometheus = wg.render_with_names(Some(&pehm), true, false);
let prometheus = wg.render_with_names(Some(&pehm), &options);
assert_eq!(prometheus, REF_SPLIT_NO_REMOTE); assert_eq!(prometheus, REF_SPLIT_NO_REMOTE);
// second test // second test
@ -680,10 +604,7 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
}; };
pehm.insert(pe.public_key, pe.clone()); pehm.insert(pe.public_key, pe.clone());
options.separate_allowed_ips = false; let prometheus = wg.render_with_names(Some(&pehm), false, true);
options.export_remote_ip_and_port = true;
let prometheus = wg.render_with_names(Some(&pehm), &options);
assert_eq!(prometheus, REF_JSON); assert_eq!(prometheus, REF_JSON);
} }
} }

View file

@ -8,7 +8,6 @@ use std::convert::TryInto;
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub(crate) struct PeerEntry<'a> { pub(crate) struct PeerEntry<'a> {
pub public_key: &'a str, pub public_key: &'a str,
#[allow(dead_code)]
pub allowed_ips: &'a str, pub allowed_ips: &'a str,
pub friendly_description: Option<FriendlyDescription<'a>>, pub friendly_description: Option<FriendlyDescription<'a>>,
} }