burp: Add client/backup info retrieval methods
The `get_clients`, `get_client`, `get_backup`, `get_backup_log`, and `get_backup_stats` methods fetch information from the BURP server using its JSON stats interface. These will be used to populate the metrics we want to export to Prometheus.
This commit is contained in:
45
Cargo.lock
generated
45
Cargo.lock
generated
@@ -28,6 +28,8 @@ name = "burp_exporter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"openssl",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tracing",
|
||||
@@ -101,6 +103,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -297,6 +305,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.19"
|
||||
@@ -330,6 +344,37 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
|
||||
@@ -7,9 +7,14 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
openssl = "^0.10.38"
|
||||
serde_json = "1.0.78"
|
||||
tokio-native-tls = "^0.3.0"
|
||||
tracing = "^0.1.30"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "^1.0.136"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "^1.16.1"
|
||||
features = ["io-util", "macros", "net", "rt", "signal"]
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
|
||||
use serde_json;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_native_tls::native_tls::TlsConnector as NativeTlsConnector;
|
||||
@@ -14,6 +15,7 @@ use tokio_native_tls::TlsStream;
|
||||
use tracing::{debug, info, trace};
|
||||
|
||||
use super::error::Error;
|
||||
use super::model::{BackupInfo, BackupStats, ClientInfo, ClientList};
|
||||
|
||||
/// The BURP client version emulated by this implementation
|
||||
const CLIENT_VERSION: &str = "2.1.32";
|
||||
@@ -298,4 +300,148 @@ impl Client {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve information about all known clients
|
||||
///
|
||||
/// This method returns a list of clients known to the BURP server.
|
||||
/// Usually, a client can only retrieve information about itself;
|
||||
/// additional configuration is required in order for a client to
|
||||
/// view other clients' information. Specifically, the client must
|
||||
/// be named as a `restore_client` in the BURP server configuration
|
||||
/// AND it must have *at least* `client_can_list` set to `1` for at
|
||||
/// least one other client (or globally).
|
||||
pub async fn get_clients(&mut self) -> Result<ClientList, Error> {
|
||||
let res = self.command('c', "c:").await?;
|
||||
Ok(serde_json::from_str(&res)?)
|
||||
}
|
||||
|
||||
/// Retrieve information about a specific client
|
||||
///
|
||||
/// This method returns information about a specific client, if that
|
||||
/// client is known to the BURP server. The same caveat applies
|
||||
/// about client permissions as for [`get_clients`].
|
||||
pub async fn get_client<S: AsRef<str>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
) -> Result<ClientInfo, Error> {
|
||||
let res = self.command('c', &format!("c:{}", name.as_ref())).await?;
|
||||
let mut clientlist: ClientList = serde_json::from_str(&res)?;
|
||||
match clientlist.clients.pop() {
|
||||
Some(c) => Ok(c),
|
||||
None => Err(Error::Protocol(
|
||||
"Invalid response from server: no client listed".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve information about a client backup
|
||||
///
|
||||
/// This method returns details about a specific backup for a
|
||||
/// particular client.
|
||||
///
|
||||
/// * `name`: The client name
|
||||
/// * `number`: The backup number
|
||||
pub async fn get_backup<S: AsRef<str>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
number: u64,
|
||||
) -> Result<BackupInfo, Error> {
|
||||
let res = self
|
||||
.command('c', &format!("c:{}:b:{}", name.as_ref(), number))
|
||||
.await?;
|
||||
let mut clientlist: ClientList = serde_json::from_str(&res)?;
|
||||
let mut client = match clientlist.clients.pop() {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(Error::Protocol(
|
||||
"Invalid response from server: no client listed".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
match client.backups.pop() {
|
||||
Some(b) => Ok(b),
|
||||
None => Err(Error::Protocol(
|
||||
"Invalid response from server: no backup listed".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the log for a client backup
|
||||
///
|
||||
/// This method returns the log for a specific backup for a
|
||||
/// particular client, as a string.
|
||||
///
|
||||
/// * `name`: The client name
|
||||
/// * `number`: The backup number
|
||||
pub async fn get_backup_log<S: AsRef<str>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
number: u64,
|
||||
) -> Result<Option<Vec<String>>, Error> {
|
||||
let res = self
|
||||
.command(
|
||||
'c',
|
||||
&format!("c:{}:b:{}:l:backup", name.as_ref(), number),
|
||||
)
|
||||
.await?;
|
||||
let mut clientlist: ClientList = serde_json::from_str(&res)?;
|
||||
let mut client = match clientlist.clients.pop() {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(Error::Protocol(
|
||||
"Invalid response from server: no client listed".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let backup = match client.backups.pop() {
|
||||
Some(b) => b,
|
||||
None => {
|
||||
return Err(Error::Protocol(
|
||||
"Invalid response from server: no backup listed".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(backup.logs.backup)
|
||||
}
|
||||
|
||||
/// Retrieve the statistics for a client backup
|
||||
///
|
||||
/// This method returns the statistics of a specific backup for a
|
||||
/// particular client.
|
||||
///
|
||||
/// * `name`: The client name
|
||||
/// * `number`: The backup number
|
||||
pub async fn get_backup_stats<S: AsRef<str>>(
|
||||
&mut self,
|
||||
name: S,
|
||||
number: u64,
|
||||
) -> Result<Option<BackupStats>, Error> {
|
||||
let res = self
|
||||
.command(
|
||||
'c',
|
||||
&format!("c:{}:b:{}:l:backup_stats", name.as_ref(), number),
|
||||
)
|
||||
.await?;
|
||||
let mut clientlist: ClientList = serde_json::from_str(&res)?;
|
||||
let mut client = match clientlist.clients.pop() {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(Error::Protocol(
|
||||
"Invalid response from server: no client listed".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let backup = match client.backups.pop() {
|
||||
Some(b) => b,
|
||||
None => {
|
||||
return Err(Error::Protocol(
|
||||
"Invalid response from server: no backup listed".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
match backup.logs.backup_stats {
|
||||
Some(lines) => Ok(Some(serde_json::from_str(&lines.join("\n"))?)),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Client error handling
|
||||
use std::io;
|
||||
|
||||
use serde_json;
|
||||
use tokio_native_tls::native_tls;
|
||||
|
||||
/// BURP client errors
|
||||
@@ -32,3 +34,9 @@ impl From<native_tls::Error> for Error {
|
||||
Self::Tls(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for Error {
|
||||
fn from(error: serde_json::Error) -> Self {
|
||||
Self::Protocol(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
#![warn(missing_docs)]
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
pub mod model;
|
||||
|
||||
51
src/burp/model.rs
Normal file
51
src/burp/model.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Logs {
|
||||
pub list: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub backup: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub backup_stats: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BackupInfo {
|
||||
pub number: u64,
|
||||
pub timestamp: u64,
|
||||
pub flags: Vec<String>,
|
||||
pub logs: Logs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ClientInfo {
|
||||
pub name: String,
|
||||
pub run_status: String,
|
||||
pub protocol: u64,
|
||||
pub backups: Vec<BackupInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ClientList {
|
||||
pub clients: Vec<ClientInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Counter {
|
||||
pub name: String,
|
||||
pub r#type: String,
|
||||
pub count: u64,
|
||||
#[serde(default)]
|
||||
pub changed: u64,
|
||||
#[serde(default)]
|
||||
pub same: u64,
|
||||
#[serde(default)]
|
||||
pub deleted: u64,
|
||||
#[serde(default)]
|
||||
pub scanned: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BackupStats {
|
||||
pub counters: Vec<Counter>,
|
||||
}
|
||||
Reference in New Issue
Block a user