6 use proxmox_schema
::api
;
14 use proxmox_router
::list_subdirs_api_method
;
17 Authid
, DataStoreStatusListItem
, Operation
, RRDMode
, RRDTimeFrame
,
18 PRIV_DATASTORE_AUDIT
, PRIV_DATASTORE_BACKUP
,
21 use pbs_datastore
::DataStore
;
22 use pbs_config
::CachedUserInfo
;
24 use crate::tools
::statistics
::{linear_regression}
;
25 use crate::rrd_cache
::extract_rrd_data
;
29 description
: "Lists the Status of the Datastores.",
32 type: DataStoreStatusListItem
,
36 permission
: &Permission
::Anybody
,
39 /// List Datastore usages and estimates
40 pub fn datastore_status(
43 rpcenv
: &mut dyn RpcEnvironment
,
44 ) -> Result
<Vec
<DataStoreStatusListItem
>, Error
> {
46 let (config
, _digest
) = pbs_config
::datastore
::config()?
;
48 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
49 let user_info
= CachedUserInfo
::new()?
;
51 let mut list
= Vec
::new();
53 for (store
, (_
, _
)) in &config
.sections
{
54 let user_privs
= user_info
.lookup_privs(&auth_id
, &["datastore", store
]);
55 let allowed
= (user_privs
& (PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_BACKUP
)) != 0;
60 let datastore
= match DataStore
::lookup_datastore(&store
, Some(Operation
::Read
)) {
61 Ok(datastore
) => datastore
,
63 list
.push(DataStoreStatusListItem
{
71 estimated_full_date
: None
,
72 error
: Some(err
.to_string()),
77 let status
= crate::tools
::disks
::disk_usage(&datastore
.base_path())?
;
79 let mut entry
= DataStoreStatusListItem
{
81 total
: status
.total
as i64,
82 used
: status
.used
as i64,
83 avail
: status
.avail
as i64,
87 estimated_full_date
: None
,
91 let rrd_dir
= format
!("datastore/{}", store
);
93 let get_rrd
= |what
: &str| extract_rrd_data(
100 let total_res
= get_rrd("total")?
;
101 let used_res
= get_rrd("used")?
;
103 if let (Some((start
, reso
, total_list
)), Some((_
, _
, used_list
))) = (total_res
, used_res
) {
104 let mut usage_list
: Vec
<f64> = Vec
::new();
105 let mut time_list
: Vec
<u64> = Vec
::new();
106 let mut history
= Vec
::new();
108 for (idx
, used
) in used_list
.iter().enumerate() {
109 let total
= if idx
< total_list
.len() {
115 match (total
, used
) {
116 (Some(total
), Some(used
)) if total
!= 0.0 => {
117 time_list
.push(start
+ (idx
as u64)*reso
);
118 let usage
= used
/total
;
119 usage_list
.push(usage
);
120 history
.push(Some(usage
));
128 entry
.history_start
= Some(start
);
129 entry
.history_delta
= Some(reso
);
130 entry
.history
= Some(history
);
132 // we skip the calculation for datastores with not enough data
133 if usage_list
.len() >= 7 {
134 entry
.estimated_full_date
= match linear_regression(&time_list
, &usage_list
) {
135 Some((a
, b
)) if b
!= 0.0 => Some(((1.0 - a
) / b
).floor() as i64),
136 Some((_
, b
)) if b
== 0.0 => Some(0), // infinite estimate, set to past for gui to detect
148 const SUBDIRS
: SubdirMap
= &[
149 ("datastore-usage", &Router
::new().get(&API_METHOD_DATASTORE_STATUS
)),
152 pub const ROUTER
: Router
= Router
::new()
153 .get(&list_subdirs_api_method
!(SUBDIRS
))