Compare commits
29 commits
Author | SHA1 | Date | |
---|---|---|---|
02d4b5ab13 | |||
d5ccea6fc3 | |||
|
2d82a9c06c | ||
|
56290d6801 | ||
|
a21dc2852e | ||
|
9f0eb7f050 | ||
|
8f586ed65b | ||
|
f0c7a8fbfc | ||
|
f8222bc5ab | ||
|
eb7455fa85 | ||
|
86cc251954 | ||
|
9206a4f595 | ||
|
61de41169b | ||
|
d987baf1f1 | ||
|
23298a72c4 | ||
|
72d3f7393e | ||
|
5b709b19f1 | ||
|
6222d71685 | ||
|
6678669dfb | ||
|
d8237c8b7c | ||
|
62fe64e1c0 | ||
|
638b9d1c33 | ||
|
5752476184 | ||
|
d18c045c98 | ||
|
2bc7ea9e06 | ||
|
8f44776745 | ||
|
45472a35b1 | ||
|
9d37840b83 | ||
|
3a74f8b5b0 |
25 changed files with 1324 additions and 665 deletions
25
.cargo/config.toml
Normal file
25
.cargo/config.toml
Normal file
|
@ -0,0 +1,25 @@
|
|||
# This is used in the Docker build, you might need to adjust it for local usage.
|
||||
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
linker = "x86_64-linux-musl-gcc"
|
||||
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
linker = "aarch64-linux-musl-gcc"
|
||||
|
||||
[target.armv7-unknown-linux-musleabi]
|
||||
linker = "armv7m-linux-musleabi-gcc"
|
||||
|
||||
[target.arm-unknown-linux-musleabi]
|
||||
linker = "armv6-linux-musleabi-gcc"
|
||||
|
||||
[target.i686-unknown-linux-musl]
|
||||
linker = "i686-linux-musl-gcc"
|
||||
|
||||
[target.powerpc64le-unknown-linux-musl]
|
||||
linker = "powerpc64le-linux-musl-gcc"
|
||||
|
||||
[target.s390x-unknown-linux-musl]
|
||||
linker = "s390x-linux-musl-gcc"
|
||||
|
||||
[target.riscv64gc-unknown-linux-musl]
|
||||
linker = "riscv64-linux-musl-gcc"
|
5
.devcontainer/.dockerignore
Normal file
5
.devcontainer/.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
.dockerignore
|
||||
devcontainer.json
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
README.md
|
1
.devcontainer/Dockerfile
Normal file
1
.devcontainer/Dockerfile
Normal file
|
@ -0,0 +1 @@
|
|||
FROM qmcgaw/rustdevcontainer
|
70
.devcontainer/README.md
Normal file
70
.devcontainer/README.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Development container
|
||||
|
||||
Development container that can be used with VSCode.
|
||||
|
||||
It works on Linux, Windows and OSX.
|
||||
|
||||
## Requirements
|
||||
|
||||
- [VS code](https://code.visualstudio.com/download) installed
|
||||
- [VS code remote containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) installed
|
||||
- [Docker](https://www.docker.com/products/docker-desktop) installed and running
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/) installed
|
||||
|
||||
## Setup
|
||||
|
||||
1. Create the following files on your host if you don't have them:
|
||||
|
||||
```sh
|
||||
touch ~/.gitconfig ~/.zsh_history
|
||||
```
|
||||
|
||||
Note that the development container will create the empty directories `~/.docker`, `~/.ssh` and `~/.kube` if you don't have them.
|
||||
|
||||
1. **For Docker on OSX or Windows without WSL**: ensure your home directory `~` is accessible by Docker.
|
||||
1. **For Docker on Windows without WSL:** if you want to use SSH keys, bind mount your host `~/.ssh` to `/tmp/.ssh` instead of `~/.ssh` by changing the `volumes` section in the [docker-compose.yml](docker-compose.yml).
|
||||
1. Open the command palette in Visual Studio Code (CTRL+SHIFT+P).
|
||||
1. Select `Remote-Containers: Open Folder in Container...` and choose the project directory.
|
||||
|
||||
## Customization
|
||||
|
||||
### Customize the image
|
||||
|
||||
You can make changes to the [Dockerfile](Dockerfile) and then rebuild the image. For example, your Dockerfile could be:
|
||||
|
||||
```Dockerfile
|
||||
FROM qmcgaw/rustdevcontainer
|
||||
RUN apk add curl
|
||||
```
|
||||
|
||||
To rebuild the image, either:
|
||||
|
||||
- With VSCode through the command palette, select `Remote-Containers: Rebuild and reopen in container`
|
||||
- With a terminal, go to this directory and `docker-compose build`
|
||||
|
||||
### Customize VS code settings
|
||||
|
||||
You can customize **settings** and **extensions** in the [devcontainer.json](devcontainer.json) definition file.
|
||||
|
||||
### Entrypoint script
|
||||
|
||||
You can bind mount a shell script to `/home/vscode/.welcome.sh` to replace the [current welcome script](shell/.welcome.sh).
|
||||
|
||||
### Publish a port
|
||||
|
||||
To access a port from your host to your development container, publish a port in [docker-compose.yml](docker-compose.yml). You can also now do it directly with VSCode without restarting the container.
|
||||
|
||||
### Run other services
|
||||
|
||||
1. Modify [docker-compose.yml](docker-compose.yml) to launch other services at the same time as this development container, such as a test database:
|
||||
|
||||
```yml
|
||||
database:
|
||||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_PASSWORD: password
|
||||
```
|
||||
|
||||
1. In [devcontainer.json](devcontainer.json), change the line `"runServices": ["vscode"],` to `"runServices": ["vscode", "database"],`.
|
||||
1. In the VS code command palette, rebuild the container.
|
40
.devcontainer/devcontainer.json
Normal file
40
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "prometheus_wireguard_exporter_dev",
|
||||
"dockerComposeFile": ["docker-compose.yml"],
|
||||
"service": "vscode",
|
||||
"runServices": ["vscode"],
|
||||
"shutdownAction": "stopCompose",
|
||||
"postCreateCommand": "",
|
||||
"workspaceFolder": "/workspace",
|
||||
// "overrideCommand": "",
|
||||
"extensions": [
|
||||
"matklad.rust-analyzer",
|
||||
"tamasfe.even-better-toml", // for Cargo.toml
|
||||
"eamodio.gitlens", // IDE Git information
|
||||
"davidanson.vscode-markdownlint",
|
||||
"ms-azuretools.vscode-docker", // Docker integration and linting
|
||||
"shardulm94.trailing-spaces", // Show trailing spaces
|
||||
"Gruntfuggly.todo-tree", // Highlights TODO comments
|
||||
"bierner.emojisense", // Emoji sense for markdown
|
||||
"stkb.rewrap", // rewrap comments after n characters on one line
|
||||
"vscode-icons-team.vscode-icons", // Better file extension icons
|
||||
"github.vscode-pull-request-github", // Github interaction
|
||||
"redhat.vscode-yaml", // Kubernetes, Drone syntax highlighting
|
||||
"bajdzis.vscode-database", // Supports connections to mysql or postgres, over SSL, socked
|
||||
"IBM.output-colorizer", // Colorize your output/test logs
|
||||
// "mohsen1.prettify-json", // Prettify JSON data
|
||||
// "zxh404.vscode-proto3", // Supports Proto syntax
|
||||
// "jrebocho.vscode-random", // Generates random values
|
||||
// "alefragnani.Bookmarks", // Manage bookmarks
|
||||
// "quicktype.quicktype", // Paste JSON as code
|
||||
// "spikespaz.vscode-smoothtype", // smooth cursor animation
|
||||
],
|
||||
"settings": {
|
||||
"files.eol": "\n",
|
||||
"remote.extensionKind": {
|
||||
"ms-azuretools.vscode-docker": "workspace"
|
||||
},
|
||||
"editor.codeActionsOnSaveTimeout": 3000,
|
||||
"rust-analyzer.serverPath": "/usr/local/bin/rust-analyzer"
|
||||
}
|
||||
}
|
31
.devcontainer/docker-compose.yml
Normal file
31
.devcontainer/docker-compose.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
version: "3.7"
|
||||
|
||||
services:
|
||||
vscode:
|
||||
build: .
|
||||
image: rustdevcontainer
|
||||
volumes:
|
||||
- ../:/workspace
|
||||
# Docker
|
||||
- ~/.docker:/root/.docker:z
|
||||
# Docker socket to access Docker server
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
# SSH directory for Linux, OSX and WSL
|
||||
- ~/.ssh:/root/.ssh:z
|
||||
# For Windows without WSL, a copy will be made
|
||||
# from /tmp/.ssh to ~/.ssh to fix permissions
|
||||
# - ~/.ssh:/tmp/.ssh:ro
|
||||
# Shell history persistence
|
||||
- ~/.zsh_history:/root/.zsh_history:z
|
||||
# Git config
|
||||
- ~/.gitconfig:/root/.gitconfig:z
|
||||
# Kubernetes
|
||||
- ~/.kube:/root/.kube:z
|
||||
environment:
|
||||
- TZ=
|
||||
# Needed for debugging
|
||||
# cap_add:
|
||||
# - SYS_PTRACE
|
||||
# security_opt:
|
||||
# - seccomp:unconfined
|
||||
entrypoint: zsh -c "while sleep 1000; do :; done"
|
26
.github/workflows/build.yml
vendored
26
.github/workflows/build.yml
vendored
|
@ -1,26 +0,0 @@
|
|||
name: Docker build
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/rust.yml
|
||||
- extra
|
||||
- _config.yml
|
||||
- .gitignore
|
||||
- .rustfmt.toml
|
||||
- .gitignore
|
||||
- example.json
|
||||
- LICENSE
|
||||
- README.md
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build image
|
||||
run: docker build .
|
42
.github/workflows/buildx-branch.yml
vendored
42
.github/workflows/buildx-branch.yml
vendored
|
@ -1,42 +0,0 @@
|
|||
name: Buildx branch
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '*/*'
|
||||
- '!master'
|
||||
paths-ignore:
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/rust.yml
|
||||
- extra
|
||||
- _config.yml
|
||||
- .gitignore
|
||||
- .rustfmt.toml
|
||||
- .gitignore
|
||||
- example.json
|
||||
- LICENSE
|
||||
- README.md
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u mindflavor --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg COMMIT=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=${GITHUB_REF##*/} \
|
||||
-t mindflavor/prometheus-wireguard-exporter:${GITHUB_REF##*/} \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/mindflavor/prometheus-wireguard-exporter/TODO || exit 0
|
39
.github/workflows/buildx-latest.yml
vendored
39
.github/workflows/buildx-latest.yml
vendored
|
@ -1,39 +0,0 @@
|
|||
name: Buildx latest
|
||||
on:
|
||||
release:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/rust.yml
|
||||
- extra
|
||||
- _config.yml
|
||||
- .gitignore
|
||||
- .rustfmt.toml
|
||||
- .gitignore
|
||||
- example.json
|
||||
- LICENSE
|
||||
- README.md
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u mindflavor --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg COMMIT=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=latest \
|
||||
-t mindflavor/prometheus-wireguard-exporter:latest \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/mindflavor/prometheus-wireguard-exporter/TODO || exit 0
|
39
.github/workflows/buildx-release.yml
vendored
39
.github/workflows/buildx-release.yml
vendored
|
@ -1,39 +0,0 @@
|
|||
name: Buildx release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
paths-ignore:
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/rust.yml
|
||||
- extra
|
||||
- _config.yml
|
||||
- .gitignore
|
||||
- .rustfmt.toml
|
||||
- .gitignore
|
||||
- example.json
|
||||
- LICENSE
|
||||
- README.md
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u mindflavor --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg COMMIT=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=${GITHUB_REF##*/} \
|
||||
-t mindflavor/prometheus-wireguard-exporter:${GITHUB_REF##*/} \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/mindflavor/prometheus-wireguard-exporter/TODO || exit 0
|
58
.github/workflows/ci.yaml
vendored
Normal file
58
.github/workflows/ci.yaml
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
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 }}"]'
|
84
.github/workflows/docker.yml
vendored
Normal file
84
.github/workflows/docker.yml
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
name: CI
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- .github/workflows/docker.yml
|
||||
- src/**
|
||||
- .dockerignore
|
||||
- Cargo.lock
|
||||
- Cargo.toml
|
||||
- Dockerfile
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/docker.yml
|
||||
- src/**
|
||||
- .dockerignore
|
||||
- Cargo.lock
|
||||
- Cargo.toml
|
||||
- Dockerfile
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Lint
|
||||
run: docker build --target lint .
|
||||
|
||||
- name: Build test image
|
||||
run: docker build --target test -t test-container .
|
||||
|
||||
- name: Run tests in test container
|
||||
run: |
|
||||
docker run --rm test-container
|
||||
|
||||
# We run this using the caching from the previous steps
|
||||
- name: Build final image
|
||||
run: docker build .
|
||||
|
||||
publish:
|
||||
needs: [verify]
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- uses: docker/setup-qemu-action@v1
|
||||
- uses: docker/setup-buildx-action@v1
|
||||
|
||||
- uses: docker/login-action@v1.9.0
|
||||
with:
|
||||
username: mindflavor
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
BRANCH=${GITHUB_REF#refs/heads/}
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
echo ::set-output name=commit::$(git rev-parse --short HEAD)
|
||||
echo ::set-output name=build_date::$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
if [ "$TAG" != "$GITHUB_REF" ]; then
|
||||
echo ::set-output name=version::$TAG
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
elif [ "$BRANCH" = "master" ]; then
|
||||
echo ::set-output name=version::latest
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
else
|
||||
echo ::set-output name=version::$BRANCH
|
||||
echo ::set-output name=platforms::linux/amd64,linux/386,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
fi
|
||||
|
||||
- name: Build and push final image
|
||||
uses: docker/build-push-action@v2.4.0
|
||||
with:
|
||||
platforms: ${{ steps.vars.outputs.platforms }}
|
||||
build-args: |
|
||||
BUILD_DATE=${{ steps.vars.outputs.build_date }}
|
||||
COMMIT=${{ steps.vars.outputs.commit }}
|
||||
VERSION=${{ steps.vars.outputs.version }}
|
||||
tags: mindflavor/prometheus-wireguard-exporter:${{ steps.vars.outputs.version }}
|
||||
push: true
|
12
.github/workflows/dockerhub-description.yml
vendored
12
.github/workflows/dockerhub-description.yml
vendored
|
@ -10,10 +10,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v2.3.4
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v2.1.0
|
||||
env:
|
||||
DOCKERHUB_USERNAME: mindflavor
|
||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
DOCKERHUB_REPOSITORY: mindflavor/prometheus-wireguard-exporter
|
||||
uses: peter-evans/dockerhub-description@v2.4.3
|
||||
with:
|
||||
username: mindflavor
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
repository: mindflavor/prometheus-wireguard-exporter
|
||||
|
|
19
.github/workflows/rust.yml
vendored
19
.github/workflows/rust.yml
vendored
|
@ -1,19 +0,0 @@
|
|||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
710
Cargo.lock
generated
710
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
33
Cargo.toml
33
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "prometheus_wireguard_exporter"
|
||||
version = "3.5.0"
|
||||
version = "3.6.6"
|
||||
authors = ["Francesco Cogno <francesco.cogno@outlook.com>"]
|
||||
description = "Prometheus WireGuard Exporter"
|
||||
edition = "2018"
|
||||
|
@ -14,16 +14,23 @@ homepage = "https://github.com/MindFlavor/prometheus_wireguard_e
|
|||
keywords = ["prometheus", "exporter", "wireguard"]
|
||||
categories = ["database"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
leaky_log = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.8"
|
||||
env_logger = "0.7.1"
|
||||
clap = "2.33.0"
|
||||
serde_json = "1.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
thiserror = "1.0"
|
||||
hyper = { version = "0.14", features = ["stream"] }
|
||||
http = "0.2"
|
||||
tokio = { version = "1.0", features = ["macros", "rt"] }
|
||||
prometheus_exporter_base = { version = "1.2", features = ["hyper_server"] }
|
||||
regex = "1.3.1"
|
||||
log = "0.4.17"
|
||||
env_logger = "0.9.3"
|
||||
clap = { version = "4.0.26", features = ["cargo", "env"] }
|
||||
serde_json = "1.0.88"
|
||||
serde = "1.0.147"
|
||||
thiserror = "1.0.37"
|
||||
anyhow = "1.0.66"
|
||||
hyper = { version = "0.14.23", features = ["stream"] }
|
||||
http = "0.2.8"
|
||||
tokio = { version = "1.22.0", features = ["macros", "rt"] }
|
||||
prometheus_exporter_base = { version = "1.3.0", features = ["hyper_server"] }
|
||||
regex = "1.7.0"
|
||||
|
||||
[dev-dependencies]
|
||||
clippy = "0.0.302"
|
||||
|
|
133
Dockerfile
133
Dockerfile
|
@ -1,34 +1,135 @@
|
|||
ARG ALPINE_VERSION=3.12
|
||||
ARG RUST_VERSION=1-alpine${ALPINE_VERSION}
|
||||
ARG BUILDPLATFORM=linux/amd64
|
||||
|
||||
FROM rust:${RUST_VERSION} AS build
|
||||
ARG ALPINE_VERSION=3.14
|
||||
ARG RUST_VERSION=1.69-bullseye
|
||||
|
||||
FROM --platform=${BUILDPLATFORM} rust:${RUST_VERSION} AS base
|
||||
WORKDIR /usr/src/prometheus_wireguard_exporter
|
||||
|
||||
# Setup
|
||||
ARG ARCH=x86_64
|
||||
RUN apk add --update -q --no-cache musl-dev
|
||||
RUN rustup target add ${ARCH}-unknown-linux-musl
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
# to cross build with musl
|
||||
musl-tools \
|
||||
# to download the musl cross build tool
|
||||
wget \
|
||||
# for verifying the binary properties
|
||||
file
|
||||
|
||||
# Download dependencies
|
||||
RUN mkdir src && \
|
||||
echo 'fn main() {}' > src/main.rs
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
RUN cargo fetch && \
|
||||
rm src/main.rs
|
||||
|
||||
ARG STATIC=yes
|
||||
RUN touch /tmp/rustflags && \
|
||||
if [ "${STATIC}" != "yes" ]; then \
|
||||
echo "-C target-feature=-crt-static" | tee /tmp/rustflags; \
|
||||
fi
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
RUN echo "Setting variables for ${TARGETPLATFORM:=linux/amd64}" && \
|
||||
case "${TARGETPLATFORM}" in \
|
||||
linux/amd64) \
|
||||
MUSL="x86_64-linux-musl"; \
|
||||
RUSTTARGET="x86_64-unknown-linux-musl"; \
|
||||
break;; \
|
||||
linux/arm64) \
|
||||
MUSL="aarch64-linux-musl"; \
|
||||
RUSTTARGET="aarch64-unknown-linux-musl"; \
|
||||
break;; \
|
||||
linux/arm/v7) \
|
||||
MUSL="armv7m-linux-musleabi"; \
|
||||
RUSTTARGET="armv7-unknown-linux-musleabi"; \
|
||||
break;; \
|
||||
linux/arm/v6) \
|
||||
MUSL="armv6-linux-musleabi"; \
|
||||
RUSTTARGET="arm-unknown-linux-musleabi"; \
|
||||
break;; \
|
||||
linux/386) \
|
||||
MUSL="i686-linux-musl"; \
|
||||
RUSTTARGET="i686-unknown-linux-musl"; \
|
||||
break;; \
|
||||
linux/ppc64le) \
|
||||
MUSL="powerpc64le-linux-musl"; \
|
||||
RUSTTARGET="powerpc64le-unknown-linux-musl"; \
|
||||
break;; \
|
||||
linux/s390x) \
|
||||
MUSL="s390x-linux-musl"; \
|
||||
RUSTTARGET="s390x-unknown-linux-musl"; \
|
||||
break;; \
|
||||
linux/riscv64) \
|
||||
MUSL="riscv64-linux-musl"; \
|
||||
RUSTTARGET="riscv64gc-unknown-linux-musl"; \
|
||||
break;; \
|
||||
*) echo "unsupported platform ${TARGETPLATFORM}"; exit 1;; \
|
||||
esac && \
|
||||
echo "${MUSL}" | tee /tmp/musl && \
|
||||
echo "${RUSTTARGET}" | tee /tmp/rusttarget
|
||||
|
||||
RUN MUSL="$(cat /tmp/musl)" && \
|
||||
wget -qO- "https://musl.cc/$MUSL-cross.tgz" | tar -xzC /tmp && \
|
||||
rm "/tmp/$MUSL-cross/usr" && \
|
||||
cp -fr /tmp/"$MUSL"-cross/* / && \
|
||||
rm -rf "/tmp/$MUSL-cross"
|
||||
|
||||
RUN rustup target add "$(cat /tmp/rusttarget)"
|
||||
|
||||
# Copy .cargo/config for cross build configuration
|
||||
COPY .cargo ./.cargo
|
||||
|
||||
# Install Clippy for build platform
|
||||
RUN rustup component add clippy
|
||||
|
||||
# Install dependencies
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
RUN mkdir src && \
|
||||
echo "fn main() {}" > src/main.rs
|
||||
RUN cargo build --release && \
|
||||
rm -rf target/release/deps/prometheus_wireguard_exporter*
|
||||
RUN echo 'fn main() {}' > src/main.rs && \
|
||||
RUSTFLAGS="$(cat /tmp/rustflags)" \
|
||||
CC="$(cat /tmp/musl)-gcc" \
|
||||
cargo build --target "$(cat /tmp/rusttarget)" --release
|
||||
RUN rm -r \
|
||||
target/*-linux-*/release/deps/prometheus_wireguard_exporter* \
|
||||
target/*-linux-*/release/prometheus_wireguard_exporter* \
|
||||
src/main.rs
|
||||
|
||||
# Build the musl linked binary
|
||||
COPY . .
|
||||
RUN cargo build --release
|
||||
RUN cargo install --target ${ARCH}-unknown-linux-musl --path .
|
||||
|
||||
FROM base AS lint
|
||||
RUN RUSTFLAGS="$(cat /tmp/rustflags)" \
|
||||
CC="$(cat /tmp/musl)-gcc" \
|
||||
cargo clippy --target "$(cat /tmp/rusttarget)"
|
||||
|
||||
FROM base AS test
|
||||
ENTRYPOINT \
|
||||
RUSTFLAGS="$(cat /tmp/rustflags)" \
|
||||
CC="$(cat /tmp/musl)-gcc" \
|
||||
cargo test --target "$(cat /tmp/rusttarget)"
|
||||
|
||||
FROM base AS build
|
||||
# Build static binary with musl built-in
|
||||
RUN RUSTFLAGS="$(cat /tmp/rustflags)" \
|
||||
CC="$(cat /tmp/musl)-gcc" \
|
||||
cargo build --target "$(cat /tmp/rusttarget)" --release && \
|
||||
mv target/*-linux-*/release/prometheus_wireguard_exporter /tmp/binary
|
||||
RUN description="$(file /tmp/binary)" && \
|
||||
echo "$description" && \
|
||||
if [ "${STATIC}" = "yes" ] && [ ! -z "$(echo $description | grep musl)" ]; then \
|
||||
echo "binary is not statically built!" && exit 1; \
|
||||
fi
|
||||
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
EXPOSE 9586/tcp
|
||||
WORKDIR /usr/local/bin
|
||||
RUN apk add --no-cache --q tini && \
|
||||
rm -rf /var/cache/apk/*
|
||||
RUN adduser prometheus-wireguard-exporter -s /bin/sh -D -u 1000 1000 && \
|
||||
mkdir -p /etc/sudoers.d && \
|
||||
echo 'prometheus-wireguard-exporter ALL=(root) NOPASSWD:/usr/bin/wg show * dump' > /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
|
||||
USER prometheus-wireguard-exporter
|
||||
ENTRYPOINT [ "prometheus_wireguard_exporter" ]
|
||||
#USER root
|
||||
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/prometheus_wireguard_exporter"]
|
||||
CMD [ "-a" ]
|
||||
COPY --from=build --chown=prometheus-wireguard-exporter /usr/local/cargo/bin/prometheus_wireguard_exporter /usr/local/bin/prometheus_wireguard_exporter
|
||||
COPY --from=build --chown=prometheus-wireguard-exporter /tmp/binary ./prometheus_wireguard_exporter
|
||||
|
|
217
README.md
217
README.md
|
@ -4,24 +4,29 @@
|
|||
|
||||
[](https://crates.io/crates/prometheus_wireguard_exporter) [](https://crates.io/crates/prometheus_wireguard_exporter) [](https://crates.io/crates/prometheus_wireguard_exporter)
|
||||
|
||||
[](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.5.0)
|
||||
[](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.5.0)
|
||||
[](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.6.6)
|
||||
[](https://github.com/MindFlavor/prometheus_wireguard_exporter/tree/3.6.6)
|
||||
|
||||
[](https://github.com/mindflavor/prometheus_wireguard_exporter/actions?query=workflow%3ARust)
|
||||
[](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.5.0.svg)
|
||||
[](https://img.shields.io/github/commits-since/mindflavor/prometheus_wireguard_exporter/3.6.6)
|
||||
|
||||

|
||||
[](https://github.com/qdm12/godevcontainer/actions/workflows/docker.yml)
|
||||
|
||||
[](https://hub.docker.com/r/mindflavor/prometheus-wireguard-exporter)
|
||||
|
||||
## Intro
|
||||
|
||||
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.
|
||||
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. It's also built for Docker for the following CPU architectures: `amd64`, `386`, `arm64`, `armv7` and `armv6`.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
* **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.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.5.0) the exporter supports the `friendly_json` tag. Entries prepended with the `friendly_json` tag will output all the entries in the specificed json as Prometheus attributes. Thanks to [DrProxyProSupport](https://github.com/iqdoctor) for the idea.
|
||||
* From release [3.4.1](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.4.0) the exporter supports prepending `sudo` to the `wg` command. This allows to run the exporter as a non root user (although sudoer without password). Thanks to [Jonas Seydel](https://github.com/Thor77) for the idea.
|
||||
* **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!
|
||||
|
@ -30,63 +35,108 @@ A Prometheus exporter for [WireGuard](https://www.wireguard.com), written in Rus
|
|||
* 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)).
|
||||
* Starting from release [2.0.2](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/2.0.2) this exporter supports IPv6 addresses too (thanks to [Maximilian Bosch](https://github.com/Ma27)'s PR [#5](https://github.com/MindFlavor/prometheus_wireguard_exporter/pull/5)).
|
||||
|
||||
## Prerequisites
|
||||
## Setup
|
||||
|
||||
* You need [Rust](https://www.rust-lang.org/) to compile this code. Simply follow the instructions on Rust's website to install the toolchain. If you get weird errors while compiling please try and update your Rust version first (I have developed it on `rustc 1.53.0-nightly (f82664191 2021-03-21)`). Alternatively you can build the docker image or use the prebuilt one.
|
||||
* You need [WireGuard](https://www.wireguard.com) *and* the `wg` CLI in the path. The tool will call `wg show <interface(s)>|all dump` and of course will fail if the `wg` executable is not found. If you want I can add the option of specifying the `wg` path in the command line, just open an issue for it.
|
||||
### Pre-built binaries
|
||||
|
||||
Alternatively, as long as you have Wireguard on your host kernel with some Wireguard interfaces running, you can use Docker. For example:
|
||||
Coming soon, subcribe to [#59](https://github.com/MindFlavor/prometheus_wireguard_exporter/issues/59)
|
||||
|
||||
### Docker
|
||||
|
||||
1. You need Docker installed
|
||||
1. You need [WireGuard](https://www.wireguard.com) installed in your host kernel
|
||||
1. You need some Wireguard interfaces running
|
||||
1. Download and run the container with:
|
||||
|
||||
```sh
|
||||
docker run -d --net=host --cap-add=NET_ADMIN --name wgexporter mindflavor/prometheus-wireguard-exporter
|
||||
```
|
||||
|
||||
⚠️ If you encounter time issues on your 32 bit operating system, [check this](https://wiki.alpinelinux.org/wiki/Release_Notes_for_Alpine_3.13.0#time64_requirements)
|
||||
|
||||
1. Check it's up by visiting [http://localhost:9586/metrics](http://localhost:9586/metrics)
|
||||
|
||||
You can then update the image with
|
||||
|
||||
```sh
|
||||
docker run -it --rm --init --net=host --cap-add=NET_ADMIN mindflavor/prometheus-wireguard-exporter
|
||||
# Check it's up
|
||||
docker run -it --rm alpine:3.12 wget -qO- http://localhost:9586/metrics
|
||||
docker pull mindflavor/prometheus_wireguard_exporter
|
||||
```
|
||||
|
||||
## Compilation
|
||||
Or use a [tagged image](https://hub.docker.com/r/mindflavor/prometheus-wireguard-exporter/tags) such as `:3.5.1`.
|
||||
|
||||
To compile the latest master version:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/MindFlavor/prometheus_wireguard_exporter.git
|
||||
cd prometheus_wireguard_exporter
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
If you want the latest release you can simply use:
|
||||
|
||||
```bash
|
||||
cargo install prometheus_wireguard_exporter
|
||||
```
|
||||
|
||||
You can also build the Docker image with
|
||||
If your host has an `amd64` or `686` CPU, you can also build the Docker image from source (you need `git`) with:
|
||||
|
||||
```sh
|
||||
docker build -t mindflavor/prometheus-wireguard-exporter .
|
||||
docker build -t mindflavor/prometheus_wireguard_exporter https://github.com/MindFlavor/prometheus_wireguard_exporter.git#master
|
||||
```
|
||||
|
||||
### Build from source
|
||||
|
||||
1. You need [Rust](https://www.rust-lang.org/tools/install) installed
|
||||
1. You need [WireGuard](https://www.wireguard.com) installed on your host
|
||||
1. You need `wg` accessible in your path. The tool will call `wg show <interface(s)>|all dump` and of course will fail if the `wg` executable is not found.
|
||||
1. You need some Wireguard interfaces running
|
||||
1. You need `git` installed
|
||||
1. Clone the repository with
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MindFlavor/prometheus_wireguard_exporter.git
|
||||
cd prometheus_wireguard_exporter
|
||||
```
|
||||
|
||||
1. Compile the program with
|
||||
|
||||
```sh
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
💁 If you encounter errors, please try updating your rust installation with `rustup update`.
|
||||
The code should compile with any relatively recent, 2018-compliant rustc version.
|
||||
As a frame of reference, the last release was built using the Rust Docker image using `rustc 1.53.0 (53cb7b09b 2021-06-17)`.
|
||||
|
||||
1. Run the program
|
||||
|
||||
```sh
|
||||
./prometheus_wireguard_exporter
|
||||
```
|
||||
|
||||
1. Check it's up by visiting [http://localhost:9586/metrics](http://localhost:9586/metrics)
|
||||
|
||||
## Usage
|
||||
|
||||
Start the binary with `-h` to get the complete syntax. The parameters are:
|
||||
### Flags available
|
||||
|
||||
| Parameter | Mandatory | Valid values | Default | Accepts multiple occurrences? | Description |
|
||||
| -- | -- | -- | -- | -- | -- |
|
||||
| `-v` | no | <switch> | | No | Enable verbose mode.
|
||||
| `-a` | no | <switch> | | No | Prepends sudo to `wg` commands.
|
||||
| `-l` | no | any valid ip address | 0.0.0.0 | No | Specify the service address. This is the address your Prometheus instance should point to.
|
||||
| `-p` | no | any valid port number | 9586 | No | Specify the service port. This is the port your Prometheus instance should point to.
|
||||
| `-n` | no | path to the wireguard configuration file | | No | This flag adds the *friendly_name* attribute or the *friendly_json* attributes to the exported entries. See [Friendly tags](#friendly-tags) for more details.
|
||||
| `-s` | no | <switch> | off | No | Enable the allowed ip + subnet split mode for the labels.
|
||||
| `-r` | no | <switch> | off | No | Exports peer's remote ip and port as labels (if available).
|
||||
| `-i` | no | your interface name(s) | `all` | Yes | Specifies the interface(s) passed to the `wg show <interface> dump` parameter. Multiple parameters are allowed.
|
||||
Start the binary with `-h` to get the complete syntax. The parameters are below.
|
||||
|
||||
❗**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 |
|
||||
| -- | -- | -- | -- | -- | -- | -- |
|
||||
| `-v` | `PROMETHEUS_WIREGUARD_EXPORTER_VERBOSE_ENABLED` | No | `true` or `false` | `false` | No | Enable verbose mode.
|
||||
| `-a` | `PROMETHEUS_WIREGUARD_EXPORTER_PREPEND_SUDO_ENABLED` | No | `true` or `false` | `false` | No | Prepends sudo to `wg` commands.
|
||||
| `-l` | `PROMETHEUS_WIREGUARD_EXPORTER_ADDRESS` | No | Any valid IP address | `0.0.0.0` | No | Specify the service address. This is the address your Prometheus instance should point to.
|
||||
| `-p` | `PROMETHEUS_WIREGUARD_EXPORTER_PORT` | No | Any valid port number | `9586` | No | Specify the service port. This is the port your Prometheus instance should point to.
|
||||
| `-n` | `PROMETHEUS_WIREGUARD_EXPORTER_CONFIG_FILE_NAMES` | No | Path to the wireguard configuration file | | Yes | This flag adds the *friendly_name* attribute or the *friendly_json* attributes to the exported entries. See [Friendly tags](#friendly-tags) for more details. Multiple files are allowed (they will be merged as a single file in memory so avoid duplicates).
|
||||
| `-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).
|
||||
| `-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.
|
||||
|
||||
Once started, the tool will listen on the specified port (or the default one, 9586, if not specified) and return a Prometheus valid response at the url `/metrics`. So to check if the tool is working properly simply browse the `http://localhost:9586/metrics` (or whichever port you choose).
|
||||
|
||||
## Friendly Tags
|
||||
### Friendly Tags
|
||||
|
||||
Starting from version 3.5 you can instruct the exporter to append a *friendly name* or a *friendly_json* to the exported entries. This can make the output more understandable than using the public keys. For example this is the standard output:
|
||||
|
||||
```
|
||||
```ebnf
|
||||
# HELP wireguard_sent_bytes_total Bytes sent to the peer
|
||||
# TYPE wireguard_sent_bytes_total counter
|
||||
wireguard_sent_bytes_total{interface="wg0",public_key="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowed_ips="10.70.0.2/32,10.70.0.66/32"} 3208804
|
||||
|
@ -118,7 +168,7 @@ wireguard_latest_handshake_seconds{interface="wg0",public_key="wTjv6hS6fKfNK+SzO
|
|||
|
||||
And this is the one augmented with friendly names:
|
||||
|
||||
```
|
||||
```ebnf
|
||||
# HELP wireguard_sent_bytes_total Bytes sent to the peer
|
||||
# TYPE wireguard_sent_bytes_total counter
|
||||
wireguard_sent_bytes_total{interface="wg0",public_key="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowed_ips="10.70.0.2/32,10.70.0.66/32",friendly_name="OnePlus 6T"} 3208804
|
||||
|
@ -148,8 +198,8 @@ 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
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
From version [3.5.0](https://github.com/MindFlavor/prometheus_wireguard_exporter/releases/tag/3.5.0) you can optionally specify a `friendly_json` tag followed by a flat json (that is, a json with only top level, simple entries). If a `friendly_json` tag will be found every entry will be used as attribute in the exported Prometheus instance. No compliance check will be done. Also, numbers will be converted to strings (as it's expected for a Prometheus attribute).
|
||||
|
||||
For example this is how you edit your WireGuard configuration file:
|
||||
|
@ -182,7 +232,7 @@ As you can see, all you need to do is to add the friendly name in the comments p
|
|||
|
||||
This is a sample of the label split mode:
|
||||
|
||||
```
|
||||
```ebnf
|
||||
# HELP wireguard_sent_bytes_total Bytes sent to the peer
|
||||
# TYPE wireguard_sent_bytes_total counter
|
||||
wireguard_sent_bytes_total{interface="wg0",public_key="2S7mA0vEMethCNQrJpJKE81/JmhgtB+tHHLYQhgM6kk=",allowed_ip_0="10.70.0.2",allowed_subnet_0="32",allowed_ip_1="10.70.0.66",allowed_subnet_1="32",friendly_name="OnePlus 6T"} 3208804
|
||||
|
@ -214,9 +264,9 @@ wireguard_latest_handshake_seconds{interface="wg0",public_key="wTjv6hS6fKfNK+SzO
|
|||
|
||||
### 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 (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 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:
|
||||
|
||||
```
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Prometheus WireGuard Exporter
|
||||
Wants=network-online.target
|
||||
|
@ -231,3 +281,74 @@ ExecStart=/usr/local/bin/prometheus_wireguard_exporter -n /etc/wireguard/peers.c
|
|||
[Install]
|
||||
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
|
||||
|
||||
### Locally
|
||||
|
||||
1. Install [Rust](https://www.rust-lang.org/tools/install)
|
||||
1. Install [Rust Analyzer](https://rust-analyzer.github.io/manual.html#installation) and set it up with your editor
|
||||
1. Install [Clippy](https://github.com/rust-lang/rust-clippy): `rustup clippy`
|
||||
|
||||
You may want to install Docker as well to build and run the Docker image.
|
||||
|
||||
The following commands are available:
|
||||
|
||||
```sh
|
||||
# Download dependencies
|
||||
cargo fetch
|
||||
# Build the program
|
||||
cargo build
|
||||
# Run tests
|
||||
cargo test
|
||||
# Run clippy to lint
|
||||
cargo clippy
|
||||
# Build the Docker image
|
||||
docker build -t mindflavor/prometheus_wireguard_exporter .
|
||||
```
|
||||
|
||||
### VSCode development container
|
||||
|
||||
This is more of a plug and play solution based on Docker and VSCode.
|
||||
|
||||
See [.devcontainer/README.md](https://github.com/MindFlavor/prometheus_wireguard_exporter/blob/master/.devcontainer/README.md)
|
||||
|
|
1
clippy.toml
Normal file
1
clippy.toml
Normal file
|
@ -0,0 +1 @@
|
|||
# see https://rust-lang.github.io/rust-clippy/master/index.html
|
|
@ -37,7 +37,7 @@ pub enum ExporterError {
|
|||
UTF8 { e: std::string::FromUtf8Error },
|
||||
|
||||
#[error("JSON format error: {}", e)]
|
||||
JSON { e: serde_json::error::Error },
|
||||
Json { e: serde_json::error::Error },
|
||||
|
||||
#[error("IO Error: {}", e)]
|
||||
IO { e: std::io::Error },
|
||||
|
@ -84,7 +84,7 @@ impl From<std::string::FromUtf8Error> for ExporterError {
|
|||
|
||||
impl From<serde_json::error::Error> for ExporterError {
|
||||
fn from(e: serde_json::error::Error) -> Self {
|
||||
ExporterError::JSON { e }
|
||||
ExporterError::Json { e }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ impl<'a> TryFrom<(&'a str, &'a str)> for FriendlyDescription<'a> {
|
|||
|
||||
fn try_from((header_name, value): (&'a str, &'a str)) -> Result<Self, Self::Error> {
|
||||
Ok(match header_name {
|
||||
"friendly_name" => FriendlyDescription::Name(value.into()),
|
||||
"friendly_name" => FriendlyDescription::Name(value.replace('\"', "\\\"").into()),
|
||||
"friendly_json" => {
|
||||
let ret: HashMap<&str, serde_json::Value> = serde_json::from_str(value)?;
|
||||
FriendlyDescription::Json(ret)
|
||||
|
@ -29,3 +29,23 @@ impl<'a> TryFrom<(&'a str, &'a str)> for FriendlyDescription<'a> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[test]
|
||||
fn test_no_escape_friendly_name() {
|
||||
let fd: FriendlyDescription = ("friendly_name", "no escaping").try_into().unwrap();
|
||||
assert_eq!(fd, FriendlyDescription::Name("no escaping".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_friendly_name() {
|
||||
const TO_ESCAPE: &str = r#"man this is a quote ""#;
|
||||
const ESCAPED: &str = r#"man this is a quote \""#;
|
||||
let fd: FriendlyDescription = ("friendly_name", TO_ESCAPE).try_into().unwrap();
|
||||
assert_eq!(fd, FriendlyDescription::Name(ESCAPED.into()));
|
||||
}
|
||||
}
|
||||
|
|
146
src/main.rs
146
src/main.rs
|
@ -1,7 +1,8 @@
|
|||
//extern crate serde_json;
|
||||
use clap::{crate_authors, crate_name, crate_version, Arg};
|
||||
use anyhow::Context;
|
||||
use clap::{crate_authors, crate_name, crate_version, value_parser, Arg};
|
||||
use hyper::{Body, Request};
|
||||
use log::{debug, info, trace};
|
||||
use prometheus_exporter_base::prelude::{Authorization, ServerOptions};
|
||||
use std::env;
|
||||
mod options;
|
||||
use options::Options;
|
||||
|
@ -26,21 +27,27 @@ async fn perform_request(
|
|||
Some(interfaces_str) => interfaces_str.clone(),
|
||||
None => vec!["all".to_owned()],
|
||||
};
|
||||
log::trace!("interfaces_to_handle == {:?}", interfaces_to_handle);
|
||||
|
||||
let peer_entry_contents =
|
||||
if let Some(extract_names_config_file) = &options.extract_names_config_file {
|
||||
Some(::std::fs::read_to_string(
|
||||
&extract_names_config_file as &str,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let peer_entry_contents = options
|
||||
.extract_names_config_files
|
||||
.as_ref()
|
||||
.map(|files| {
|
||||
files // if we have values
|
||||
.iter() // for each value
|
||||
.map(|file| std::fs::read_to_string(file as &str)) // read the contents into a String
|
||||
.collect::<Result<Vec<String>, std::io::Error>>() // And transform it into a vec (stopping in case of errors)
|
||||
})
|
||||
.transpose()
|
||||
.with_context(|| "failed to read peer config file")? // bail out if there was an error
|
||||
.map(|strings| strings.join("\n")); // now join the strings in a new string
|
||||
|
||||
let peer_entry_hashmap = if let Some(peer_entry_contents) = &peer_entry_contents {
|
||||
Some(peer_entry_hashmap_try_from(peer_entry_contents)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let peer_entry_hashmap = peer_entry_contents
|
||||
.as_ref()
|
||||
.map(|contents| peer_entry_hashmap_try_from(contents))
|
||||
.transpose()?;
|
||||
|
||||
trace!("peer_entry_hashmap == {:#?}", peer_entry_hashmap);
|
||||
|
||||
let mut wg_accumulator: Option<WireGuard> = None;
|
||||
|
||||
|
@ -98,11 +105,7 @@ async fn perform_request(
|
|||
}
|
||||
|
||||
if let Some(wg_accumulator) = wg_accumulator {
|
||||
Ok(wg_accumulator.render_with_names(
|
||||
peer_entry_hashmap.as_ref(),
|
||||
options.separate_allowed_ips,
|
||||
options.export_remote_ip_and_port,
|
||||
))
|
||||
Ok(wg_accumulator.render_with_names(peer_entry_hashmap.as_ref(), &options))
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
|
@ -110,62 +113,89 @@ async fn perform_request(
|
|||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let matches = clap::App::new(crate_name!())
|
||||
let matches = clap::Command::new(crate_name!())
|
||||
.version(crate_version!())
|
||||
.author(crate_authors!("\n"))
|
||||
.arg(
|
||||
Arg::with_name("addr")
|
||||
.short("l")
|
||||
Arg::new("addr")
|
||||
.short('l')
|
||||
.long("address")
|
||||
.env("PROMETHEUS_WIREGUARD_EXPORTER_ADDRESS")
|
||||
.value_parser(value_parser!(IpAddr))
|
||||
.help("exporter address")
|
||||
.default_value("0.0.0.0")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.short("p")
|
||||
Arg::new("port")
|
||||
.short('p')
|
||||
.long("port")
|
||||
.env("PROMETHEUS_WIREGUARD_EXPORTER_PORT")
|
||||
.value_parser(value_parser!(u16))
|
||||
.help("exporter port")
|
||||
.default_value("9586")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("verbose")
|
||||
.short("v")
|
||||
Arg::new("verbose")
|
||||
.short('v')
|
||||
.long("verbose")
|
||||
.env("PROMETHEUS_WIREGUARD_EXPORTER_VERBOSE_ENABLED")
|
||||
.value_parser(value_parser!(bool))
|
||||
.help("verbose logging")
|
||||
.takes_value(false),
|
||||
.default_value("false")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("prepend_sudo")
|
||||
.short("a")
|
||||
Arg::new("prepend_sudo")
|
||||
.short('a')
|
||||
.long("prepend_sudo")
|
||||
.env("PROMETHEUS_WIREGUARD_EXPORTER_PREPEND_SUDO_ENABLED")
|
||||
.value_parser(value_parser!(bool))
|
||||
.help("Prepend sudo to the wg show commands")
|
||||
.takes_value(false),
|
||||
.default_value("false")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("separate_allowed_ips")
|
||||
.short("s")
|
||||
Arg::new("separate_allowed_ips")
|
||||
.short('s')
|
||||
.long("separate_allowed_ips")
|
||||
.env("PROMETHEUS_WIREGUARD_EXPORTER_SEPARATE_ALLOWED_IPS_ENABLED")
|
||||
.value_parser(value_parser!(bool))
|
||||
.help("separate allowed ips and ports")
|
||||
.takes_value(false),
|
||||
.default_value("false")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("export_remote_ip_and_port")
|
||||
.short("r")
|
||||
Arg::new("export_remote_ip_and_port")
|
||||
.short('r')
|
||||
.long("export_remote_ip_and_port")
|
||||
.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)")
|
||||
.takes_value(false),
|
||||
.default_value("false")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("extract_names_config_files")
|
||||
.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)")
|
||||
.multiple(false)
|
||||
.number_of_values(1)
|
||||
.takes_value(true))
|
||||
Arg::new("extract_names_config_files")
|
||||
.short('n')
|
||||
.long("extract_names_config_files")
|
||||
.num_args(0..)
|
||||
.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.")
|
||||
.use_value_delimiter(false))
|
||||
.arg(
|
||||
Arg::with_name("interfaces")
|
||||
.short("i")
|
||||
Arg::new("interfaces")
|
||||
.short('i')
|
||||
.long("interfaces")
|
||||
.num_args(0..)
|
||||
.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.")
|
||||
.multiple(true)
|
||||
.number_of_values(1)
|
||||
.takes_value(true))
|
||||
.get_matches();
|
||||
.use_value_delimiter(false))
|
||||
.arg(
|
||||
Arg::new("export_latest_handshake_delay")
|
||||
.short('d')
|
||||
.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);
|
||||
|
||||
|
@ -189,14 +219,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
);
|
||||
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::<IpAddr>().unwrap();
|
||||
let addr = (ip, bind).into();
|
||||
let bind: u16 = *matches.get_one("port").unwrap();
|
||||
let ip: IpAddr = *matches.get_one("addr").unwrap();
|
||||
let addr: std::net::SocketAddr = (ip, bind).into();
|
||||
|
||||
info!("starting exporter on http://{}/metrics", addr);
|
||||
|
||||
render_prometheus(addr, options, |request, options| {
|
||||
let server_options = ServerOptions {
|
||||
addr,
|
||||
authorization: Authorization::None,
|
||||
};
|
||||
|
||||
render_prometheus(server_options, options, |request, options| {
|
||||
Box::pin(perform_request(request, options))
|
||||
})
|
||||
.await;
|
||||
|
|
|
@ -1,31 +1,34 @@
|
|||
use clap::parser::ValuesRef;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Options {
|
||||
pub verbose: bool,
|
||||
pub prepend_sudo: bool,
|
||||
pub separate_allowed_ips: bool,
|
||||
pub extract_names_config_file: Option<String>,
|
||||
pub extract_names_config_files: Option<Vec<String>>,
|
||||
pub interfaces: Option<Vec<String>>,
|
||||
pub export_remote_ip_and_port: bool,
|
||||
pub export_latest_handshake_delay: bool,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn from_claps(matches: &clap::ArgMatches<'_>) -> Options {
|
||||
pub fn from_claps(matches: &clap::ArgMatches) -> Options {
|
||||
let options = Options {
|
||||
verbose: matches.is_present("verbose"),
|
||||
prepend_sudo: matches.is_present("prepend_sudo"),
|
||||
separate_allowed_ips: matches.is_present("separate_allowed_ips"),
|
||||
extract_names_config_file: matches
|
||||
.value_of("extract_names_config_files")
|
||||
.map(|e| e.to_owned()),
|
||||
interfaces: matches.values_of("interfaces").map(|e| {
|
||||
e.into_iter()
|
||||
.map(|a| {
|
||||
println!("a ==> {}", a);
|
||||
a.to_owned()
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"),
|
||||
verbose: *matches.get_one("verbose").unwrap_or(&false),
|
||||
prepend_sudo: *matches.get_one("prepend_sudo").unwrap_or(&false),
|
||||
separate_allowed_ips: *matches.get_one("separate_allowed_ips").unwrap_or(&false),
|
||||
extract_names_config_files: matches
|
||||
.get_many("extract_names_config_files")
|
||||
.map(|e: ValuesRef<'_, String>| e.into_iter().map(|a| a.to_owned()).collect()),
|
||||
interfaces: matches
|
||||
.get_many("interfaces")
|
||||
.map(|e: ValuesRef<'_, String>| e.into_iter().map(|a| a.to_string()).collect()),
|
||||
export_remote_ip_and_port: *matches
|
||||
.get_one("export_remote_ip_and_port")
|
||||
.unwrap_or(&false),
|
||||
export_latest_handshake_delay: *matches
|
||||
.get_one("export_latest_handshake_delay")
|
||||
.unwrap_or(&false),
|
||||
};
|
||||
|
||||
options
|
||||
|
|
176
src/wireguard.rs
176
src/wireguard.rs
|
@ -1,4 +1,5 @@
|
|||
use crate::exporter_error::ExporterError;
|
||||
use crate::options::Options;
|
||||
use crate::wireguard_config::PeerEntryHashMap;
|
||||
use crate::FriendlyDescription;
|
||||
use log::{debug, trace};
|
||||
|
@ -6,14 +7,40 @@ use prometheus_exporter_base::{MetricType, PrometheusInstance, PrometheusMetric}
|
|||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Debug;
|
||||
use std::net::SocketAddr;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
const EMPTY: &str = "(none)";
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) struct SecureString(String);
|
||||
|
||||
#[cfg(feature = "leaky_log")]
|
||||
impl Debug for SecureString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "leaky_log"))]
|
||||
impl Debug for SecureString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("**hidden**")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for SecureString {
|
||||
fn from(s: &str) -> Self {
|
||||
Self(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub(crate) struct LocalEndpoint {
|
||||
pub public_key: String,
|
||||
pub private_key: String,
|
||||
pub private_key: SecureString,
|
||||
pub local_port: u16,
|
||||
pub persistent_keepalive: bool,
|
||||
}
|
||||
|
@ -27,6 +54,7 @@ pub(crate) struct RemoteEndpoint {
|
|||
pub latest_handshake: u64,
|
||||
pub sent_bytes: u128,
|
||||
pub received_bytes: u128,
|
||||
#[allow(dead_code)]
|
||||
pub persistent_keepalive: bool,
|
||||
}
|
||||
|
||||
|
@ -70,7 +98,7 @@ impl TryFrom<&str> for WireGuard {
|
|||
// this is the local interface
|
||||
Endpoint::Local(LocalEndpoint {
|
||||
public_key: v[1].to_owned(),
|
||||
private_key: v[2].to_owned(),
|
||||
private_key: v[2].into(),
|
||||
local_port: v[3].parse::<u16>().unwrap(),
|
||||
persistent_keepalive: to_bool(v[4]),
|
||||
})
|
||||
|
@ -115,8 +143,7 @@ impl TryFrom<&str> for WireGuard {
|
|||
if let Some(endpoints) = wg.interfaces.get_mut(v[0]) {
|
||||
endpoints.push(endpoint);
|
||||
} else {
|
||||
let mut new_vec = Vec::new();
|
||||
new_vec.push(endpoint);
|
||||
let new_vec = vec![endpoint];
|
||||
wg.interfaces.insert(v[0].to_owned(), new_vec);
|
||||
}
|
||||
}
|
||||
|
@ -129,11 +156,11 @@ impl TryFrom<&str> for WireGuard {
|
|||
impl WireGuard {
|
||||
pub fn merge(&mut self, merge_from: &WireGuard) {
|
||||
for (interface_name, endpoints_to_merge) in merge_from.interfaces.iter() {
|
||||
if let Some(endpoints) = self.interfaces.get_mut(&interface_name as &str) {
|
||||
endpoints.extend_from_slice(&endpoints_to_merge);
|
||||
if let Some(endpoints) = self.interfaces.get_mut(interface_name as &str) {
|
||||
endpoints.extend_from_slice(endpoints_to_merge);
|
||||
} else {
|
||||
let mut new_vec = Vec::new();
|
||||
new_vec.extend_from_slice(&endpoints_to_merge);
|
||||
new_vec.extend_from_slice(endpoints_to_merge);
|
||||
self.interfaces.insert(interface_name.to_owned(), new_vec);
|
||||
}
|
||||
}
|
||||
|
@ -142,10 +169,12 @@ impl WireGuard {
|
|||
pub(crate) fn render_with_names(
|
||||
&self,
|
||||
pehm: Option<&PeerEntryHashMap>,
|
||||
split_allowed_ips: bool,
|
||||
export_remote_ip_and_port: bool,
|
||||
options: &Options,
|
||||
) -> String {
|
||||
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);
|
||||
debug!(
|
||||
"WireGuard::render_with_names(self == {:?}, pehm == {:?}, options == {:?} called",
|
||||
self, pehm, options
|
||||
);
|
||||
|
||||
// these are the exported counters
|
||||
let mut pc_sent_bytes_total = PrometheusMetric::build()
|
||||
|
@ -161,8 +190,19 @@ impl WireGuard {
|
|||
let mut pc_latest_handshake = PrometheusMetric::build()
|
||||
.with_name("wireguard_latest_handshake_seconds")
|
||||
.with_metric_type(MetricType::Gauge)
|
||||
.with_help("Seconds from the last handshake")
|
||||
.with_help("UNIX timestamp seconds of the last handshake")
|
||||
.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
|
||||
// lexicographical order.
|
||||
|
@ -188,12 +228,10 @@ impl WireGuard {
|
|||
// store in attibutes their references. attributes_owned is onyl
|
||||
// needed for separate ip+subnet
|
||||
let mut attributes_owned: Vec<(String, String)> = Vec::new();
|
||||
let mut attributes: Vec<(&str, &str)> = Vec::new();
|
||||
let mut attributes: Vec<(&str, &str)> =
|
||||
vec![("interface", interface), ("public_key", &ep.public_key)];
|
||||
|
||||
attributes.push(("interface", interface));
|
||||
attributes.push(("public_key", &ep.public_key));
|
||||
|
||||
if split_allowed_ips {
|
||||
if options.separate_allowed_ips {
|
||||
let v_ip_and_subnet: Vec<(&str, &str)> = ep
|
||||
.allowed_ips
|
||||
.split(',')
|
||||
|
@ -265,9 +303,9 @@ impl WireGuard {
|
|||
}
|
||||
}
|
||||
|
||||
if export_remote_ip_and_port {
|
||||
if options.export_remote_ip_and_port {
|
||||
if let Some(r_ip) = &ep.remote_ip {
|
||||
attributes.push(("remote_ip", &r_ip));
|
||||
attributes.push(("remote_ip", r_ip));
|
||||
}
|
||||
if let Some(r_port) = &ep.remote_port {
|
||||
attributes_owned.push(("remote_port".to_string(), r_port.to_string()));
|
||||
|
@ -283,6 +321,18 @@ impl WireGuard {
|
|||
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
|
||||
.render_and_append_instance(&instance.clone().with_value(ep.sent_bytes))
|
||||
.render();
|
||||
|
@ -299,10 +349,15 @@ impl WireGuard {
|
|||
}
|
||||
|
||||
format!(
|
||||
"{}\n{}\n{}",
|
||||
"{}\n{}\n{}{}",
|
||||
pc_sent_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())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -376,7 +431,17 @@ wg0\tsUsR6xufQQ8Tf0FuyY9tfEeYdhVMeFelr4ZMUrj+B0E=\t(none)\t10.211.123.128:51820\
|
|||
|
||||
let pe = PeerEntryHashMap::new();
|
||||
|
||||
let s = a.render_with_names(Some(&pe), true, true);
|
||||
let options = Options {
|
||||
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);
|
||||
|
||||
let s_ok = "# HELP wireguard_sent_bytes_total Bytes sent to the peer
|
||||
|
@ -419,7 +484,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=\"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 Seconds from the last handshake
|
||||
# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake
|
||||
# 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=\"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
|
||||
|
@ -466,13 +531,24 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
#[test]
|
||||
fn test_parse_and_serialize() {
|
||||
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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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 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";
|
||||
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";
|
||||
|
||||
let re = Endpoint::Remote(RemoteEndpoint {
|
||||
public_key: "test".to_owned(),
|
||||
|
@ -488,11 +564,20 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
interfaces: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut v = Vec::new();
|
||||
v.push(re);
|
||||
let v = vec![re];
|
||||
wg.interfaces.insert("Pippo".to_owned(), v);
|
||||
|
||||
let prometheus = wg.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: false,
|
||||
};
|
||||
|
||||
let prometheus = wg.render_with_names(None, &options);
|
||||
|
||||
assert_eq!(prometheus, REF);
|
||||
}
|
||||
|
@ -501,13 +586,13 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
fn test_render_to_prometheus_complex() {
|
||||
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 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 :&'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_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 :&'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_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_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_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";
|
||||
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";
|
||||
|
||||
let re1 = Endpoint::Remote(RemoteEndpoint {
|
||||
public_key: "test".to_owned(),
|
||||
|
@ -534,9 +619,7 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
interfaces: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut v = Vec::new();
|
||||
v.push(re1);
|
||||
v.push(re2);
|
||||
let v = vec![re1, re2];
|
||||
wg.interfaces.insert("Pippo".to_owned(), v);
|
||||
|
||||
let mut pehm = PeerEntryHashMap::new();
|
||||
|
@ -549,13 +632,27 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
};
|
||||
pehm.insert(pe.public_key, pe.clone());
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), false, true);
|
||||
let mut 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: false,
|
||||
};
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), &options);
|
||||
assert_eq!(prometheus, REF);
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), true, true);
|
||||
options.separate_allowed_ips = true;
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), &options);
|
||||
assert_eq!(prometheus, REF_SPLIT);
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), true, false);
|
||||
options.export_remote_ip_and_port = false;
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), &options);
|
||||
assert_eq!(prometheus, REF_SPLIT_NO_REMOTE);
|
||||
|
||||
// second test
|
||||
|
@ -583,7 +680,10 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0
|
|||
};
|
||||
pehm.insert(pe.public_key, pe.clone());
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), false, true);
|
||||
options.separate_allowed_ips = false;
|
||||
options.export_remote_ip_and_port = true;
|
||||
|
||||
let prometheus = wg.render_with_names(Some(&pehm), &options);
|
||||
assert_eq!(prometheus, REF_JSON);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,14 @@ use std::convert::TryInto;
|
|||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct PeerEntry<'a> {
|
||||
pub public_key: &'a str,
|
||||
#[allow(dead_code)]
|
||||
pub allowed_ips: &'a str,
|
||||
pub friendly_description: Option<FriendlyDescription<'a>>,
|
||||
}
|
||||
|
||||
fn after_char(s: &str, c_split: char) -> &str {
|
||||
let mut p: usize = 0;
|
||||
for c in s.chars().into_iter() {
|
||||
for c in s.chars() {
|
||||
if c == c_split {
|
||||
return &s[p + 1..];
|
||||
} else {
|
||||
|
@ -28,7 +29,7 @@ fn after_char_strip_comment(s: &str, c_split: char) -> &str {
|
|||
let s = after_char(s, c_split);
|
||||
|
||||
if let Some(idx) = s.find('#') {
|
||||
&s[..idx].trim()
|
||||
s[..idx].trim()
|
||||
} else {
|
||||
s
|
||||
}
|
||||
|
@ -116,7 +117,7 @@ pub(crate) fn peer_entry_hashmap_try_from(
|
|||
let mut v_blocks = Vec::new();
|
||||
let mut cur_block: Option<Vec<&str>> = None;
|
||||
|
||||
for line in txt.lines().into_iter() {
|
||||
for line in txt.lines() {
|
||||
if line.starts_with('[') {
|
||||
if let Some(inner_cur_block) = cur_block {
|
||||
// close the block
|
||||
|
@ -124,7 +125,7 @@ pub(crate) fn peer_entry_hashmap_try_from(
|
|||
cur_block = None;
|
||||
}
|
||||
|
||||
if line == "[Peer]" {
|
||||
if line == "[Peer]" || line == "[WireGuardPeer]" {
|
||||
// start a new block
|
||||
cur_block = Some(Vec::new());
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ pub(crate) fn peer_entry_hashmap_try_from(
|
|||
debug!("peer_entry_hashmap_try_from v_blocks == {:?}", v_blocks);
|
||||
|
||||
for block in &v_blocks {
|
||||
let p: PeerEntry = PeerEntry::try_from(&block as &[&str])?;
|
||||
let p: PeerEntry = PeerEntry::try_from(block as &[&str])?;
|
||||
hm.insert(p.public_key, p);
|
||||
}
|
||||
|
||||
|
@ -160,7 +161,7 @@ mod tests {
|
|||
use super::FriendlyDescription;
|
||||
use super::*;
|
||||
|
||||
const TEXT: &'static str = "
|
||||
const TEXT: &str = "
|
||||
ListenPort = 51820
|
||||
PrivateKey = my_super_secret_private_key
|
||||
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
|
||||
|
@ -204,7 +205,7 @@ PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
|
|||
AllowedIPs = 10.70.0.80/32
|
||||
";
|
||||
|
||||
const TEXT_JSON: &'static str = "
|
||||
const TEXT_JSON: &str = "
|
||||
ListenPort = 51820
|
||||
PrivateKey = my_super_secret_private_key
|
||||
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
|
||||
|
@ -248,7 +249,7 @@ PublicKey = 928vO9Lf4+Mo84cWu4k1oRyzf0AR7FTGoPKHGoTMSHk=
|
|||
AllowedIPs = 10.70.0.80/32
|
||||
";
|
||||
|
||||
const TEXT_NOPK: &'static str = "
|
||||
const TEXT_NOPK: &str = "
|
||||
ListenPort = 51820
|
||||
PrivateKey = my_super_secret_private_key
|
||||
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
|
||||
|
@ -269,7 +270,7 @@ PublicKey = L2UoJZN7RmEKsMmqaJgKG0m1S2Zs2wd2ptAf+kb3008=
|
|||
AllowedIPs = 10.70.0.4/32
|
||||
";
|
||||
|
||||
const TEXT_AIP: &'static str = "
|
||||
const TEXT_AIP: &str = "
|
||||
ListenPort = 51820
|
||||
PrivateKey = my_super_secret_private_key
|
||||
# PreUp = iptables -t nat -A POSTROUTING -s 10.70.0.0/24 -o enp7s0 -j MASQUERADE
|
||||
|
|
Loading…
Add table
Reference in a new issue