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
,
22 use crate::backup
::DataStore
;
23 use crate::config
::datastore
;
24 use crate::tools
::statistics
::{linear_regression}
;
25 use crate::config
::cached_user_info
::CachedUserInfo
;
29 description
: "Lists the Status of the Datastores.",
32 description
: "Status of a Datastore",
36 schema
: DATASTORE_SCHEMA
,
40 description
: "The Size of the underlying storage in bytes",
44 description
: "The used bytes of the underlying storage",
48 description
: "The available bytes of the underlying storage",
53 description
: "A list of usages of the past (last Month).",
56 description
: "The usage of a time in the past. Either null or between 0.0 and 1.0.",
59 "estimated-full-date": {
62 description
: "Estimation of the UNIX epoch when the storage will be full.\
63 This is calculated via a simple Linear Regression (Least Squares)\
64 of RRD data of the last Month. Missing if there are not enough data points yet.\
65 If the estimate lies in the past, the usage is decreasing.",
70 description
: "An error description, for example, when the datastore could not be looked up.",
76 permission
: &Permission
::Anybody
,
79 /// List Datastore usages and estimates
80 pub fn datastore_status(
83 rpcenv
: &mut dyn RpcEnvironment
,
84 ) -> Result
<Value
, Error
> {
86 let (config
, _digest
) = datastore
::config()?
;
88 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
89 let user_info
= CachedUserInfo
::new()?
;
91 let mut list
= Vec
::new();
93 for (store
, (_
, _
)) in &config
.sections
{
94 let user_privs
= user_info
.lookup_privs(&auth_id
, &["datastore", &store
]);
95 let allowed
= (user_privs
& (PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_BACKUP
)) != 0;
100 let datastore
= match DataStore
::lookup_datastore(&store
) {
101 Ok(datastore
) => datastore
,
108 "error": err
.to_string()
113 let status
= crate::tools
::disks
::disk_usage(&datastore
.base_path())?
;
115 let mut entry
= json
!({
117 "total": status
.total
,
119 "avail": status
.avail
,
120 "gc-status": datastore
.last_gc_status(),
123 let rrd_dir
= format
!("datastore/{}", store
);
124 let now
= proxmox
::tools
::time
::epoch_f64();
126 let get_rrd
= |what
: &str| crate::rrd
::extract_cached_data(
130 RRDTimeFrameResolution
::Month
,
134 let total_res
= get_rrd("total");
135 let used_res
= get_rrd("used");
137 if let (Some((start
, reso
, total_list
)), Some((_
, _
, used_list
))) = (total_res
, used_res
) {
138 let mut usage_list
: Vec
<f64> = Vec
::new();
139 let mut time_list
: Vec
<u64> = Vec
::new();
140 let mut history
= Vec
::new();
142 for (idx
, used
) in used_list
.iter().enumerate() {
143 let total
= if idx
< total_list
.len() {
149 match (total
, used
) {
150 (Some(total
), Some(used
)) if total
!= 0.0 => {
151 time_list
.push(start
+ (idx
as u64)*reso
);
152 let usage
= used
/total
;
153 usage_list
.push(usage
);
154 history
.push(json
!(usage
));
157 history
.push(json
!(null
))
162 entry
["history-start"] = start
.into();
163 entry
["history-delta"] = reso
.into();
164 entry
["history"] = history
.into();
166 // we skip the calculation for datastores with not enough data
167 if usage_list
.len() >= 7 {
168 entry
["estimated-full-date"] = match linear_regression(&time_list
, &usage_list
) {
169 Some((a
, b
)) if b
!= 0.0 => Value
::from(((1.0 - a
) / b
).floor() as u64),
181 const SUBDIRS
: SubdirMap
= &[
182 ("datastore-usage", &Router
::new().get(&API_METHOD_DATASTORE_STATUS
)),
185 pub const ROUTER
: Router
= Router
::new()
186 .get(&list_subdirs_api_method
!(SUBDIRS
))