1 use proxmox
::list_subdirs_api_method
;
4 use serde_json
::{json, Value}
;
15 use crate::api2
::types
::{
18 RRDTimeFrameResolution
,
25 use crate::backup
::{DataStore}
;
26 use crate::config
::datastore
;
27 use crate::tools
::statistics
::{linear_regression}
;
28 use crate::config
::cached_user_info
::CachedUserInfo
;
29 use crate::config
::acl
::{
32 PRIV_DATASTORE_BACKUP
,
37 description
: "Lists the Status of the Datastores.",
40 description
: "Status of a Datastore",
44 schema
: DATASTORE_SCHEMA
,
48 description
: "The Size of the underlying storage in bytes",
52 description
: "The used bytes of the underlying storage",
56 description
: "The available bytes of the underlying storage",
60 description
: "A list of usages of the past (last Month).",
63 description
: "The usage of a time in the past. Either null or between 0.0 and 1.0.",
66 "estimated-full-date": {
69 description
: "Estimation of the UNIX epoch when the storage will be full.\
70 This is calculated via a simple Linear Regression (Least Squares)\
71 of RRD data of the last Month. Missing if there are not enough data points yet.\
72 If the estimate lies in the past, the usage is decreasing.",
78 permission
: &Permission
::Anybody
,
81 /// List Datastore usages and estimates
85 rpcenv
: &mut dyn RpcEnvironment
,
86 ) -> Result
<Value
, Error
> {
88 let (config
, _digest
) = datastore
::config()?
;
90 let userid
: Userid
= rpcenv
.get_user().unwrap().parse()?
;
91 let user_info
= CachedUserInfo
::new()?
;
93 let mut list
= Vec
::new();
95 for (store
, (_
, _
)) in &config
.sections
{
96 let user_privs
= user_info
.lookup_privs(&userid
, &["datastore", &store
]);
97 let allowed
= (user_privs
& (PRIV_DATASTORE_AUDIT
| PRIV_DATASTORE_BACKUP
)) != 0;
102 let datastore
= DataStore
::lookup_datastore(&store
)?
;
103 let status
= crate::tools
::disks
::disk_usage(&datastore
.base_path())?
;
105 let mut entry
= json
!({
107 "total": status
.total
,
109 "avail": status
.avail
,
112 let rrd_dir
= format
!("datastore/{}", store
);
113 let now
= proxmox
::tools
::time
::epoch_f64();
114 let rrd_resolution
= RRDTimeFrameResolution
::Month
;
115 let rrd_mode
= RRDMode
::Average
;
117 let total_res
= crate::rrd
::extract_cached_data(
125 let used_res
= crate::rrd
::extract_cached_data(
133 match (total_res
, used_res
) {
134 (Some((start
, reso
, total_list
)), Some((_
, _
, used_list
))) => {
135 let mut usage_list
: Vec
<f64> = Vec
::new();
136 let mut time_list
: Vec
<u64> = Vec
::new();
137 let mut history
= Vec
::new();
139 for (idx
, used
) in used_list
.iter().enumerate() {
140 let total
= if idx
< total_list
.len() {
146 match (total
, used
) {
147 (Some(total
), Some(used
)) if total
!= 0.0 => {
148 time_list
.push(start
+ (idx
as u64)*reso
);
149 let usage
= used
/total
;
150 usage_list
.push(usage
);
151 history
.push(json
!(usage
));
154 history
.push(json
!(null
))
159 entry
["history"] = history
.into();
161 // we skip the calculation for datastores with not enough data
162 if usage_list
.len() >= 7 {
163 if let Some((a
,b
)) = linear_regression(&time_list
, &usage_list
) {
165 let estimate
= (1.0 - a
) / b
;
166 entry
["estimated-full-date"] = Value
::from(estimate
.floor() as u64);
168 entry
["estimated-full-date"] = Value
::from(0);
187 description
: "Only list tasks since this UNIX epoch.",
193 description
: "Only list tasks, whose type contains this string.",
198 description
: "Only list tasks which have any one of the listed status.",
206 description
: "A list of tasks.",
208 items
: { type: TaskListItem }
,
211 description
: "Users can only see there own tasks, unless the have Sys.Audit on /system/tasks.",
212 permission
: &Permission
::Anybody
,
218 typefilter
: Option
<String
>,
219 statusfilter
: Option
<Vec
<TaskStateType
>>,
221 rpcenv
: &mut dyn RpcEnvironment
,
222 ) -> Result
<Vec
<TaskListItem
>, Error
> {
224 let userid
: Userid
= rpcenv
.get_user().unwrap().parse()?
;
225 let user_info
= CachedUserInfo
::new()?
;
226 let user_privs
= user_info
.lookup_privs(&userid
, &["system", "tasks"]);
228 let list_all
= (user_privs
& PRIV_SYS_AUDIT
) != 0;
229 let since
= since
.unwrap_or_else(|| 0);
231 let list
: Vec
<TaskListItem
> = server
::TaskListInfoIterator
::new(false)?
234 Ok(info
) => info
.upid
.starttime
> since
,
241 if list_all
|| info
.upid
.userid
== userid
{
242 if let Some(filter
) = &typefilter
{
243 if !info
.upid
.worker_type
.contains(filter
) {
248 if let Some(filters
) = &statusfilter
{
249 if let Some(state
) = &info
.state
{
250 let statetype
= match state
{
251 server
::TaskState
::OK { .. }
=> TaskStateType
::OK
,
252 server
::TaskState
::Unknown { .. }
=> TaskStateType
::Unknown
,
253 server
::TaskState
::Error { .. }
=> TaskStateType
::Error
,
254 server
::TaskState
::Warning { .. }
=> TaskStateType
::Warning
,
257 if !filters
.contains(&statetype
) {
263 Some(Ok(TaskListItem
::from(info
)))
268 Err(err
) => Some(Err(err
))
271 .collect
::<Result
<Vec
<TaskListItem
>, Error
>>()?
;
276 const SUBDIRS
: SubdirMap
= &[
277 ("datastore-usage", &Router
::new().get(&API_METHOD_DATASTORE_STATUS
)),
278 ("tasks", &Router
::new().get(&API_METHOD_LIST_TASKS
)),
281 pub const ROUTER
: Router
= Router
::new()
282 .get(&list_subdirs_api_method
!(SUBDIRS
))