Compare commits
5 commits
ccd714acb7
...
9302bd110c
Author | SHA1 | Date | |
---|---|---|---|
9302bd110c | |||
ce88978583 | |||
6de1b761a5 | |||
dcdee5ffaa | |||
bf9549d801 |
13 changed files with 338 additions and 86 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake
|
19
.forgejo/workflows/build-docker.yml
Normal file
19
.forgejo/workflows/build-docker.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
tags: [ '*' ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
uses: famedly/github-workflows/.github/workflows/docker.yml@main
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }} # Always build, don't publish on pull requests
|
||||
registry_user: famedly-ci
|
||||
registry: docker-oss.nexus.famedly.de
|
||||
image_name: openmetrics-vici-exporter
|
||||
build_args: "VERSION=${{ matrix.version }}"
|
||||
secrets: inherit
|
13
.forgejo/workflows/build-rust.yml
Normal file
13
.forgejo/workflows/build-rust.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ['*']
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: famedly/github-workflows/.github/workflows/rust.yml@main
|
||||
secrets: inherit
|
28
.github/workflows/build.yml
vendored
28
.github/workflows/build.yml
vendored
|
@ -1,28 +0,0 @@
|
|||
name: CI
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
release:
|
||||
types: [ published ]
|
||||
jobs:
|
||||
docker:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ github.token }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
ghcr.io/${{ github.repository }}:latest
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
81
README.md
81
README.md
|
@ -1,28 +1,77 @@
|
|||
[](https://github.com/famedly/openmetrics-vici-expoter/actions/workflows/build.yml)
|
||||
|
||||
# openmetrics-vici-exporter
|
||||
|
||||
provides an openmetrics compatible endpoint for strongSwan charon's VICI.
|
||||
initally tested against strongSwan 5.9 and strongSwan 6.0.
|
||||
|
||||
## deployment
|
||||
pull container image from `ghcr.io`, see `docker-compose.yml` in this repo
|
||||
Provides an openmetrics compatible endpoint for strongSwan charon's VICI.
|
||||
|
||||
|
||||
## development
|
||||
## Features
|
||||
|
||||
1. `sudo groupadd vici`
|
||||
2. `sudo chown root:vici /var/run/charon.vici`
|
||||
3. `sudo chmod 0770 /var/run/charon.vici`
|
||||
4. `sudo usermod -aG vici $user`
|
||||
5. `cargo run`
|
||||
6. `curl http://localhost:8001/metrics`
|
||||
as of `v0.1.0` the following metrics are exporterd:
|
||||
|
||||
| name | |
|
||||
|------|-|
|
||||
|`sa_uptime`| seconds since state changed to up |
|
||||
|`sa_rekey_time`||
|
||||
|
||||
## license
|
||||
| name |
|
||||
|`sa_child_bytes_in`|
|
||||
|`sa_child_bytes_out`|
|
||||
|`sa_child_packets_in`|
|
||||
|`sa_child_packets_out`|
|
||||
|
||||
### Planned Features:
|
||||
* `v0.2.0`
|
||||
* an info metric showing the applied configuration
|
||||
* an enum metric showing the current state / queued jobs per connection
|
||||
|
||||
## Usage
|
||||
|
||||
### Deployment
|
||||
You have a few options avalible:
|
||||
1. [Binary Releases](/releases)
|
||||
2. Docker Image
|
||||
* `docker-oss.nexus.famedly.de/openmetrics-vici-exporter
|
||||
|
||||
### Configuration
|
||||
|
||||
All values have defaults, no configuration is necessary, but an exhaustive default configuration is still provided, see [`config.yml`](/blob/main/config.yml).
|
||||
|
||||
You can also set these as environment variables, prefixed with `VICI_EXPORTER`
|
||||
|
||||
| Key | Default | |
|
||||
|-----|---------|-|
|
||||
|`vici.socket`|`/var/run/charon.vici`| unix socket where vici is reachable |
|
||||
|`vici.interval`|`10`| how often to get data from the vici, in seconds |
|
||||
|`server.address`|`0.0.0.0`| any bind address, ipv6 is also allowed `[::1]`|
|
||||
|`server.port`|`8000`||
|
||||
|
||||
## Development
|
||||
|
||||
if you'd like to contribute you are free to do so.
|
||||
|
||||
we provide a nix flake (`nix develop`) to setup the rust enviroment for you, but there's still some manual setup to do.
|
||||
|
||||
you need charon running with the vici plugin enabled in the configuration.
|
||||
|
||||
make sure your user has the required permissions to access the vici socket.
|
||||
|
||||
on a debian system you can just run the following to give yourself access:
|
||||
|
||||
``` bash
|
||||
sudo groupadd vici
|
||||
sudo chown root:vici /var/run/charon.vici
|
||||
sudo chmod 0770 /var/run/charon.vici
|
||||
sudo usermod -aG vici $(whoami)
|
||||
```
|
||||
|
||||
` cargo run && curl http://[::1]:8001/metrics `
|
||||
|
||||
## License
|
||||
|
||||
[AGPL-3.0-only](LICENSE.md)
|
||||
|
||||
## authors
|
||||
## Authors
|
||||
|
||||
This software is authored and maintained as open-source by Famedly's Infrastructure Team.
|
||||
|
||||
- Evelyn Alicke <e.alicke@famedly.com>
|
||||
- Famedly GmbH <info@famedly.com>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
version: '3'
|
||||
|
||||
services:
|
||||
ove:
|
||||
openmetrics-vici-exporter:
|
||||
image: docker-oss.famedly.de/openmetrics-vici-exporter
|
||||
restart: "unless-stopped"
|
||||
environment:
|
||||
- VICI_EXPORTER_VICI_SOCKET="/var/run/charon.vici"
|
||||
|
@ -9,7 +10,7 @@ services:
|
|||
- VICI_EXPORTER_SERVER_ADDRESS=0.0.0.0
|
||||
- VICI_EXPORTER_SERVER_PORT=8001
|
||||
volumes:
|
||||
#- ./config.yml:/opt/openmetrics-vici-exporter/config.yml
|
||||
# - ./config.yml:/opt/openmetrics-vici-exporter/config.yml
|
||||
- /var/run/charon.vici:/var/run/charon.vici
|
||||
ports:
|
||||
- 8111:80/tcp
|
||||
- 8001:8001/tcp
|
||||
|
|
130
flake.lock
generated
Normal file
130
flake.lock
generated
Normal file
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1711333969,
|
||||
"narHash": "sha256-5PiWGn10DQjMZee5NXzeA6ccsv60iLu+Xtw+mfvkUAs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "57e6b3a9e4ebec5aa121188301f04a6b8c354c9b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1706487304,
|
||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711505476,
|
||||
"narHash": "sha256-yK1zue1c8EdpZvEyQWrjawG9Ykzl7eB2xJ/V+2vU5Jo=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "56f48d6e7559b807763ea03191bfaf95549ce610",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
40
flake.nix
Normal file
40
flake.nix
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
description = "A devShell example";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, rust-overlay, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = mkShell {
|
||||
buildInputs = [
|
||||
openssl
|
||||
pkg-config
|
||||
eza
|
||||
fd
|
||||
rust-bin.beta.latest.complete
|
||||
clippy
|
||||
rust-analyzer
|
||||
perf-tools
|
||||
linuxPackages_latest.perf
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
alias ls=eza
|
||||
alias find=fd
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
max_width = 120
|
|
@ -1,5 +0,0 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [ rustc cargo gcc rustfmt clippy ];
|
||||
name = "rust-env";
|
||||
}
|
|
@ -28,14 +28,17 @@ pub struct Configuration {
|
|||
|
||||
impl Configuration {
|
||||
pub async fn load() -> Result<Configuration> {
|
||||
let mut s = Config::builder();
|
||||
if std::fs::metadata("config").is_ok(){
|
||||
s = s.add_source(config::File::with_name("config"));
|
||||
} else { println!("config file not found. continuing with env vars... ") };
|
||||
|
||||
s = s.add_source(config::Environment::with_prefix("VICI_EXPORTER").separator("_"));
|
||||
// s.build().unwrap();
|
||||
let conf: Configuration = s.build().unwrap().try_deserialize().unwrap();
|
||||
Ok(conf)
|
||||
let settings = Config::builder()
|
||||
.set_default("vici.socket", "/var/run/charon.vici")?
|
||||
.set_default("vici.interval", 10)?
|
||||
.set_default("server.address", "0.0.0.0")?
|
||||
.set_default("server.port", 8000)?
|
||||
.add_source(config::File::with_name("config"))
|
||||
.add_source(config::Environment::with_prefix("VICI_EXPORTER").separator("_"))
|
||||
.build();
|
||||
match settings {
|
||||
Ok(body) => Ok(body.try_deserialize().unwrap()),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
33
src/main.rs
33
src/main.rs
|
@ -1,10 +1,4 @@
|
|||
use metrics::{
|
||||
describe_gauge,
|
||||
gauge,
|
||||
describe_counter,
|
||||
counter,
|
||||
IntoLabels,
|
||||
Unit};
|
||||
use metrics::{counter, describe_counter, describe_gauge, gauge, IntoLabels, Unit};
|
||||
use metrics_exporter_prometheus::PrometheusBuilder;
|
||||
use tokio::time::{interval, Duration, MissedTickBehavior};
|
||||
|
||||
|
@ -44,11 +38,26 @@ async fn main() -> anyhow::Result<()> {
|
|||
let mut child_labels = sa_child_values.into_labels();
|
||||
child_labels.push((&("sa_name", sa_name.clone())).into());
|
||||
child_labels.push((&("sa_child_name", sa_child_name)).into());
|
||||
counter!("sa_child_bytes_in", sa_child_values.bytes_in, child_labels.clone());
|
||||
counter!("sa_child_bytes_out", sa_child_values.bytes_out, child_labels.clone());
|
||||
counter!("sa_child_packets_in", sa_child_values.packets_in, child_labels.clone());
|
||||
counter!("sa_child_packets_out", sa_child_values.packets_out, child_labels.clone());
|
||||
|
||||
counter!(
|
||||
"sa_child_bytes_in",
|
||||
sa_child_values.bytes_in,
|
||||
child_labels.clone()
|
||||
);
|
||||
counter!(
|
||||
"sa_child_bytes_out",
|
||||
sa_child_values.bytes_out,
|
||||
child_labels.clone()
|
||||
);
|
||||
counter!(
|
||||
"sa_child_packets_in",
|
||||
sa_child_values.packets_in,
|
||||
child_labels.clone()
|
||||
);
|
||||
counter!(
|
||||
"sa_child_packets_out",
|
||||
sa_child_values.packets_out,
|
||||
child_labels.clone()
|
||||
);
|
||||
}
|
||||
}
|
||||
interval.tick().await;
|
||||
|
|
45
src/vici.rs
45
src/vici.rs
|
@ -1,12 +1,12 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{de::value::BoolDeserializer, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use futures_util::stream::StreamExt;
|
||||
|
||||
use anyhow::Result;
|
||||
use metrics::{IntoLabels,Label};
|
||||
use metrics::{IntoLabels, Label};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VICIState {
|
||||
|
@ -25,22 +25,45 @@ impl VICIState {
|
|||
Ok(VICIState {
|
||||
version: client.request("version", ()).await?,
|
||||
statistics: client.request("statistics", ()).await?,
|
||||
policies: collected_stream::<NamedPolicy, Policies>(client, "list-policies", "list-policy").await?,
|
||||
connections: collected_stream::<NamedConnection, Connections>(client, "list-connections", "list-conn")
|
||||
.await?,
|
||||
security_associations: collected_stream::<NamedSecurityAssociation, SecurityAssociations>(
|
||||
client, "list-sas", "list-sa",
|
||||
policies: collected_stream::<NamedPolicy, Policies>(
|
||||
client,
|
||||
"list-policies",
|
||||
"list-policy",
|
||||
)
|
||||
.await?,
|
||||
certificates: collected_stream::<NamedCertificate, Certificates>(client, "list-certs", "list-cert").await?,
|
||||
authorities: collected_stream::<NamedAuthority, Authorities>(client, "list-authorities", "list-authority")
|
||||
connections: collected_stream::<NamedConnection, Connections>(
|
||||
client,
|
||||
"list-connections",
|
||||
"list-conn",
|
||||
)
|
||||
.await?,
|
||||
security_associations:
|
||||
collected_stream::<NamedSecurityAssociation, SecurityAssociations>(
|
||||
client, "list-sas", "list-sa",
|
||||
)
|
||||
.await?,
|
||||
certificates: collected_stream::<NamedCertificate, Certificates>(
|
||||
client,
|
||||
"list-certs",
|
||||
"list-cert",
|
||||
)
|
||||
.await?,
|
||||
authorities: collected_stream::<NamedAuthority, Authorities>(
|
||||
client,
|
||||
"list-authorities",
|
||||
"list-authority",
|
||||
)
|
||||
.await?,
|
||||
pools: collected_stream::<NamedPool, Pools>(client, "list-pools", "list-pool").await?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn collected_stream<N, C>(client: &mut rsvici::Client, command: &str, event: &str) -> Result<C>
|
||||
async fn collected_stream<N, C>(
|
||||
client: &mut rsvici::Client,
|
||||
command: &str,
|
||||
event: &str,
|
||||
) -> Result<C>
|
||||
where
|
||||
N: for<'de> serde::Deserialize<'de>,
|
||||
C: std::iter::Extend<N> + Default,
|
||||
|
@ -243,7 +266,6 @@ pub struct SecurityAssociation {
|
|||
pub child_security_associations: HashMap<String, SecurityAssociationChild>,
|
||||
}
|
||||
|
||||
|
||||
impl IntoLabels for &SecurityAssociationChild {
|
||||
fn into_labels(self) -> Vec<Label> {
|
||||
vec![
|
||||
|
@ -253,7 +275,6 @@ impl IntoLabels for &SecurityAssociationChild {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SecurityAssociationChild {
|
||||
pub name: String,
|
||||
|
|
Loading…
Add table
Reference in a new issue