3 use proxmox
::list_subdirs_api_method
;
6 use serde_json
::{json, Value}
;
18 DATASTORE_SCHEMA
, RRDMode
, RRDTimeFrameResolution
, Authid
,
19 PRIV_DATASTORE_AUDIT
, PRIV_DATASTORE_BACKUP
,
21 use pbs_datastore
::DataStore
;
22 use pbs_config
::CachedUserInfo
;
24 use crate::tools
::statistics
::{linear_regression}
;
28 description
: "Lists the Status of the Datastores.",
31 description
: "Status of a Datastore",
35 schema
: DATASTORE_SCHEMA
,
39 description
: "The Size of the underlying storage in bytes",
43 description
: "The used bytes of the underlying storage",
47 description
: "The available bytes of the underlying storage",
52 description
: "A list of usages of the past (last Month).",
55 description
: "The usage of a time in the past. Either null or between 0.0 and 1.0.",
58 "estimated-full-date": {
61 description
: "Estimation of the UNIX epoch when the storage will be full.\
62 This is calculated via a simple Linear Regression (Least Squares)\
63 of RRD data of the last Month. Missing if there are not enough data points yet.\
64 If the estimate lies in the past, the usage is decreasing.",
69 description
: "An error description, for example, when the datastore could not be looked up.",
75 permission
: &Permission
::Anybody
,
78 /// List Datastore usages and estimates
79 pub fn datastore_status(
82 rpcenv
: &mut dyn RpcEnvironment
,
83 ) -> Result
<Value
, Error
> {
85 let (config
, _digest
) = pbs_config
::datastore
::config()?
;
87 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
88 let user_info
= CachedUserInfo
::new()?
;
90 let mut list
= Vec
::new();
92 for (store
, (_
, _
)) in &config
.sections
{
93 let user_privs
= user_info
.lookup_privs(&auth_id
, &["datastore", &store
]);
94 let allowed
= (user_privs
& (PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_BACKUP
)) != 0;
99 let datastore
= match DataStore
::lookup_datastore(&store
) {
100 Ok(datastore
) => datastore
,
107 "error": err
.to_string()
112 let status
= crate::tools
::disks
::disk_usage(&datastore
.base_path())?
;
114 let mut entry
= json
!({
116 "total": status
.total
,
118 "avail": status
.avail
,
119 "gc-status": datastore
.last_gc_status(),
122 let rrd_dir
= format
!("datastore/{}", store
);
123 let now
= proxmox
::tools
::time
::epoch_f64();
125 let get_rrd
= |what
: &str| crate::rrd
::extract_cached_data(
129 RRDTimeFrameResolution
::Month
,
133 let total_res
= get_rrd("total");
134 let used_res
= get_rrd("used");
136 if let (Some((start
, reso
, total_list
)), Some((_
, _
, used_list
))) = (total_res
, used_res
) {
137 let mut usage_list
: Vec
<f64> = Vec
::new();
138 let mut time_list
: Vec
<u64> = Vec
::new();
139 let mut history
= Vec
::new();
141 for (idx
, used
) in used_list
.iter().enumerate() {
142 let total
= if idx
< total_list
.len() {
148 match (total
, used
) {
149 (Some(total
), Some(used
)) if total
!= 0.0 => {
150 time_list
.push(start
+ (idx
as u64)*reso
);
151 let usage
= used
/total
;
152 usage_list
.push(usage
);
153 history
.push(json
!(usage
));
156 history
.push(json
!(null
))
161 entry
["history-start"] = start
.into();
162 entry
["history-delta"] = reso
.into();
163 entry
["history"] = history
.into();
165 // we skip the calculation for datastores with not enough data
166 if usage_list
.len() >= 7 {
167 entry
["estimated-full-date"] = match linear_regression(&time_list
, &usage_list
) {
168 Some((a
, b
)) if b
!= 0.0 => Value
::from(((1.0 - a
) / b
).floor() as u64),
180 const SUBDIRS
: SubdirMap
= &[
181 ("datastore-usage", &Router
::new().get(&API_METHOD_DATASTORE_STATUS
)),
184 pub const ROUTER
: Router
= Router
::new()
185 .get(&list_subdirs_api_method
!(SUBDIRS
))