2021-10-13 08:24:41 +00:00
|
|
|
use anyhow::{bail, Error};
|
2020-06-10 10:02:57 +00:00
|
|
|
use serde_json::{Value, json};
|
2021-10-13 08:24:41 +00:00
|
|
|
use std::collections::BTreeMap;
|
2020-05-23 09:10:02 +00:00
|
|
|
|
2021-10-08 09:19:37 +00:00
|
|
|
use proxmox_router::{Permission, Router};
|
|
|
|
use proxmox_schema::api;
|
2020-05-23 09:10:02 +00:00
|
|
|
|
2021-10-06 07:49:51 +00:00
|
|
|
use pbs_api_types::{
|
2021-10-13 08:24:44 +00:00
|
|
|
NODE_SCHEMA, RRDMode, RRDTimeFrame, PRIV_SYS_AUDIT,
|
2021-10-06 07:49:51 +00:00
|
|
|
};
|
|
|
|
|
2021-10-13 08:24:42 +00:00
|
|
|
use crate::extract_rrd_data;
|
2020-06-10 10:02:57 +00:00
|
|
|
|
|
|
|
pub fn create_value_from_rrd(
|
|
|
|
basedir: &str,
|
|
|
|
list: &[&str],
|
2021-10-13 08:24:44 +00:00
|
|
|
timeframe: RRDTimeFrame,
|
2021-10-13 08:24:42 +00:00
|
|
|
mode: RRDMode,
|
2020-06-10 10:02:57 +00:00
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
2021-10-13 08:24:41 +00:00
|
|
|
let mut result: Vec<Value> = Vec::new();
|
2021-10-13 08:24:39 +00:00
|
|
|
|
2021-10-13 08:24:41 +00:00
|
|
|
let mut timemap = BTreeMap::new();
|
|
|
|
|
|
|
|
let mut last_resolution = None;
|
|
|
|
|
2020-06-10 10:02:57 +00:00
|
|
|
for name in list {
|
2021-10-13 08:24:42 +00:00
|
|
|
let (start, reso, data) = match extract_rrd_data(basedir, name, timeframe, mode)? {
|
2020-06-10 10:02:57 +00:00
|
|
|
Some(result) => result,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
|
2021-10-13 08:24:41 +00:00
|
|
|
if let Some(expected_resolution) = last_resolution {
|
|
|
|
if reso != expected_resolution {
|
|
|
|
bail!("got unexpected RRD resolution ({} != {})", reso, expected_resolution);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
last_resolution = Some(reso);
|
|
|
|
}
|
|
|
|
|
2020-06-10 10:02:57 +00:00
|
|
|
let mut t = start;
|
2021-10-13 08:24:41 +00:00
|
|
|
|
|
|
|
for index in 0..data.len() {
|
|
|
|
let entry = timemap.entry(t).or_insert(json!({ "time": t }));
|
|
|
|
if let Some(value) = data[index] {
|
|
|
|
entry[*name] = value.into();
|
2020-06-10 10:02:57 +00:00
|
|
|
}
|
|
|
|
t += reso;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-13 08:24:41 +00:00
|
|
|
for item in timemap.values() {
|
|
|
|
result.push(item.clone());
|
|
|
|
}
|
|
|
|
|
2020-06-10 10:02:57 +00:00
|
|
|
Ok(result.into())
|
|
|
|
}
|
2020-05-23 09:10:02 +00:00
|
|
|
|
|
|
|
#[api(
|
|
|
|
input: {
|
|
|
|
properties: {
|
|
|
|
node: {
|
|
|
|
schema: NODE_SCHEMA,
|
|
|
|
},
|
|
|
|
timeframe: {
|
2021-10-13 08:24:44 +00:00
|
|
|
type: RRDTimeFrame,
|
2020-05-23 09:10:02 +00:00
|
|
|
},
|
|
|
|
cf: {
|
|
|
|
type: RRDMode,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-09-16 09:51:12 +00:00
|
|
|
access: {
|
|
|
|
permission: &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false),
|
|
|
|
},
|
2020-05-23 09:10:02 +00:00
|
|
|
)]
|
2020-05-23 12:03:44 +00:00
|
|
|
/// Read node stats
|
|
|
|
fn get_node_stats(
|
2021-10-13 08:24:44 +00:00
|
|
|
timeframe: RRDTimeFrame,
|
2020-05-23 09:10:02 +00:00
|
|
|
cf: RRDMode,
|
|
|
|
_param: Value,
|
|
|
|
) -> Result<Value, Error> {
|
|
|
|
|
2020-06-10 10:02:57 +00:00
|
|
|
create_value_from_rrd(
|
2020-05-23 12:03:44 +00:00
|
|
|
"host",
|
2020-05-25 09:10:44 +00:00
|
|
|
&[
|
|
|
|
"cpu", "iowait",
|
|
|
|
"memtotal", "memused",
|
|
|
|
"swaptotal", "swapused",
|
|
|
|
"netin", "netout",
|
2020-05-25 09:49:30 +00:00
|
|
|
"loadavg",
|
2020-05-28 10:30:54 +00:00
|
|
|
"total", "used",
|
2020-05-28 17:11:37 +00:00
|
|
|
"read_ios", "read_bytes",
|
|
|
|
"write_ios", "write_bytes",
|
|
|
|
"io_ticks",
|
2020-05-28 10:30:54 +00:00
|
|
|
],
|
2020-05-23 12:03:44 +00:00
|
|
|
timeframe,
|
|
|
|
cf,
|
|
|
|
)
|
2020-05-23 09:10:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub const ROUTER: Router = Router::new()
|
2020-05-23 12:03:44 +00:00
|
|
|
.get(&API_METHOD_GET_NODE_STATS);
|