move RRD code into proxmox-rrd crate
This commit is contained in:
parent
20497c6346
commit
09340f28f5
|
@ -27,6 +27,7 @@ members = [
|
||||||
"pbs-fuse-loop",
|
"pbs-fuse-loop",
|
||||||
"pbs-runtime",
|
"pbs-runtime",
|
||||||
"proxmox-rest-server",
|
"proxmox-rest-server",
|
||||||
|
"proxmox-rrd",
|
||||||
"proxmox-systemd",
|
"proxmox-systemd",
|
||||||
"pbs-tape",
|
"pbs-tape",
|
||||||
"pbs-tools",
|
"pbs-tools",
|
||||||
|
@ -107,6 +108,7 @@ pbs-config = { path = "pbs-config" }
|
||||||
pbs-datastore = { path = "pbs-datastore" }
|
pbs-datastore = { path = "pbs-datastore" }
|
||||||
pbs-runtime = { path = "pbs-runtime" }
|
pbs-runtime = { path = "pbs-runtime" }
|
||||||
proxmox-rest-server = { path = "proxmox-rest-server" }
|
proxmox-rest-server = { path = "proxmox-rest-server" }
|
||||||
|
proxmox-rrd = { path = "proxmox-rrd" }
|
||||||
proxmox-systemd = { path = "proxmox-systemd" }
|
proxmox-systemd = { path = "proxmox-systemd" }
|
||||||
pbs-tools = { path = "pbs-tools" }
|
pbs-tools = { path = "pbs-tools" }
|
||||||
pbs-tape = { path = "pbs-tape" }
|
pbs-tape = { path = "pbs-tape" }
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -40,6 +40,7 @@ SUBCRATES := \
|
||||||
pbs-fuse-loop \
|
pbs-fuse-loop \
|
||||||
pbs-runtime \
|
pbs-runtime \
|
||||||
proxmox-rest-server \
|
proxmox-rest-server \
|
||||||
|
proxmox-rrd \
|
||||||
proxmox-systemd \
|
proxmox-systemd \
|
||||||
pbs-tape \
|
pbs-tape \
|
||||||
pbs-tools \
|
pbs-tools \
|
||||||
|
|
|
@ -358,33 +358,6 @@ pub struct APTUpdateInfo {
|
||||||
pub extra_info: Option<String>,
|
pub extra_info: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
|
||||||
pub enum RRDMode {
|
|
||||||
/// Maximum
|
|
||||||
Max,
|
|
||||||
/// Average
|
|
||||||
Average,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[api()]
|
|
||||||
#[repr(u64)]
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum RRDTimeFrameResolution {
|
|
||||||
/// 1 min => last 70 minutes
|
|
||||||
Hour = 60,
|
|
||||||
/// 30 min => last 35 hours
|
|
||||||
Day = 60*30,
|
|
||||||
/// 3 hours => about 8 days
|
|
||||||
Week = 60*180,
|
|
||||||
/// 12 hours => last 35 days
|
|
||||||
Month = 60*720,
|
|
||||||
/// 1 week => last 490 days
|
|
||||||
Year = 60*10080,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[api()]
|
#[api()]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "proxmox-rrd"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Dietmar Maurer <dietmar@proxmox.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "Simple RRD database implementation."
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
bitflags = "1.2.1"
|
||||||
|
serde = { version = "1.0", features = [] }
|
||||||
|
|
||||||
|
proxmox = { version = "0.13.5", features = ["api-macro"] }
|
|
@ -0,0 +1,111 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{RwLock};
|
||||||
|
|
||||||
|
use anyhow::{format_err, Error};
|
||||||
|
|
||||||
|
use proxmox::tools::fs::{create_path, CreateOptions};
|
||||||
|
|
||||||
|
use crate::{RRDMode, RRDTimeFrameResolution};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// RRD cache - keep RRD data in RAM, but write updates to disk
|
||||||
|
///
|
||||||
|
/// This cache is designed to run as single instance (no concurrent
|
||||||
|
/// access from other processes).
|
||||||
|
pub struct RRDCache {
|
||||||
|
basedir: PathBuf,
|
||||||
|
file_options: CreateOptions,
|
||||||
|
dir_options: CreateOptions,
|
||||||
|
cache: RwLock<HashMap<String, RRD>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RRDCache {
|
||||||
|
|
||||||
|
/// Creates a new instance
|
||||||
|
pub fn new<P: AsRef<Path>>(
|
||||||
|
basedir: P,
|
||||||
|
file_options: Option<CreateOptions>,
|
||||||
|
dir_options: Option<CreateOptions>,
|
||||||
|
) -> Self {
|
||||||
|
let basedir = basedir.as_ref().to_owned();
|
||||||
|
Self {
|
||||||
|
basedir,
|
||||||
|
file_options: file_options.unwrap_or_else(|| CreateOptions::new()),
|
||||||
|
dir_options: dir_options.unwrap_or_else(|| CreateOptions::new()),
|
||||||
|
cache: RwLock::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RRDCache {
|
||||||
|
|
||||||
|
/// Create rrdd stat dir with correct permission
|
||||||
|
pub fn create_rrdb_dir(&self) -> Result<(), Error> {
|
||||||
|
|
||||||
|
create_path(&self.basedir, Some(self.dir_options.clone()), Some(self.file_options.clone()))
|
||||||
|
.map_err(|err: Error| format_err!("unable to create rrdb stat dir - {}", err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update data in RAM and write file back to disk (if `save` is set)
|
||||||
|
pub fn update_value(
|
||||||
|
&self,
|
||||||
|
rel_path: &str,
|
||||||
|
value: f64,
|
||||||
|
dst: DST,
|
||||||
|
save: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mut path = self.basedir.clone();
|
||||||
|
path.push(rel_path);
|
||||||
|
|
||||||
|
std::fs::create_dir_all(path.parent().unwrap())?; // fixme??
|
||||||
|
|
||||||
|
let mut map = self.cache.write().unwrap();
|
||||||
|
let now = proxmox::tools::time::epoch_f64();
|
||||||
|
|
||||||
|
if let Some(rrd) = map.get_mut(rel_path) {
|
||||||
|
rrd.update(now, value);
|
||||||
|
if save { rrd.save(&path, self.file_options.clone())?; }
|
||||||
|
} else {
|
||||||
|
let mut rrd = match RRD::load(&path) {
|
||||||
|
Ok(rrd) => rrd,
|
||||||
|
Err(err) => {
|
||||||
|
if err.kind() != std::io::ErrorKind::NotFound {
|
||||||
|
eprintln!("overwriting RRD file {:?}, because of load error: {}", path, err);
|
||||||
|
}
|
||||||
|
RRD::new(dst)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
rrd.update(now, value);
|
||||||
|
if save {
|
||||||
|
rrd.save(&path, self.file_options.clone())?;
|
||||||
|
}
|
||||||
|
map.insert(rel_path.into(), rrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract data from cached RRD
|
||||||
|
pub fn extract_cached_data(
|
||||||
|
&self,
|
||||||
|
base: &str,
|
||||||
|
name: &str,
|
||||||
|
now: f64,
|
||||||
|
timeframe: RRDTimeFrameResolution,
|
||||||
|
mode: RRDMode,
|
||||||
|
) -> Option<(u64, u64, Vec<Option<f64>>)> {
|
||||||
|
|
||||||
|
let map = self.cache.read().unwrap();
|
||||||
|
|
||||||
|
match map.get(&format!("{}/{}", base, name)) {
|
||||||
|
Some(rrd) => Some(rrd.extract_data(now, timeframe, mode)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
mod rrd;
|
||||||
|
pub use rrd::*;
|
||||||
|
|
||||||
|
mod cache;
|
||||||
|
pub use cache::*;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use proxmox::api::api;
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
/// RRD consolidation mode
|
||||||
|
pub enum RRDMode {
|
||||||
|
/// Maximum
|
||||||
|
Max,
|
||||||
|
/// Average
|
||||||
|
Average,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[api()]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
/// RRD time frame resolution
|
||||||
|
pub enum RRDTimeFrameResolution {
|
||||||
|
/// 1 min => last 70 minutes
|
||||||
|
Hour = 60,
|
||||||
|
/// 30 min => last 35 hours
|
||||||
|
Day = 60*30,
|
||||||
|
/// 3 hours => about 8 days
|
||||||
|
Week = 60*180,
|
||||||
|
/// 12 hours => last 35 days
|
||||||
|
Month = 60*720,
|
||||||
|
/// 1 week => last 490 days
|
||||||
|
Year = 60*10080,
|
||||||
|
}
|
|
@ -3,17 +3,21 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
use pbs_api_types::{RRDMode, RRDTimeFrameResolution};
|
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
||||||
|
|
||||||
|
use crate::{RRDMode, RRDTimeFrameResolution};
|
||||||
|
|
||||||
|
/// The number of data entries per RRA
|
||||||
pub const RRD_DATA_ENTRIES: usize = 70;
|
pub const RRD_DATA_ENTRIES: usize = 70;
|
||||||
|
|
||||||
|
/// Proxmox RRD file magic number
|
||||||
// openssl::sha::sha256(b"Proxmox Round Robin Database file v1.0")[0..8];
|
// openssl::sha::sha256(b"Proxmox Round Robin Database file v1.0")[0..8];
|
||||||
pub const PROXMOX_RRD_MAGIC_1_0: [u8; 8] = [206, 46, 26, 212, 172, 158, 5, 186];
|
pub const PROXMOX_RRD_MAGIC_1_0: [u8; 8] = [206, 46, 26, 212, 172, 158, 5, 186];
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
bitflags!{
|
bitflags!{
|
||||||
pub struct RRAFlags: u64 {
|
struct RRAFlags: u64 {
|
||||||
// Data Source Types
|
// Data Source Types
|
||||||
const DST_GAUGE = 1;
|
const DST_GAUGE = 1;
|
||||||
const DST_DERIVE = 2;
|
const DST_DERIVE = 2;
|
||||||
|
@ -27,6 +31,7 @@ bitflags!{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RRD data source tyoe
|
||||||
pub enum DST {
|
pub enum DST {
|
||||||
Gauge,
|
Gauge,
|
||||||
Derive,
|
Derive,
|
||||||
|
@ -227,6 +232,7 @@ impl RRD {
|
||||||
timeframe: RRDTimeFrameResolution,
|
timeframe: RRDTimeFrameResolution,
|
||||||
mode: RRDMode,
|
mode: RRDMode,
|
||||||
) -> (u64, u64, Vec<Option<f64>>) {
|
) -> (u64, u64, Vec<Option<f64>>) {
|
||||||
|
|
||||||
let epoch = time as u64;
|
let epoch = time as u64;
|
||||||
let reso = timeframe as u64;
|
let reso = timeframe as u64;
|
||||||
|
|
||||||
|
@ -296,25 +302,11 @@ impl RRD {
|
||||||
Self::from_raw(&raw)
|
Self::from_raw(&raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self, filename: &Path) -> Result<(), Error> {
|
pub fn save(&self, filename: &Path, options: CreateOptions) -> Result<(), Error> {
|
||||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
|
||||||
|
|
||||||
let rrd_slice = unsafe {
|
let rrd_slice = unsafe {
|
||||||
std::slice::from_raw_parts(self as *const _ as *const u8, std::mem::size_of::<RRD>())
|
std::slice::from_raw_parts(self as *const _ as *const u8, std::mem::size_of::<RRD>())
|
||||||
};
|
};
|
||||||
|
replace_file(filename, rrd_slice, options)
|
||||||
let backup_user = pbs_config::backup_user()?;
|
|
||||||
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0644);
|
|
||||||
// set the correct owner/group/permissions while saving file
|
|
||||||
// owner(rw) = backup, group(r)= backup
|
|
||||||
let options = CreateOptions::new()
|
|
||||||
.perm(mode)
|
|
||||||
.owner(backup_user.uid)
|
|
||||||
.group(backup_user.gid);
|
|
||||||
|
|
||||||
replace_file(filename, rrd_slice, options)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,11 @@ use proxmox::{http_err, identity, list_subdirs_api_method, sortable};
|
||||||
use pxar::accessor::aio::Accessor;
|
use pxar::accessor::aio::Accessor;
|
||||||
use pxar::EntryKind;
|
use pxar::EntryKind;
|
||||||
|
|
||||||
|
use proxmox_rrd::{RRDMode, RRDTimeFrameResolution};
|
||||||
use pbs_api_types::{ Authid, BackupContent, Counts, CryptMode,
|
use pbs_api_types::{ Authid, BackupContent, Counts, CryptMode,
|
||||||
DataStoreListItem, GarbageCollectionStatus, GroupListItem,
|
DataStoreListItem, GarbageCollectionStatus, GroupListItem,
|
||||||
SnapshotListItem, SnapshotVerifyState, PruneOptions,
|
SnapshotListItem, SnapshotVerifyState, PruneOptions,
|
||||||
DataStoreStatus, RRDMode, RRDTimeFrameResolution,
|
DataStoreStatus,
|
||||||
BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA,
|
BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_TIME_SCHEMA,
|
||||||
BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
BACKUP_TYPE_SCHEMA, DATASTORE_SCHEMA,
|
||||||
IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA,
|
IGNORE_VERIFIED_BACKUPS_SCHEMA, UPID_SCHEMA,
|
||||||
|
|
|
@ -3,9 +3,10 @@ use serde_json::{Value, json};
|
||||||
|
|
||||||
use proxmox::api::{api, Permission, Router};
|
use proxmox::api::{api, Permission, Router};
|
||||||
|
|
||||||
use pbs_api_types::{RRDMode, RRDTimeFrameResolution, NODE_SCHEMA, PRIV_SYS_AUDIT};
|
use pbs_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT};
|
||||||
|
use proxmox_rrd::{RRDMode, RRDTimeFrameResolution, RRD_DATA_ENTRIES};
|
||||||
|
|
||||||
use crate::rrd::{extract_cached_data, RRD_DATA_ENTRIES};
|
use crate::RRD_CACHE;
|
||||||
|
|
||||||
pub fn create_value_from_rrd(
|
pub fn create_value_from_rrd(
|
||||||
basedir: &str,
|
basedir: &str,
|
||||||
|
@ -18,7 +19,7 @@ pub fn create_value_from_rrd(
|
||||||
let now = proxmox::tools::time::epoch_f64();
|
let now = proxmox::tools::time::epoch_f64();
|
||||||
|
|
||||||
for name in list {
|
for name in list {
|
||||||
let (start, reso, list) = match extract_cached_data(basedir, name, now, timeframe, cf) {
|
let (start, reso, list) = match RRD_CACHE.extract_cached_data(basedir, name, now, timeframe, cf) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,13 +15,15 @@ use proxmox::api::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
DATASTORE_SCHEMA, RRDMode, RRDTimeFrameResolution, Authid,
|
Authid, DATASTORE_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
|
||||||
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
|
|
||||||
};
|
};
|
||||||
|
use proxmox_rrd::{RRDMode, RRDTimeFrameResolution};
|
||||||
|
|
||||||
use pbs_datastore::DataStore;
|
use pbs_datastore::DataStore;
|
||||||
use pbs_config::CachedUserInfo;
|
use pbs_config::CachedUserInfo;
|
||||||
|
|
||||||
use crate::tools::statistics::{linear_regression};
|
use crate::tools::statistics::{linear_regression};
|
||||||
|
use crate::RRD_CACHE;
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
returns: {
|
returns: {
|
||||||
|
@ -122,7 +124,7 @@ pub fn datastore_status(
|
||||||
let rrd_dir = format!("datastore/{}", store);
|
let rrd_dir = format!("datastore/{}", store);
|
||||||
let now = proxmox::tools::time::epoch_f64();
|
let now = proxmox::tools::time::epoch_f64();
|
||||||
|
|
||||||
let get_rrd = |what: &str| crate::rrd::extract_cached_data(
|
let get_rrd = |what: &str| RRD_CACHE.extract_cached_data(
|
||||||
&rrd_dir,
|
&rrd_dir,
|
||||||
what,
|
what,
|
||||||
now,
|
now,
|
||||||
|
|
|
@ -17,6 +17,7 @@ use proxmox_rest_server::{daemon, AuthError, ApiConfig, RestServer, RestEnvironm
|
||||||
|
|
||||||
use proxmox_backup::server::auth::check_pbs_auth;
|
use proxmox_backup::server::auth::check_pbs_auth;
|
||||||
use proxmox_backup::auth_helpers::*;
|
use proxmox_backup::auth_helpers::*;
|
||||||
|
use proxmox_backup::RRD_CACHE;
|
||||||
use proxmox_backup::config;
|
use proxmox_backup::config;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -74,7 +75,8 @@ async fn run() -> Result<(), Error> {
|
||||||
|
|
||||||
proxmox_backup::server::create_run_dir()?;
|
proxmox_backup::server::create_run_dir()?;
|
||||||
|
|
||||||
proxmox_backup::rrd::create_rrdb_dir()?;
|
RRD_CACHE.create_rrdb_dir()?;
|
||||||
|
|
||||||
proxmox_backup::server::jobstate::create_jobstate_dir()?;
|
proxmox_backup::server::jobstate::create_jobstate_dir()?;
|
||||||
proxmox_backup::tape::create_tape_status_dir()?;
|
proxmox_backup::tape::create_tape_status_dir()?;
|
||||||
proxmox_backup::tape::create_drive_state_dir()?;
|
proxmox_backup::tape::create_drive_state_dir()?;
|
||||||
|
|
|
@ -24,12 +24,15 @@ use proxmox::tools::fs::CreateOptions;
|
||||||
|
|
||||||
use pbs_tools::task_log;
|
use pbs_tools::task_log;
|
||||||
use pbs_datastore::DataStore;
|
use pbs_datastore::DataStore;
|
||||||
|
use proxmox_rrd::DST;
|
||||||
|
|
||||||
use proxmox_rest_server::{
|
use proxmox_rest_server::{
|
||||||
rotate_task_log_archive, extract_cookie , AuthError, ApiConfig, RestServer, RestEnvironment,
|
rotate_task_log_archive, extract_cookie , AuthError, ApiConfig, RestServer, RestEnvironment,
|
||||||
ServerAdapter, WorkerTask,
|
ServerAdapter, WorkerTask,
|
||||||
};
|
};
|
||||||
|
|
||||||
use proxmox_backup::{
|
use proxmox_backup::{
|
||||||
|
RRD_CACHE,
|
||||||
server::{
|
server::{
|
||||||
auth::check_pbs_auth,
|
auth::check_pbs_auth,
|
||||||
jobstate::{
|
jobstate::{
|
||||||
|
@ -895,15 +898,13 @@ async fn run_stat_generator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rrd_update_gauge(name: &str, value: f64, save: bool) {
|
fn rrd_update_gauge(name: &str, value: f64, save: bool) {
|
||||||
use proxmox_backup::rrd;
|
if let Err(err) = RRD_CACHE.update_value(name, value, DST::Gauge, save) {
|
||||||
if let Err(err) = rrd::update_value(name, value, rrd::DST::Gauge, save) {
|
|
||||||
eprintln!("rrd::update_value '{}' failed - {}", name, err);
|
eprintln!("rrd::update_value '{}' failed - {}", name, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rrd_update_derive(name: &str, value: f64, save: bool) {
|
fn rrd_update_derive(name: &str, value: f64, save: bool) {
|
||||||
use proxmox_backup::rrd;
|
if let Err(err) = RRD_CACHE.update_value(name, value, DST::Derive, save) {
|
||||||
if let Err(err) = rrd::update_value(name, value, rrd::DST::Derive, save) {
|
|
||||||
eprintln!("rrd::update_value '{}' failed - {}", name, err);
|
eprintln!("rrd::update_value '{}' failed - {}", name, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
src/lib.rs
25
src/lib.rs
|
@ -5,8 +5,11 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use proxmox::tools::fs::CreateOptions;
|
||||||
|
|
||||||
use pbs_buildcfg::configdir;
|
use pbs_buildcfg::configdir;
|
||||||
use pbs_tools::cert::CertInfo;
|
use pbs_tools::cert::CertInfo;
|
||||||
|
use proxmox_rrd::RRDCache;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod tools;
|
pub mod tools;
|
||||||
|
@ -25,8 +28,6 @@ pub mod auth_helpers;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
|
||||||
pub mod rrd;
|
|
||||||
|
|
||||||
pub mod tape;
|
pub mod tape;
|
||||||
|
|
||||||
pub mod acme;
|
pub mod acme;
|
||||||
|
@ -37,3 +38,23 @@ pub mod client_helpers;
|
||||||
pub fn cert_info() -> Result<CertInfo, anyhow::Error> {
|
pub fn cert_info() -> Result<CertInfo, anyhow::Error> {
|
||||||
CertInfo::from_path(PathBuf::from(configdir!("/proxy.pem")))
|
CertInfo::from_path(PathBuf::from(configdir!("/proxy.pem")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static!{
|
||||||
|
/// Proxmox Backup Server RRD cache instance
|
||||||
|
pub static ref RRD_CACHE: RRDCache = {
|
||||||
|
let backup_user = pbs_config::backup_user().unwrap();
|
||||||
|
let file_options = CreateOptions::new()
|
||||||
|
.owner(backup_user.uid)
|
||||||
|
.group(backup_user.gid);
|
||||||
|
|
||||||
|
let dir_options = CreateOptions::new()
|
||||||
|
.owner(backup_user.uid)
|
||||||
|
.group(backup_user.gid);
|
||||||
|
|
||||||
|
RRDCache::new(
|
||||||
|
"/var/lib/proxmox-backup/rrdb",
|
||||||
|
Some(file_options),
|
||||||
|
Some(dir_options),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{RwLock};
|
|
||||||
|
|
||||||
use anyhow::{format_err, Error};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
|
||||||
|
|
||||||
use pbs_api_types::{RRDMode, RRDTimeFrameResolution};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const PBS_RRD_BASEDIR: &str = "/var/lib/proxmox-backup/rrdb";
|
|
||||||
|
|
||||||
lazy_static!{
|
|
||||||
static ref RRD_CACHE: RwLock<HashMap<String, RRD>> = {
|
|
||||||
RwLock::new(HashMap::new())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create rrdd stat dir with correct permission
|
|
||||||
pub fn create_rrdb_dir() -> Result<(), Error> {
|
|
||||||
|
|
||||||
let backup_user = pbs_config::backup_user()?;
|
|
||||||
let opts = CreateOptions::new()
|
|
||||||
.owner(backup_user.uid)
|
|
||||||
.group(backup_user.gid);
|
|
||||||
|
|
||||||
create_path(PBS_RRD_BASEDIR, None, Some(opts))
|
|
||||||
.map_err(|err: Error| format_err!("unable to create rrdb stat dir - {}", err))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_value(rel_path: &str, value: f64, dst: DST, save: bool) -> Result<(), Error> {
|
|
||||||
|
|
||||||
let mut path = PathBuf::from(PBS_RRD_BASEDIR);
|
|
||||||
path.push(rel_path);
|
|
||||||
|
|
||||||
std::fs::create_dir_all(path.parent().unwrap())?;
|
|
||||||
|
|
||||||
let mut map = RRD_CACHE.write().unwrap();
|
|
||||||
let now = proxmox::tools::time::epoch_f64();
|
|
||||||
|
|
||||||
if let Some(rrd) = map.get_mut(rel_path) {
|
|
||||||
rrd.update(now, value);
|
|
||||||
if save { rrd.save(&path)?; }
|
|
||||||
} else {
|
|
||||||
let mut rrd = match RRD::load(&path) {
|
|
||||||
Ok(rrd) => rrd,
|
|
||||||
Err(err) => {
|
|
||||||
if err.kind() != std::io::ErrorKind::NotFound {
|
|
||||||
eprintln!("overwriting RRD file {:?}, because of load error: {}", path, err);
|
|
||||||
}
|
|
||||||
RRD::new(dst)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
rrd.update(now, value);
|
|
||||||
if save { rrd.save(&path)?; }
|
|
||||||
map.insert(rel_path.into(), rrd);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_cached_data(
|
|
||||||
base: &str,
|
|
||||||
name: &str,
|
|
||||||
now: f64,
|
|
||||||
timeframe: RRDTimeFrameResolution,
|
|
||||||
mode: RRDMode,
|
|
||||||
) -> Option<(u64, u64, Vec<Option<f64>>)> {
|
|
||||||
|
|
||||||
let map = RRD_CACHE.read().unwrap();
|
|
||||||
|
|
||||||
match map.get(&format!("{}/{}", base, name)) {
|
|
||||||
Some(rrd) => Some(rrd.extract_data(now, timeframe, mode)),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
#[allow(clippy::module_inception)]
|
|
||||||
mod rrd;
|
|
||||||
pub use rrd::*;
|
|
||||||
mod cache;
|
|
||||||
pub use cache::*;
|
|
Loading…
Reference in New Issue