Initial Commit
This commit is contained in:
commit
a48db9c4c8
5 changed files with 520 additions and 0 deletions
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "openmetrics-vici-exporter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
config = { version = "0.13.1", features = ["yaml"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
prometheus-client = "0.18.1"
|
||||
futures-util = "0.3.25"
|
||||
actix-web-httpauth = "0.8.0"
|
||||
actix-web = "4.2.1"
|
||||
tokio = "1.21.2"
|
||||
rsvici = "0.1"
|
4
README.md
Normal file
4
README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
`groupadd vici`
|
||||
`chown root:vici /var/run/charon.vici`
|
||||
`chmod 0770 /var/run/charon.vici`
|
||||
`usermod -aG vici $user`
|
5
config.yml
Normal file
5
config.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
vici_socket: "/var/run/charon.vici"
|
||||
actix_bind_addr: "0.0.0.0"
|
||||
actix_bind_port: "80"
|
||||
actix_auth_token: ""
|
122
src/main.rs
Normal file
122
src/main.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
#![allow(dead_code,non_camel_case_types)] // I don't want to be bothered for case stuff decided upon me by the VICI API
|
||||
|
||||
use actix_web::{web, App, HttpResponse, HttpServer, Responder, Result};
|
||||
|
||||
use prometheus_client::{
|
||||
registry::Registry,
|
||||
encoding::{text::encode},
|
||||
metrics::{
|
||||
family::Family,
|
||||
info::Info,
|
||||
counter::Counter,
|
||||
gauge::Gauge,
|
||||
MetricType::Unknown,
|
||||
}
|
||||
};
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
error::Error,
|
||||
sync::Mutex,
|
||||
net::IpAddr,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
|
||||
use futures_util::{
|
||||
stream::{TryStreamExt},
|
||||
pin_mut,
|
||||
};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use config::Config;
|
||||
|
||||
mod vici_structs;
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Configuration {
|
||||
vici_socket: String,
|
||||
actix_bind_addr: IpAddr,
|
||||
actix_bind_port: u16,
|
||||
axtix_auth_token: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn metrics_handler(state: web::Data<Mutex<AppState>>) -> Result<HttpResponse> {
|
||||
let state = state.lock().unwrap();
|
||||
let mut buf = Vec::new();
|
||||
encode(&mut buf, &state.registry)?;
|
||||
let body = std::str::from_utf8(buf.as_slice()).unwrap().to_string();
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/openmetrics-text; version=1.0.0; charset=utf-8")
|
||||
.body(body))
|
||||
}
|
||||
|
||||
pub struct AppState {
|
||||
pub registry: Registry,
|
||||
pub vici: vici_structs::VICIState,
|
||||
}
|
||||
|
||||
pub struct Metrics {
|
||||
sa_uptime: Family<vici_structs::SecurityAssociationLabels, Counter>,
|
||||
}
|
||||
|
||||
impl Metrics {
|
||||
pub fn sa_uptime(&self, security_associations: vici_structs::SecurityAssociations) {
|
||||
for (sa_name, sa_values) in security_associations.into_iter() {
|
||||
self.sa_uptime.get_or_create(&vici_structs::SecurityAssociationLabels{uniqueid: sa_values.uniqueid}).inner(sa_values.established); // "Vertrau mir Bruder"
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
pub fn get_vici_state(client: rsvici::Client) -> Result<vici_structs::VICIState, actix_web::Error>{
|
||||
let version: vici_structs::Version = client.request("version", ()).await?;
|
||||
let statistics: vici_structs::Statistics = client.request("statistics", ()).await?;
|
||||
let connections = client.stream_request::<(), vici_structs::Connections>("list-connections", "list-conn", ());
|
||||
pin_mut!(connections);
|
||||
while let Some(conn) = connections.try_next().await? {
|
||||
println!("{:#?}", conn);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let settings = Config::builder()
|
||||
.add_source(config::File::with_name("config"))
|
||||
.add_source(config::Environment::with_prefix("VICI_EXPORTER"))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut conf: Configuration = settings.try_deserialize().unwrap();
|
||||
let mut client = rsvici::unix::connect(conf.vici_socket).await?;
|
||||
let mut vici_state: vici_structs::VICIState;
|
||||
|
||||
let metrics = web::Data::new(Metrics {
|
||||
sa_uptime: Family::default(),
|
||||
});
|
||||
|
||||
let mut state = AppState {
|
||||
registry: Registry::default(),
|
||||
vici: vici_structs::VICIState.update(client),
|
||||
};
|
||||
|
||||
state.registry.register(
|
||||
"sa_uptime",
|
||||
"How Long a connection has been established",
|
||||
Box::new(metrics.sa_uptime.clone()),
|
||||
);
|
||||
let state = web::Data::new(Mutex::new(state));
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
//.app_data(metrics.clone())
|
||||
.app_data(state.clone())
|
||||
.service(web::resource("/metrics").route(web::get().to(metrics_handler)))
|
||||
})
|
||||
.bind((conf.actix_bind_addr, conf.actix_bind_port))?
|
||||
.run()
|
||||
.await
|
||||
}
|
373
src/vici_structs.rs
Normal file
373
src/vici_structs.rs
Normal file
|
@ -0,0 +1,373 @@
|
|||
#![allow(dead_code,non_camel_case_types)] // I don't want to be bothered for case stuff decided upon me by the VICI API
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use prometheus_client::{
|
||||
encoding::text::Encode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VICIState {
|
||||
pub version: Version,
|
||||
pub statistics: Statistics,
|
||||
pub policies: Policies,
|
||||
pub connections: Connections,
|
||||
pub security_associations: SecurityAssociations,
|
||||
pub certificates: Certificates,
|
||||
pub authorities: Authorities,
|
||||
pub pools: Pools,
|
||||
}
|
||||
|
||||
impl<E> VICIState {
|
||||
async fn update(client: rsvici::Client) -> Result<VICIState, E> {
|
||||
VICIState {
|
||||
version: client.request("version", ()).await?,
|
||||
statistics: client.request("statistics", ()).await?,
|
||||
policies: client.stream_request::<(), Policies>("list-policies", "list-policy", ()).await?,
|
||||
connections: client.stream_request::<(), Connections>("list-connections", "list-conn", ()).await?,
|
||||
security_associations: client.stream_request::<(), SecurityAssociations>("list-sas", "list-sa", ()).await?,
|
||||
certificates: client.stream_request::<(), Certificates>("list-certs", "list-cert", ()).await?,
|
||||
authorities: client.stream_request::<(), Authorities>("list-authoroties", "list-authoroty", ()).await?,
|
||||
pools: client.stream_request::<(), Pools>("list-pools", "list-pool", ()).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Structs for parsing the control interface
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Version {
|
||||
pub daemon: String,
|
||||
pub version: String,
|
||||
pub sysname: String,
|
||||
pub release: String,
|
||||
pub machine: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Statistics {
|
||||
pub uptime: StatisticsUptime,
|
||||
pub workers: StatisticsWorkers,
|
||||
pub queues: StatisticsJobPriorities,
|
||||
pub scheduled: String,
|
||||
pub ikesecurity_associations: StatisticsIKESecurityAssociations,
|
||||
pub plugins: Vec<String>,
|
||||
pub mem: Option<StatisticsMem>,
|
||||
pub mallinfo: Option<StatisticsMallinfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsUptime {
|
||||
pub running: String,
|
||||
pub since: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsWorkers {
|
||||
pub total: String,
|
||||
pub idle: String,
|
||||
pub active: StatisticsJobPriorities,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsJobPriorities {
|
||||
pub critical: String,
|
||||
pub high: String,
|
||||
pub medium: String,
|
||||
pub low: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsIKESecurityAssociations {
|
||||
pub total: String,
|
||||
pub half_open: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsMem {
|
||||
pub total: String,
|
||||
pub allocs: String,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct StatisticsMallinfo {
|
||||
pub sbrk: String,
|
||||
pub mmap: String,
|
||||
pub used: String,
|
||||
pub free: String,
|
||||
}
|
||||
|
||||
pub type Policies = HashMap<String, Policy>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Policy {
|
||||
pub child: String,
|
||||
pub ike: Option<String>,
|
||||
pub mode: PolicyMode,
|
||||
pub local_ts: Option<Vec<String>>,
|
||||
pub remote_ts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum PolicyMode {
|
||||
tunnel,
|
||||
transport,
|
||||
pass,
|
||||
drop,
|
||||
}
|
||||
|
||||
pub type Connections = HashMap<String, Conn>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Conn {
|
||||
pub local_addrs: Vec<String>,
|
||||
pub remote_addrs: Vec<String>,
|
||||
pub version: String,
|
||||
pub reauth_time: u32,
|
||||
pub rekey_time: u32,
|
||||
pub children: HashMap<String, ConnChildSection>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ConnAuthSection {
|
||||
pub class: String,
|
||||
pub eap_type: Option<String>,
|
||||
pub eap_vendor: Option<String>,
|
||||
pub xauth: Option<String>,
|
||||
pub revocation: Option<String>,
|
||||
pub id: String,
|
||||
pub aaa_id: Option<String>,
|
||||
pub eap_id: Option<String>,
|
||||
pub xauth_id: Option<String>,
|
||||
pub groups: Option<Vec<String>>,
|
||||
pub certificates: Option<Vec<String>>,
|
||||
pub cacerts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ConnChildSection {
|
||||
pub mode: ChildSecurityAssociationMode,
|
||||
pub rekey_time: u32,
|
||||
pub rekey_bytes: u64,
|
||||
pub rekey_packets: u64,
|
||||
pub local_ts: Option<Vec<String>>,
|
||||
pub remote_ts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Hash, PartialEq, Eq)]
|
||||
enum ChildSecurityAssociationMode {
|
||||
TUNNEL,
|
||||
TRANSPORT,
|
||||
BEET,
|
||||
}
|
||||
#[derive(Debug, Deserialize, Clone, Hash, PartialEq, Eq)]
|
||||
enum ChildSecurityAssociationProtocol {
|
||||
AH,
|
||||
ESP,
|
||||
}
|
||||
|
||||
pub type SecurityAssociations = HashMap<String, SecurityAssociation>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SecurityAssociation {
|
||||
pub uniqueid: String,
|
||||
pub version: u8,
|
||||
pub state: String,
|
||||
pub local_host: Option<String>,
|
||||
pub local_port: Option<u16>,
|
||||
pub local_id: Option<String>,
|
||||
pub remote_host: Option<String>,
|
||||
pub remote_port: Option<u16>,
|
||||
pub remote_id: Option<String>,
|
||||
pub remote_xauth_id: Option<String>,
|
||||
pub remote_epa_id: Option<String>,
|
||||
pub initiator: Option<bool>,
|
||||
pub initiator_spi: Option<String>,
|
||||
pub responder_spi: Option<String>,
|
||||
pub nat_local: Option<bool>,
|
||||
pub nat_remote: Option<bool>,
|
||||
pub nat_fake: Option<bool>,
|
||||
pub nat_any: Option<bool>,
|
||||
pub if_id_in: Option<String>,
|
||||
pub if_id_out: Option<String>,
|
||||
pub encr_alg: Option<String>,
|
||||
pub encr_keysize: Option<String>,
|
||||
pub integ_alg: Option<String>,
|
||||
pub integ_keysize: Option<String>,
|
||||
pub prf_alg: Option<String>,
|
||||
pub dh_group: Option<String>,
|
||||
pub established: u64,
|
||||
pub rekey_time: Option<u32>,
|
||||
pub reauth_time: Option<u32>,
|
||||
pub local_vips: Option<Vec<String>>,
|
||||
pub remote_vips: Option<Vec<String>>,
|
||||
pub tasks_queued: Option<Vec<String>>,
|
||||
pub tasks_active: Option<Vec<String>>,
|
||||
pub tasks_passive: Option<Vec<String>>,
|
||||
pub child_security_associations: Option<HashMap<String, SecurityAssociationChild>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct SecurityAssociationChild {
|
||||
pub name: String,
|
||||
pub uniqueid: String,
|
||||
pub reqid: String,
|
||||
pub state: String,
|
||||
pub mode: ChildSecurityAssociationMode,
|
||||
pub protocol: ChildSecurityAssociationProtocol,
|
||||
pub encap: Option<bool>,
|
||||
pub spi_in: String,
|
||||
pub spi_out: String,
|
||||
pub cpi_in: Option<String>,
|
||||
pub cpi_out: Option<String>,
|
||||
pub mark_in: Option<String>,
|
||||
pub mark_mask_in: Option<String>,
|
||||
pub mark_out: Option<String>,
|
||||
pub mark_mask_out: Option<String>,
|
||||
pub if_id_in: Option<String>,
|
||||
pub if_id_out: Option<String>,
|
||||
pub encr_alg: Option<String>,
|
||||
pub encr_keysize: Option<String>,
|
||||
pub integ_alg: Option<String>,
|
||||
pub integ_keysize: Option<String>,
|
||||
pub prf_alg: Option<String>,
|
||||
pub dh_group: Option<String>,
|
||||
pub esn: Option<u16>,
|
||||
pub bytes_in: u64,
|
||||
pub packets_in: u64,
|
||||
pub use_in: Option<u32>,
|
||||
pub bytes_out: u64,
|
||||
pub packets_out: u64,
|
||||
pub use_out: Option<u32>,
|
||||
pub rekey_time: Option<u32>,
|
||||
pub life_time: u32,
|
||||
pub install_time: u64,
|
||||
pub local_ts: Vec<String>,
|
||||
pub remote_ts: Vec<String>,
|
||||
}
|
||||
|
||||
pub type Certificates = HashMap<String, Cert>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Cert {
|
||||
pub r#type: CertType,
|
||||
pub flag: X509CertFlag,
|
||||
pub has_privkey: Option<String>,
|
||||
pub data: String,
|
||||
pub subject: Option<String>,
|
||||
pub not_before: Option<String>,
|
||||
pub not_after: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum CertType {
|
||||
X509,
|
||||
X509_AC,
|
||||
X509_CRL,
|
||||
OSCP_RESPONSE,
|
||||
PUBKEY,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum X509CertFlag {
|
||||
NONE,
|
||||
CA,
|
||||
AA,
|
||||
OCSP,
|
||||
}
|
||||
|
||||
pub type Authorities = HashMap<String, Authority>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Authority {
|
||||
pub cacert: String,
|
||||
pub crl_uris: Vec<String>,
|
||||
pub ocsp_uris: Vec<String>,
|
||||
pub cert_uri_base: String,
|
||||
}
|
||||
|
||||
pub type Pools = HashMap<String, Pool>;
|
||||
|
||||
#[derive(Debug,Deserialize)]
|
||||
pub struct Pool {
|
||||
pub name: String,
|
||||
pub base: String,
|
||||
pub size: u128,
|
||||
pub online: u128,
|
||||
pub offline: u128,
|
||||
pub leases: Option<HashMap<u16,PoolLease>>,
|
||||
}
|
||||
|
||||
#[derive(Debug,Deserialize)]
|
||||
pub struct PoolLease {
|
||||
pub address: String,
|
||||
pub identity: String,
|
||||
pub status: PoolLeaseStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum PoolLeaseStatus {
|
||||
online,
|
||||
offline,
|
||||
}
|
||||
|
||||
// Structs for generating metrics, TODO
|
||||
|
||||
/*
|
||||
#[derive(Debug, Deserialize, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct SecurityAssociationLabels {
|
||||
pub uniqueid: String,
|
||||
pub local_id: String,
|
||||
pub local_host: String,
|
||||
pub local_port: u16,
|
||||
pub remote_id: String,
|
||||
pub remote_host: String,
|
||||
pub remote_port: u16,
|
||||
}
|
||||
*/
|
||||
#[derive(Debug, Deserialize, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct SecurityAssociationInfo {
|
||||
pub uniqueid: String,
|
||||
pub version: u8,
|
||||
pub local_host: String,
|
||||
pub local_port: u16,
|
||||
pub local_id: String,
|
||||
pub remote_host: String,
|
||||
pub remote_port: u16,
|
||||
pub remote_id: String,
|
||||
pub if_id_in: String,
|
||||
pub if_id_out: String,
|
||||
pub encr_alg: String,
|
||||
pub encr_keysize: String,
|
||||
pub integ_alg: String,
|
||||
pub integ_keysize: String,
|
||||
pub prf_alg: String,
|
||||
pub dh_group: Option<String>,
|
||||
pub local_vips: Vec<String>,
|
||||
pub remote_vips: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct SecurityAssociationChildInfo {
|
||||
pub name: String,
|
||||
pub uniqueid: String,
|
||||
pub reqid: String,
|
||||
pub mode: ChildSecurityAssociationMode,
|
||||
pub if_id_in: String,
|
||||
pub if_id_out: String,
|
||||
pub encr_alg: String,
|
||||
pub encr_keysize: String,
|
||||
pub integ_alg: String,
|
||||
pub integ_keysize: String,
|
||||
pub prf_alg: String,
|
||||
pub dh_group: Option<String>,
|
||||
pub local_ts: Vec<String>,
|
||||
pub remote_ts: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq, Encode)]
|
||||
pub struct SecurityAssociationLabels {
|
||||
pub uniqueid: String,
|
||||
}
|
Loading…
Add table
Reference in a new issue