diff --git a/.gitignore b/.gitignore index 38b709b..cf9c4a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target **/*.rs.bk *.vim +.idea +*.tar diff --git a/Cargo.lock b/Cargo.lock index f537790..3b37539 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" @@ -74,9 +74,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" [[package]] name = "byteorder" @@ -86,15 +86,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.68" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" [[package]] name = "cfg-if" @@ -212,24 +212,24 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures-channel" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-macro" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg", "proc-macro-hack", @@ -240,15 +240,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-util" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", "futures-core", @@ -283,9 +283,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ "bytes", "fnv", @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" +checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" dependencies = [ "bytes", "http", @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" @@ -332,9 +332,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.10" +version = "0.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7728a72c4c7d72665fde02204bcbd93b247721025b222ef78606f14513e0fd03" +checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" dependencies = [ "bytes", "futures-channel", @@ -372,15 +372,15 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -393,9 +393,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.98" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" [[package]] name = "log" @@ -408,9 +408,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" @@ -558,18 +558,17 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] [[package]] name = "prometheus_exporter_base" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e31a078176ab4e58d34c158b1c64c0a562670c739372a6b9d81f0fdf149789a" +version = "1.3.0" +source = "git+https://github.com/gausnes/prometheus_exporter_base?branch=ContentType#0f689d5c2aec99e3a8a26b4ee37901d649e23d70" dependencies = [ "clap", "env_logger 0.7.1", @@ -610,9 +609,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] @@ -731,9 +730,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.3.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", "core-foundation", @@ -744,9 +743,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.3.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", @@ -754,15 +753,15 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -771,9 +770,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -782,15 +781,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "socket2" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ "libc", "winapi", @@ -810,9 +809,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.73" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" dependencies = [ "proc-macro2", "quote", @@ -850,18 +849,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -870,9 +869,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c8b05dc14c75ea83d63dd391100353789f5f24b8b3866542a5e85c8be8e985" +checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" dependencies = [ "autocfg", "libc", @@ -884,9 +883,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "154794c8f499c2619acd19e839294703e9e32e7630ef5f46ea80d4ef0fbee5eb" dependencies = [ "proc-macro2", "quote", @@ -912,9 +911,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.26" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if", "pin-project-lite", @@ -923,9 +922,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] @@ -938,9 +937,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -978,9 +977,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -988,9 +987,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -1003,9 +1002,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1013,9 +1012,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -1026,15 +1025,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index c3c9fe3..bc48bfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ 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"] } +prometheus_exporter_base = { git = "https://github.com/gausnes/prometheus_exporter_base", branch = "ContentType", features = ["hyper_server"] } regex = "1.5.4" [dev-dependencies] diff --git a/src/main.rs b/src/main.rs index e9b986e..d334ccc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,9 @@ mod friendly_description; pub use friendly_description::*; use wireguard::WireGuard; mod exporter_error; +mod metrics; mod wireguard_config; + use prometheus_exporter_base::render_prometheus; use std::net::IpAddr; use std::sync::Arc; @@ -33,7 +35,7 @@ async fn perform_request( .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 + .map(|file| std::fs::read_to_string(file as &str)) // read the contents into a String .collect::, std::io::Error>>() // And transform it into a vec (stopping in case of errors) }) .transpose()? // bail out if there was an error @@ -102,11 +104,8 @@ 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.metric_attributes)) } else { panic!(); } @@ -155,6 +154,12 @@ async fn main() -> Result<(), Box> { .help("exports peer's remote ip and port as labels (if available)") .takes_value(false), ) + .arg( + Arg::with_name("handshake_timeout_seconds") + .short("t") + .help("Handshake timeout to determine if host is still connected") + .takes_value(true), + ) .arg( Arg::with_name("extract_names_config_files") .short("n") @@ -194,7 +199,7 @@ async fn main() -> Result<(), Box> { info!("using options: {:?}", options); let bind = matches.value_of("port").unwrap(); - let bind = (&bind).parse::().expect("port must be a valid number"); + let bind = bind.parse::().expect("port must be a valid number"); let ip = matches.value_of("addr").unwrap().parse::().unwrap(); let addr = (ip, bind).into(); diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 0000000..02c9fc5 --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,90 @@ +use prometheus_exporter_base::{ + MetricType, MissingValue, PrometheusInstance, PrometheusMetric, Yes, +}; + +#[derive(Debug, Clone)] +pub(crate) struct MetricAttributeOptions { + pub split_allowed_ips: bool, + pub export_remote_ip_and_port: bool, + pub handshake_timeout_seconds: Option, +} + +pub struct EndpointMetrics<'a> { + pub pc_sent_bytes_total: PrometheusMetric<'a>, + pub pc_received_bytes_total: PrometheusMetric<'a>, + pub pc_latest_handshake: PrometheusMetric<'a>, +} + +impl<'a> EndpointMetrics<'a> { + pub fn new() -> EndpointMetrics<'a> { + return EndpointMetrics { + pc_sent_bytes_total: PrometheusMetric::build() + .with_name("wireguard_sent_bytes_total") + .with_metric_type(MetricType::Counter) + .with_help("Bytes sent to the peer") + .build(), + pc_received_bytes_total: PrometheusMetric::build() + .with_name("wireguard_received_bytes_total") + .with_metric_type(MetricType::Counter) + .with_help("Bytes received from the peer") + .build(), + pc_latest_handshake: PrometheusMetric::build() + .with_name("wireguard_latest_handshake_seconds") + .with_metric_type(MetricType::Gauge) + .with_help("Seconds from the last handshake") + .build(), + }; + } + + pub fn sent_bytes_total( + &mut self, + instance: &PrometheusInstance, + bytes: u128, + ) { + self.pc_sent_bytes_total + .render_and_append_instance(&instance.clone().with_value(bytes)) + .render(); + } + + pub fn received_bytes_total( + &mut self, + instance: &PrometheusInstance, + bytes: u128, + ) { + self.pc_received_bytes_total + .render_and_append_instance(&instance.clone().with_value(bytes)) + .render(); + } + + pub fn latest_handshake( + &mut self, + instance: &PrometheusInstance, + latest: u128, + ) { + self.pc_latest_handshake + .render_and_append_instance(&instance.clone().with_value(latest)) + .render(); + } +} + +pub struct InterfaceMetrics<'a> { + pub total_peers_gauge: PrometheusMetric<'a>, +} + +impl<'a> InterfaceMetrics<'a> { + pub fn new() -> InterfaceMetrics<'a> { + return InterfaceMetrics { + total_peers_gauge: PrometheusMetric::build() + .with_name("wireguard_peers_total") + .with_metric_type(MetricType::Gauge) + .with_help("Total number of peers") + .build(), + }; + } + + pub fn connected_peers(&mut self, instance: &PrometheusInstance) { + self.total_peers_gauge + .render_and_append_instance(instance) + .render(); + } +} diff --git a/src/options.rs b/src/options.rs index b15d759..1271b35 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,26 +1,34 @@ +use crate::metrics::MetricAttributeOptions; + #[derive(Debug, Clone)] pub(crate) struct Options { pub verbose: bool, pub prepend_sudo: bool, - pub separate_allowed_ips: bool, pub extract_names_config_files: Option>, pub interfaces: Option>, - pub export_remote_ip_and_port: bool, + pub metric_attributes: MetricAttributeOptions, } impl Options { pub fn from_claps(matches: &clap::ArgMatches<'_>) -> Options { + let handshake_timeout_seconds = matches + .value_of("handshake_timeout_seconds") + .map(|timeout| timeout.parse::().unwrap()); + let options = Options { verbose: matches.is_present("verbose"), prepend_sudo: matches.is_present("prepend_sudo"), - separate_allowed_ips: matches.is_present("separate_allowed_ips"), + metric_attributes: MetricAttributeOptions { + split_allowed_ips: matches.is_present("separate_allowed_ips"), + export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"), + handshake_timeout_seconds, + }, extract_names_config_files: matches .values_of("extract_names_config_files") .map(|e| e.into_iter().map(|e| e.to_owned()).collect()), interfaces: matches .values_of("interfaces") .map(|e| e.into_iter().map(|a| a.to_owned()).collect()), - export_remote_ip_and_port: matches.is_present("export_remote_ip_and_port"), }; options diff --git a/src/wireguard.rs b/src/wireguard.rs index 0df43a1..845f37f 100644 --- a/src/wireguard.rs +++ b/src/wireguard.rs @@ -1,13 +1,15 @@ use crate::exporter_error::ExporterError; +use crate::metrics::{EndpointMetrics, InterfaceMetrics, MetricAttributeOptions}; use crate::wireguard_config::PeerEntryHashMap; use crate::FriendlyDescription; use log::{debug, trace}; -use prometheus_exporter_base::{MetricType, PrometheusInstance, PrometheusMetric}; +use prometheus_exporter_base::PrometheusInstance; use regex::Regex; use std::collections::HashMap; use std::convert::TryFrom; use std::fmt::Debug; use std::net::SocketAddr; +use std::time::{SystemTime, UNIX_EPOCH}; const EMPTY: &str = "(none)"; @@ -152,11 +154,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) { + 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); } } @@ -165,27 +167,14 @@ impl WireGuard { pub(crate) fn render_with_names( &self, pehm: Option<&PeerEntryHashMap>, - split_allowed_ips: bool, - export_remote_ip_and_port: bool, + metric_attribute_options: &MetricAttributeOptions, ) -> 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 == {:?}, split_allowed_ips == {:?}, export_remote_ip_and_port == {:?} called", + self, pehm, metric_attribute_options.split_allowed_ips, metric_attribute_options.export_remote_ip_and_port); // these are the exported counters - let mut pc_sent_bytes_total = PrometheusMetric::build() - .with_name("wireguard_sent_bytes_total") - .with_metric_type(MetricType::Counter) - .with_help("Bytes sent to the peer") - .build(); - let mut pc_received_bytes_total = PrometheusMetric::build() - .with_name("wireguard_received_bytes_total") - .with_metric_type(MetricType::Counter) - .with_help("Bytes received from the peer") - .build(); - 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") - .build(); + let mut endpoint_metrics = EndpointMetrics::new(); + let mut interface_metrics = InterfaceMetrics::new(); // Here we make sure we process the interfaces in the // lexicographical order. @@ -202,131 +191,192 @@ impl WireGuard { interfaces_sorted.sort_by(|a, b| a.0.partial_cmp(b.0).unwrap()); for (interface, endpoints) in interfaces_sorted.into_iter() { - for endpoint in endpoints { - // only show remote endpoints - if let Endpoint::Remote(ep) = endpoint { - debug!("WireGuard::render_with_names ep == {:?}", ep); - - // we store in attributes_owned the ownership of the values in order to - // 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![ - ("interface", interface), - ("public_key", &ep.public_key), - ]; - - if split_allowed_ips { - let v_ip_and_subnet: Vec<(&str, &str)> = ep - .allowed_ips - .split(',') - .map(|ip_and_subnet| { - debug!( - "WireGuard::render_with_names ip_and_subnet == {:?}", - ip_and_subnet - ); - let tokens: Vec<&str> = ip_and_subnet.split('/').collect(); - debug!("WireGuard::render_with_names tokens == {:?}", tokens); - let addr = tokens[0]; - let subnet = tokens[1]; - (addr, subnet) - }) - .collect(); - - for (idx, (ip, subnet)) in v_ip_and_subnet.iter().enumerate() { - attributes_owned - .push((format!("allowed_ip_{}", idx), (*ip).to_string())); - attributes_owned - .push((format!("allowed_subnet_{}", idx), (*subnet).to_string())); - } + let remote_endpoints: Vec<&RemoteEndpoint> = endpoints + .iter() + .map(|endpoint| { + self.populate_remote_endpoint_metrics( + pehm, + interface, + endpoint, + &mut endpoint_metrics, + metric_attribute_options, + ) + }) + .flatten() + .collect(); + + self.populate_interface_metrics( + interface, + &remote_endpoints, + &mut interface_metrics, + metric_attribute_options, + ); + } + + format!( + "{}\n{}\n{}\n{}", + endpoint_metrics.pc_sent_bytes_total.render(), + endpoint_metrics.pc_received_bytes_total.render(), + endpoint_metrics.pc_latest_handshake.render(), + interface_metrics.total_peers_gauge.render() + ) + } + + pub(self) fn populate_interface_metrics( + &self, + interface: &str, + remote_endpoints: &[&RemoteEndpoint], + interface_metrics: &mut InterfaceMetrics, + metric_attribute_options: &MetricAttributeOptions, + ) { + let start = SystemTime::now(); + let since_the_epoch = start + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); + + let instance = PrometheusInstance::new().with_label("interface", interface); + if metric_attribute_options.handshake_timeout_seconds.is_some() { + let connected_endpoints: Vec<&&RemoteEndpoint> = remote_endpoints + .iter() + .filter(|&endpoint| { + since_the_epoch - endpoint.latest_handshake + < metric_attribute_options.handshake_timeout_seconds.unwrap() + }) + .collect(); + + let seen_recently = instance + .clone() + .with_label("seen_recently", "true") + .with_value(connected_endpoints.len()); + interface_metrics.connected_peers(&seen_recently); + + let not_seen_recently = instance + .clone() + .with_label("seen_recently", "false") + .with_value(remote_endpoints.len() - connected_endpoints.len()); + + interface_metrics.connected_peers(¬_seen_recently); + } else { + let set = instance.with_value(remote_endpoints.len()); + interface_metrics.connected_peers(&set); + } + } + + pub(self) fn populate_remote_endpoint_metrics<'a>( + &self, + pehm: Option<&PeerEntryHashMap>, + interface: &str, + endpoint: &'a Endpoint, + endpoint_metrics: &mut EndpointMetrics, + metric_attribute_options: &MetricAttributeOptions, + ) -> Option<&'a RemoteEndpoint> { + // only show remote endpoints + return if let Endpoint::Remote(ep) = endpoint { + debug!("WireGuard::render_with_names ep == {:?}", ep); + + // we store in attributes_owned the ownership of the values in order to + // 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![("interface", interface), ("public_key", &ep.public_key)]; + + if metric_attribute_options.split_allowed_ips { + let v_ip_and_subnet: Vec<(&str, &str)> = ep + .allowed_ips + .split(',') + .map(|ip_and_subnet| { debug!( - "WireGuard::render_with_names attributes == {:?}", - attributes + "WireGuard::render_with_names ip_and_subnet == {:?}", + ip_and_subnet ); - } else { - attributes.push(("allowed_ips", &ep.allowed_ips)); - } + let tokens: Vec<&str> = ip_and_subnet.split('/').collect(); + debug!("WireGuard::render_with_names tokens == {:?}", tokens); + let addr = tokens[0]; + let subnet = tokens[1]; + (addr, subnet) + }) + .collect(); + + for (idx, (ip, subnet)) in v_ip_and_subnet.iter().enumerate() { + attributes_owned.push((format!("allowed_ip_{}", idx), (*ip).to_string())); + attributes_owned + .push((format!("allowed_subnet_{}", idx), (*subnet).to_string())); + } + debug!( + "WireGuard::render_with_names attributes == {:?}", + attributes + ); + } else { + attributes.push(("allowed_ips", &ep.allowed_ips)); + } - // let's add the friendly_name attribute if present - // and has meaniningful value - if let Some(pehm) = pehm { - if let Some(ep_friendly_description) = pehm.get(&ep.public_key as &str) { - if let Some(friendly_description) = - &ep_friendly_description.friendly_description - { - match friendly_description { - FriendlyDescription::Name(name) => { - attributes.push(("friendly_name", name)); - } - FriendlyDescription::Json(json) => { - // let's put them in a intermediate vector and then sort it - let mut v_temp = Vec::new(); - - json.iter().for_each(|(header, value)| { - //attributes_owned - v_temp.push(( - header.to_string(), - match value { - serde_json::Value::Number(number) => { - number.to_string() - } - serde_json::Value::String(s) => s.to_owned(), - serde_json::Value::Bool(b) => b.to_string(), - _ => panic!("unsupported json value"), - }, - )); - }); - - v_temp.sort_by(|(k0, _), (k1, _)| k0.cmp(k1)); - - v_temp - .into_iter() - .for_each(|item| attributes_owned.push(item)); - } - } + // let's add the friendly_name attribute if present + // and has meaniningful value + if let Some(pehm) = pehm { + if let Some(ep_friendly_description) = pehm.get(&ep.public_key as &str) { + if let Some(friendly_description) = + &ep_friendly_description.friendly_description + { + match friendly_description { + FriendlyDescription::Name(name) => { + attributes.push(("friendly_name", name)); + } + FriendlyDescription::Json(json) => { + // let's put them in a intermediate vector and then sort it + let mut v_temp = Vec::new(); + + json.iter().for_each(|(header, value)| { + //attributes_owned + v_temp.push(( + header.to_string(), + match value { + serde_json::Value::Number(number) => number.to_string(), + serde_json::Value::String(s) => s.to_owned(), + serde_json::Value::Bool(b) => b.to_string(), + _ => panic!("unsupported json value"), + }, + )); + }); + + v_temp.sort_by(|(k0, _), (k1, _)| k0.cmp(k1)); + + v_temp + .into_iter() + .for_each(|item| attributes_owned.push(item)); } } } + } + } - if export_remote_ip_and_port { - if let Some(r_ip) = &ep.remote_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())); - } - } - - for (label, val) in &attributes_owned { - attributes.push((label, val)); - } - - let mut instance = PrometheusInstance::new(); - for (h, v) in attributes { - instance = instance.with_label(h, v); - } - - pc_sent_bytes_total - .render_and_append_instance(&instance.clone().with_value(ep.sent_bytes)) - .render(); + if metric_attribute_options.export_remote_ip_and_port { + if let Some(r_ip) = &ep.remote_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())); + } + } - pc_received_bytes_total - .render_and_append_instance(&instance.clone().with_value(ep.received_bytes)) - .render(); + for (label, val) in &attributes_owned { + attributes.push((label, val)); + } - pc_latest_handshake.render_and_append_instance( - &instance.with_value(ep.latest_handshake.into()), - ); - } + let mut instance = PrometheusInstance::new(); + for (h, v) in attributes { + instance = instance.with_label(h, v); } - } - format!( - "{}\n{}\n{}", - pc_sent_bytes_total.render(), - pc_received_bytes_total.render(), - pc_latest_handshake.render() - ) + endpoint_metrics.sent_bytes_total(&instance, ep.sent_bytes); + endpoint_metrics.received_bytes_total(&instance, ep.received_bytes); + endpoint_metrics.latest_handshake(&instance, ep.latest_handshake.into()); + + Some(ep) + } else { + None + }; } } @@ -399,7 +449,12 @@ 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 metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: true, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; + let s = a.render_with_names(Some(&pe), &metric_attribute_options); println!("{}", s); let s_ok = "# HELP wireguard_sent_bytes_total Bytes sent to the peer @@ -461,6 +516,10 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"yZOoC2t6pBcXvo wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"yjeBkrZqUThSSHySFzWCjxAH8cxtiWSI2I8JFD6t1UM=\",remote_ip=\"10.211.123.126\",allowed_ip_0=\"10.90.0.5\",allowed_subnet_0=\"32\",remote_port=\"51820\"} 1574770705 wireguard_latest_handshake_seconds{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\"} 1574770783 wireguard_latest_handshake_seconds{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\"} 1574770693 + +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"wg0\"} 17 "; assert_eq!(s, s_ok); } @@ -489,13 +548,33 @@ 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 metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: false, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; + let s = a.render_with_names(None, &metric_attribute_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 +# TYPE wireguard_sent_bytes_total counter +wireguard_sent_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 1000 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_received_bytes_total{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 5000 + +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_latest_handshake_seconds{interface=\"Pippo\",public_key=\"test\",allowed_ips=\"to_change\",remote_ip=\"remote_ip\",remote_port=\"100\"} 500 + +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"Pippo\"} 1 +"; let re = Endpoint::Remote(RemoteEndpoint { public_key: "test".to_owned(), @@ -515,22 +594,182 @@ wireguard_latest_handshake_seconds{interface=\"wg0\",public_key=\"sUsR6xufQQ8Tf0 v.push(re); wg.interfaces.insert("Pippo".to_owned(), v); - let prometheus = wg.render_with_names(None, false, true); + let metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: false, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; + let prometheus = wg.render_with_names(None, &metric_attribute_options); assert_eq!(prometheus, REF); } + use crate::wireguard_config::PeerEntry; + + #[test] + fn test_render_to_prometheus_with_handshake_timeout() { + use std::time::{SystemTime, UNIX_EPOCH}; + + let start = SystemTime::now(); + let since_the_epoch = start + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); + + let handshake_timeout = 30; + + let re1 = RemoteEndpoint { + public_key: "test".to_owned(), + remote_ip: Some("remote_ip".to_owned()), + remote_port: Some(100), + allowed_ips: "10.0.0.2/32,fd86:ea04:::4/128".to_owned(), + latest_handshake: since_the_epoch - handshake_timeout - 1, + sent_bytes: 1000, + received_bytes: 5000, + persistent_keepalive: false, + }; + let re2 = RemoteEndpoint { + public_key: "second_test".to_owned(), + remote_ip: Some("remote_ip".to_owned()), + remote_port: Some(100), + allowed_ips: "10.0.0.4/32,fd86:ea04:::4/128,192.168.0.0/16".to_owned(), + latest_handshake: since_the_epoch, + sent_bytes: 14, + received_bytes: 1_000_000_000, + persistent_keepalive: false, + }; + + let handshake_timeout_output = format!("# HELP wireguard_sent_bytes_total Bytes sent to the peer +# TYPE wireguard_sent_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_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\"}} {} +wireguard_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\"}} {} + +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{{interface=\"Pippo\",seen_recently=\"true\"}} 1 +wireguard_peers_total{{interface=\"Pippo\",seen_recently=\"false\"}} 1 +", re1.latest_handshake, re2.latest_handshake); + + let mut wg = WireGuard { + interfaces: HashMap::new(), + }; + + let mut v = Vec::new(); + v.push(Endpoint::Remote(re1)); + v.push(Endpoint::Remote(re2)); + wg.interfaces.insert("Pippo".to_owned(), v); + + let mut pehm = PeerEntryHashMap::new(); + let pe = PeerEntry { + public_key: "second_test", + allowed_ips: "ignored", + friendly_description: Some(FriendlyDescription::Name( + "this is my friendly name".into(), + )), + }; + pehm.insert(pe.public_key, pe.clone()); + { + let metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: false, + export_remote_ip_and_port: true, + handshake_timeout_seconds: Some(handshake_timeout), + }; + let prometheus = wg.render_with_names(Some(&pehm), &metric_attribute_options); + assert_eq!(prometheus, handshake_timeout_output); + } + } + #[test] 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 +# TYPE wireguard_sent_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_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 +wireguard_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 - 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"; +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"Pippo\"} 2 +"; + + const REF_SPLIT :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer +# TYPE wireguard_sent_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_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 +wireguard_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 - 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"; +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_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 +wireguard_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 - 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"; +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"Pippo\"} 2 +"; - 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_SPLIT_NO_REMOTE :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer +# TYPE wireguard_sent_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_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 +wireguard_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 + +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"Pippo\"} 2 +"; + + const REF_JSON :&'static str = "# HELP wireguard_sent_bytes_total Bytes sent to the peer +# TYPE wireguard_sent_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_received_bytes_total Bytes received from the peer +# TYPE wireguard_received_bytes_total counter +wireguard_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 +wireguard_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 + +# HELP wireguard_latest_handshake_seconds Seconds from the last handshake +# TYPE wireguard_latest_handshake_seconds gauge +wireguard_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 +wireguard_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 + +# HELP wireguard_peers_total Total number of peers +# TYPE wireguard_peers_total gauge +wireguard_peers_total{interface=\"Pippo\"} 2 +"; let re1 = Endpoint::Remote(RemoteEndpoint { public_key: "test".to_owned(), @@ -572,14 +811,36 @@ 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); - assert_eq!(prometheus, REF); + { + let metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: false, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; - let prometheus = wg.render_with_names(Some(&pehm), true, true); - assert_eq!(prometheus, REF_SPLIT); + let prometheus = wg.render_with_names(Some(&pehm), &metric_attribute_options); + assert_eq!(prometheus, REF); + } - let prometheus = wg.render_with_names(Some(&pehm), true, false); - assert_eq!(prometheus, REF_SPLIT_NO_REMOTE); + { + let metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: true, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; + let prometheus = wg.render_with_names(Some(&pehm), &metric_attribute_options); + assert_eq!(prometheus, REF_SPLIT); + } + + { + let metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: true, + export_remote_ip_and_port: false, + handshake_timeout_seconds: None, + }; + let prometheus = wg.render_with_names(Some(&pehm), &metric_attribute_options); + assert_eq!(prometheus, REF_SPLIT_NO_REMOTE); + } // second test let mut pehm = PeerEntryHashMap::new(); @@ -606,7 +867,12 @@ 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 metric_attribute_options = MetricAttributeOptions { + split_allowed_ips: false, + export_remote_ip_and_port: true, + handshake_timeout_seconds: None, + }; + let prometheus = wg.render_with_names(Some(&pehm), &metric_attribute_options); assert_eq!(prometheus, REF_JSON); } } diff --git a/src/wireguard_config.rs b/src/wireguard_config.rs index a140b2a..624f1df 100644 --- a/src/wireguard_config.rs +++ b/src/wireguard_config.rs @@ -28,7 +28,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 } @@ -146,7 +146,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); }