intiial import of new code

main
Marek Isalski 3 years ago
parent c9e1824371
commit c151212db9

44
Cargo.lock generated

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@ -445,27 +447,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "peshming"
version = "0.4.1"
dependencies = [
"anyhow",
"async-anyhow-logger",
"chrono",
"clap",
"fern",
"futures",
"futures-util",
"hyper",
"lazy_static",
"log",
"prometheus",
"serde",
"tokio",
"tokio-icmp-echo",
"toml",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.7" version = "1.0.7"
@ -604,6 +585,27 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "rexaping"
version = "0.4.1"
dependencies = [
"anyhow",
"async-anyhow-logger",
"chrono",
"clap",
"fern",
"futures",
"futures-util",
"hyper",
"lazy_static",
"log",
"prometheus",
"serde",
"tokio",
"tokio-icmp-echo",
"toml",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"

@ -1,12 +1,12 @@
[package] [package]
name = "peshming" name = "rexaping"
version = "0.4.1" version = "0.5.0"
license = "AGPL-3.0-only" license = "AGPL-3.0-only"
authors = ["Jan Christian Grünhage <jan.christian@gruenhage.xyz>"] authors = ["Marek Isalski <marek@faelix.net>", "Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
repository = "https://git.jcg.re/jcgruenhage/peshming" repository = "https://gitea.faelix.net/FAELIX/rexaping"
keywords = ["ping", "icmp", "prometheus"] keywords = ["ping", "icmp", "prometheus"]
edition = "2018" edition = "2021"
description = "Pings configured hosts in a configurable intervals and exposes metrics for prometheus." description = "Pings configured hosts in a configurable intervals and labels, and exposes metrics for prometheus."
[dependencies] [dependencies]
prometheus = "0.12" prometheus = "0.12"

@ -1,21 +1,22 @@
## peshming ## rexaping
It's a prometheus exporter pinging hosts in the background. It's a prometheus exporter pinging hosts in the background.
It's been inspired by [meshping](https://bitbucket.org/Svedrin/meshping), It's been forked from [peshming](https://git.jcg.re/jcgruenhage/peshming),
but instead of managing targets using a redis db this is using a simple config file. but only allowing targets to specify an interval, the config file can enrich
In addition, this tool allows to set a ping frequency per target. the Prometheus metrics with additional labels.
The name peshming is intended as a placeholder until The name rexaping is a play on exaping, a tool with the same purpose
someone comes up with something better. originally written in Python for Exa Networks.
### Usage: ### Usage:
``` ```
$ peshming --help $ rexaping --help
peshming 0.2.3 rexaping 0.2.3
Marek Isalski <marek@faelix.net>
Jan Christian Grünhage <jan.christian@gruenhage.xyz> Jan Christian Grünhage <jan.christian@gruenhage.xyz>
Pings configured hosts in a configurable intervals and exposes metrics for prometheus. Pings configured hosts in a configurable intervals and exposes metrics for prometheus.
USAGE: USAGE:
peshming [FLAGS] <config> rexaping [FLAGS] <config>
FLAGS: FLAGS:
-h, --help Prints help information -h, --help Prints help information

@ -7,5 +7,5 @@ listener = "[::]:9898"
# will ping the primary and secondary IP of cloudflare's 1.1.1.1 DNS service # will ping the primary and secondary IP of cloudflare's 1.1.1.1 DNS service
# every 500ms, or twice per second. # every 500ms, or twice per second.
[hosts] [hosts]
"1.1.1.1" = 500 "1.1.1.1" = { interval = "500", device = "one.one.one.one", interface="eth1111" }
"1.0.0.1" = 500 "1.0.0.1" = { interval = "500", device = "one.one.one.one", interface="eth1001" }

@ -3,6 +3,7 @@
* * * *
* Copyright (C) 2019-2020 Jan Christian Grünhage * * Copyright (C) 2019-2020 Jan Christian Grünhage *
* Copyright (C) 2020 Famedly GmbH * * Copyright (C) 2020 Famedly GmbH *
* Copyright (C) 2021-2022 Faelix Limited *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as * * it under the terms of the GNU Affero General Public License as *
@ -26,7 +27,7 @@ use std::collections::HashMap;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub(crate) struct Config { pub(crate) struct Config {
pub(crate) listener: std::net::SocketAddr, pub(crate) listener: std::net::SocketAddr,
pub(crate) hosts: HashMap<std::net::IpAddr, u64>, pub(crate) hosts: HashMap<std::net::IpAddr, HashMap<String, String>>,
} }
fn setup_clap() -> clap::ArgMatches<'static> { fn setup_clap() -> clap::ArgMatches<'static> {

@ -3,6 +3,7 @@
* * * *
* Copyright (C) 2019-2020 Jan Christian Grünhage * * Copyright (C) 2019-2020 Jan Christian Grünhage *
* Copyright (C) 2020 Famedly GmbH * * Copyright (C) 2020 Famedly GmbH *
* Copyright (C) 2021-2022 Faelix Limited *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as * * it under the terms of the GNU Affero General Public License as *

@ -3,6 +3,7 @@
* * * *
* Copyright (C) 2019-2020 Jan Christian Grünhage * * Copyright (C) 2019-2020 Jan Christian Grünhage *
* Copyright (C) 2020 Famedly GmbH * * Copyright (C) 2020 Famedly GmbH *
* Copyright (C) 2021-2022 Faelix Limited *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as * * it under the terms of the GNU Affero General Public License as *

@ -3,6 +3,7 @@
* * * *
* Copyright (C) 2019-2020 Jan Christian Grünhage * * Copyright (C) 2019-2020 Jan Christian Grünhage *
* Copyright (C) 2020 Famedly GmbH * * Copyright (C) 2020 Famedly GmbH *
* Copyright (C) 2021-2022 Faelix Limited *
* * * *
* This program is free software: you can redistribute it and/or modify * * This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as * * it under the terms of the GNU Affero General Public License as *
@ -21,39 +22,54 @@ use crate::config::Config;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_anyhow_logger::catch; use async_anyhow_logger::catch;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use log::{info, trace}; use log::{trace};
use prometheus::*; use prometheus::*;
use std::net::IpAddr; use std::net::IpAddr;
use std::time::Duration; use std::time::Duration;
use tokio_icmp_echo::{PingFuture, Pinger}; use tokio_icmp_echo::{PingFuture, Pinger};
use std::collections::HashMap;
lazy_static! { lazy_static! {
static ref PING_HISTOGRAM: HistogramVec = register_histogram_vec!( static ref PING_HISTOGRAM: HistogramVec = register_histogram_vec!(
"ping_rtt_milliseconds", "ping_rtt_milliseconds",
"The ping round trip time in milliseconds", "The ping round trip time in milliseconds",
&["target"], &["target", "device", "interface", "expected", "team", "priority"],
vec![ vec![
0.5, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 50.0, 75.0, 100.0, 150.0, 200.0, 250.0, 300.0, 0.125, 0.25, 0.5, 1.0, 1.5, 2.0, 2.5, 5.0, 7.5, 10.0, 15.0, 20.0, 25.0, 30.0,
350.0, 400.0, 450.0, 500.0, 550.0, 600.0, 650.0, 700.0, 750.0, 800.0, 900.0, 1000.0, 35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 90.0, 100.0,
1250.0, 1500.0, 1750.0, 2000.0 125.0, 150.0, 175.0, 200.0, 250.0, 300.0, 400.0, 500.0, 750.0, 1000.0, 2000.0, 4000.0
] ]
) )
.unwrap(); .unwrap();
} }
lazy_static! {
static ref PING_COUNTER: IntCounterVec =
register_int_counter_vec!("ping_replies", "Number of ICMP ping responses received", &["target"]).unwrap();
}
pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> { pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> {
let pinger = Pinger::new().await.context("Couldn't create pinger")?; let pinger = Pinger::new().await.context("Couldn't create pinger")?;
let mut handles = vec![]; let mut handles = vec![];
for (host, interval) in config.hosts.clone() { let mut interval;
info!("Spawn ping task for {}", host);
handles.push(tokio::spawn(ping_host(pinger.clone(), host, interval))); for (target, hostdata) in config.hosts.clone() {
let hd_interval = hostdata.get("interval");
match hd_interval {
Some(ival) => {
interval = ival.parse()?;
},
_ => interval = 1000,
}
handles.push(tokio::spawn(ping_host(pinger.clone(), target, interval, hostdata)));
} }
let (result, _, _) = futures::future::select_all(handles).await; let (result, _, _) = futures::future::select_all(handles).await;
result??; result??;
Ok(()) Ok(())
} }
async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64) -> Result<()> { async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64, hostdata: HashMap<String, String>) -> Result<()> {
let mut pingchain = pinger.chain(host).timeout(Duration::from_secs(3)); let mut pingchain = pinger.chain(host).timeout(Duration::from_secs(3));
let mut interval = tokio::time::interval(Duration::from_millis(interval)); let mut interval = tokio::time::interval(Duration::from_millis(interval));
let host_string = host.to_string(); let host_string = host.to_string();
@ -62,23 +78,41 @@ async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64) -> Result<()> {
tokio::spawn(catch(handle_ping_result( tokio::spawn(catch(handle_ping_result(
pingchain.send(), pingchain.send(),
host_string.clone(), host_string.clone(),
hostdata.clone(),
))); )));
} }
} }
async fn handle_ping_result(result: PingFuture, host: String) -> Result<()> { async fn handle_ping_result(result: PingFuture, host: String, hostdata: HashMap<String, String>) -> Result<()> {
let pong = result.await.context(format!("Couldn't ping {}", &host))?; let pong = result.await.context(format!("Couldn't ping {}", &host))?;
let empty = "".to_string();
let device = hostdata.get("device").unwrap_or(&empty);
let interface = hostdata.get("interface").unwrap_or(&empty);
let team = hostdata.get("team").unwrap_or(&empty);
let up = "up".to_string();
let expected = hostdata.get("expected").unwrap_or(&up);
let notice = "notice".to_string();
let severity = hostdata.get("severity").unwrap_or(&notice);
match pong { match pong {
Some(time) => { Some(time) => {
let ms = time.as_millis(); let ms = time.as_millis();
trace!("Received pong from {} after {} ms", &host, &ms); trace!("Received pong from {} after {} ms", &host, &ms);
PING_HISTOGRAM PING_HISTOGRAM
.with_label_values(&[&host]) .with_label_values(&[&host, device, interface, expected, team, severity])
.observe(ms as f64); .observe(ms as f64);
//PING_COUNTER
// .with_label_values(&[&host])
// .collect();
} }
None => { None => {
trace!("Received no response from {} within timeout", &host); trace!("Received no response from {} within timeout", &host);
PING_HISTOGRAM.with_label_values(&[&host]).observe(3000.0); PING_HISTOGRAM
.with_label_values(&[&host, device, interface, expected, team, severity])
.observe(4000.0);
} }
}; };

Loading…
Cancel
Save