+//! Datastote status
+
use proxmox::list_subdirs_api_method;
use anyhow::{Error};
SubdirMap,
};
-use crate::api2::types::{
- DATASTORE_SCHEMA,
- RRDMode,
- RRDTimeFrameResolution,
- TaskListItem,
- Userid,
+use pbs_api_types::{
+ Authid, DATASTORE_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
};
+use proxmox_rrd::{RRDMode, RRDTimeFrameResolution};
+
+use pbs_datastore::DataStore;
+use pbs_config::CachedUserInfo;
-use crate::server;
-use crate::backup::{DataStore};
-use crate::config::datastore;
-use crate::tools::epoch_now_f64;
use crate::tools::statistics::{linear_regression};
-use crate::config::cached_user_info::CachedUserInfo;
-use crate::config::acl::{
- PRIV_SYS_AUDIT,
- PRIV_DATASTORE_AUDIT,
- PRIV_DATASTORE_BACKUP,
-};
+use crate::RRD_CACHE;
#[api(
returns: {
},
history: {
type: Array,
+ optional: true,
description: "A list of usages of the past (last Month).",
items: {
type: Number,
of RRD data of the last Month. Missing if there are not enough data points yet.\
If the estimate lies in the past, the usage is decreasing.",
},
+ "error": {
+ type: String,
+ optional: true,
+ description: "An error description, for example, when the datastore could not be looked up.",
+ },
},
},
},
+ access: {
+ permission: &Permission::Anybody,
+ },
)]
/// List Datastore usages and estimates
-fn datastore_status(
+pub fn datastore_status(
_param: Value,
_info: &ApiMethod,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
- let (config, _digest) = datastore::config()?;
+ let (config, _digest) = pbs_config::datastore::config()?;
- let userid: Userid = rpcenv.get_user().unwrap().parse()?;
+ let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
let user_info = CachedUserInfo::new()?;
let mut list = Vec::new();
for (store, (_, _)) in &config.sections {
- let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
+ let user_privs = user_info.lookup_privs(&auth_id, &["datastore", &store]);
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT| PRIV_DATASTORE_BACKUP)) != 0;
if !allowed {
continue;
}
- let datastore = DataStore::lookup_datastore(&store)?;
+ let datastore = match DataStore::lookup_datastore(&store) {
+ Ok(datastore) => datastore,
+ Err(err) => {
+ list.push(json!({
+ "store": store,
+ "total": -1,
+ "used": -1,
+ "avail": -1,
+ "error": err.to_string()
+ }));
+ continue;
+ }
+ };
let status = crate::tools::disks::disk_usage(&datastore.base_path())?;
let mut entry = json!({
"total": status.total,
"used": status.used,
"avail": status.avail,
+ "gc-status": datastore.last_gc_status(),
});
let rrd_dir = format!("datastore/{}", store);
- let now = epoch_now_f64()?;
- let rrd_resolution = RRDTimeFrameResolution::Month;
- let rrd_mode = RRDMode::Average;
+ let now = proxmox::tools::time::epoch_f64();
- let total_res = crate::rrd::extract_cached_data(
+ let get_rrd = |what: &str| RRD_CACHE.extract_cached_data(
&rrd_dir,
- "total",
+ what,
now,
- rrd_resolution,
- rrd_mode,
+ RRDTimeFrameResolution::Month,
+ RRDMode::Average,
);
- let used_res = crate::rrd::extract_cached_data(
- &rrd_dir,
- "used",
- now,
- rrd_resolution,
- rrd_mode,
- );
-
- match (total_res, used_res) {
- (Some((start, reso, total_list)), Some((_, _, used_list))) => {
- let mut usage_list: Vec<f64> = Vec::new();
- let mut time_list: Vec<u64> = Vec::new();
- let mut history = Vec::new();
-
- for (idx, used) in used_list.iter().enumerate() {
- let total = if idx < total_list.len() {
- total_list[idx]
- } else {
- None
- };
-
- match (total, used) {
- (Some(total), Some(used)) if total != 0.0 => {
- time_list.push(start + (idx as u64)*reso);
- let usage = used/total;
- usage_list.push(usage);
- history.push(json!(usage));
- },
- _ => {
- history.push(json!(null))
- }
+ let total_res = get_rrd("total");
+ let used_res = get_rrd("used");
+
+ if let (Some((start, reso, total_list)), Some((_, _, used_list))) = (total_res, used_res) {
+ let mut usage_list: Vec<f64> = Vec::new();
+ let mut time_list: Vec<u64> = Vec::new();
+ let mut history = Vec::new();
+
+ for (idx, used) in used_list.iter().enumerate() {
+ let total = if idx < total_list.len() {
+ total_list[idx]
+ } else {
+ None
+ };
+
+ match (total, used) {
+ (Some(total), Some(used)) if total != 0.0 => {
+ time_list.push(start + (idx as u64)*reso);
+ let usage = used/total;
+ usage_list.push(usage);
+ history.push(json!(usage));
+ },
+ _ => {
+ history.push(json!(null))
}
}
-
- entry["history"] = history.into();
-
- // we skip the calculation for datastores with not enough data
- if usage_list.len() >= 7 {
- if let Some((a,b)) = linear_regression(&time_list, &usage_list) {
- if b != 0.0 {
- let estimate = (1.0 - a) / b;
- entry["estimated-full-date"] = Value::from(estimate.floor() as u64);
- } else {
- entry["estimated-full-date"] = Value::from(0);
- }
- }
- }
- },
- _ => {},
+ }
+
+ entry["history-start"] = start.into();
+ entry["history-delta"] = reso.into();
+ entry["history"] = history.into();
+
+ // we skip the calculation for datastores with not enough data
+ if usage_list.len() >= 7 {
+ entry["estimated-full-date"] = match linear_regression(&time_list, &usage_list) {
+ Some((a, b)) if b != 0.0 => Value::from(((1.0 - a) / b).floor() as u64),
+ _ => Value::from(0),
+ };
+ }
}
list.push(entry);
Ok(list.into())
}
-#[api(
- input: {
- properties: {
- since: {
- type: u64,
- description: "Only list tasks since this UNIX epoch.",
- optional: true,
- },
- },
- },
- returns: {
- description: "A list of tasks.",
- type: Array,
- items: { type: TaskListItem },
- },
- access: {
- description: "Users can only see there own tasks, unless the have Sys.Audit on /system/tasks.",
- permission: &Permission::Anybody,
- },
-)]
-/// List tasks.
-pub fn list_tasks(
- _param: Value,
- rpcenv: &mut dyn RpcEnvironment,
-) -> Result<Vec<TaskListItem>, Error> {
-
- let userid: Userid = rpcenv.get_user().unwrap().parse()?;
- let user_info = CachedUserInfo::new()?;
- let user_privs = user_info.lookup_privs(&userid, &["system", "tasks"]);
-
- let list_all = (user_privs & PRIV_SYS_AUDIT) != 0;
-
- // TODO: replace with call that gets all task since 'since' epoch
- let list: Vec<TaskListItem> = server::read_task_list()?
- .into_iter()
- .map(TaskListItem::from)
- .filter(|entry| list_all || entry.user == userid)
- .collect();
-
- Ok(list.into())
-}
-
const SUBDIRS: SubdirMap = &[
("datastore-usage", &Router::new().get(&API_METHOD_DATASTORE_STATUS)),
- ("tasks", &Router::new().get(&API_METHOD_LIST_TASKS)),
];
pub const ROUTER: Router = Router::new()