]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/status.rs
avoid chrono dependency, depend on proxmox 0.3.8
[proxmox-backup.git] / src / api2 / status.rs
CommitLineData
bda48e04
DC
1use proxmox::list_subdirs_api_method;
2
3use anyhow::{Error};
4use serde_json::{json, Value};
5
20b3094b
DC
6use proxmox::api::{
7 api,
8 ApiMethod,
9 Permission,
10 Router,
11 RpcEnvironment,
12 SubdirMap,
20b3094b
DC
13};
14
15use crate::api2::types::{
16 DATASTORE_SCHEMA,
17 RRDMode,
18 RRDTimeFrameResolution,
e7cb4dc5
WB
19 TaskListItem,
20 Userid,
20b3094b 21};
bda48e04 22
20b3094b 23use crate::server;
bda48e04
DC
24use crate::backup::{DataStore};
25use crate::config::datastore;
26use crate::tools::statistics::{linear_regression};
27use crate::config::cached_user_info::CachedUserInfo;
28use crate::config::acl::{
20b3094b 29 PRIV_SYS_AUDIT,
bda48e04
DC
30 PRIV_DATASTORE_AUDIT,
31 PRIV_DATASTORE_BACKUP,
32};
33
34#[api(
35 returns: {
36 description: "Lists the Status of the Datastores.",
37 type: Array,
38 items: {
39 description: "Status of a Datastore",
40 type: Object,
41 properties: {
42 store: {
43 schema: DATASTORE_SCHEMA,
44 },
45 total: {
46 type: Integer,
47 description: "The Size of the underlying storage in bytes",
48 },
49 used: {
50 type: Integer,
51 description: "The used bytes of the underlying storage",
52 },
53 avail: {
54 type: Integer,
55 description: "The available bytes of the underlying storage",
56 },
57 history: {
58 type: Array,
59 description: "A list of usages of the past (last Month).",
60 items: {
61 type: Number,
62 description: "The usage of a time in the past. Either null or between 0.0 and 1.0.",
63 }
64 },
65 "estimated-full-date": {
66 type: Integer,
67 optional: true,
68 description: "Estimation of the UNIX epoch when the storage will be full.\
69 This is calculated via a simple Linear Regression (Least Squares)\
70 of RRD data of the last Month. Missing if there are not enough data points yet.\
71 If the estimate lies in the past, the usage is decreasing.",
72 },
73 },
74 },
75 },
ecd55041
FG
76 access: {
77 permission: &Permission::Anybody,
78 },
bda48e04
DC
79)]
80/// List Datastore usages and estimates
81fn datastore_status(
82 _param: Value,
83 _info: &ApiMethod,
84 rpcenv: &mut dyn RpcEnvironment,
85 ) -> Result<Value, Error> {
86
87 let (config, _digest) = datastore::config()?;
88
e7cb4dc5 89 let userid: Userid = rpcenv.get_user().unwrap().parse()?;
bda48e04
DC
90 let user_info = CachedUserInfo::new()?;
91
92 let mut list = Vec::new();
93
94 for (store, (_, _)) in &config.sections {
e7cb4dc5 95 let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
bda48e04
DC
96 let allowed = (user_privs & (PRIV_DATASTORE_AUDIT| PRIV_DATASTORE_BACKUP)) != 0;
97 if !allowed {
98 continue;
99 }
100
101 let datastore = DataStore::lookup_datastore(&store)?;
102 let status = crate::tools::disks::disk_usage(&datastore.base_path())?;
103
104 let mut entry = json!({
105 "store": store,
106 "total": status.total,
107 "used": status.used,
108 "avail": status.avail,
109 });
110
111 let rrd_dir = format!("datastore/{}", store);
6a7be83e 112 let now = proxmox::tools::time::epoch_f64();
ec8f0424
DC
113 let rrd_resolution = RRDTimeFrameResolution::Month;
114 let rrd_mode = RRDMode::Average;
bda48e04 115
ec8f0424 116 let total_res = crate::rrd::extract_cached_data(
bda48e04 117 &rrd_dir,
ec8f0424
DC
118 "total",
119 now,
120 rrd_resolution,
121 rrd_mode,
122 );
bda48e04 123
ec8f0424
DC
124 let used_res = crate::rrd::extract_cached_data(
125 &rrd_dir,
126 "used",
127 now,
128 rrd_resolution,
129 rrd_mode,
130 );
131
132 match (total_res, used_res) {
133 (Some((start, reso, total_list)), Some((_, _, used_list))) => {
134 let mut usage_list: Vec<f64> = Vec::new();
135 let mut time_list: Vec<u64> = Vec::new();
136 let mut history = Vec::new();
137
138 for (idx, used) in used_list.iter().enumerate() {
139 let total = if idx < total_list.len() {
140 total_list[idx]
141 } else {
142 None
143 };
144
145 match (total, used) {
146 (Some(total), Some(used)) if total != 0.0 => {
147 time_list.push(start + (idx as u64)*reso);
148 let usage = used/total;
149 usage_list.push(usage);
150 history.push(json!(usage));
151 },
152 _ => {
153 history.push(json!(null))
154 }
155 }
bda48e04 156 }
bda48e04 157
ec8f0424 158 entry["history"] = history.into();
bda48e04 159
ec8f0424
DC
160 // we skip the calculation for datastores with not enough data
161 if usage_list.len() >= 7 {
162 if let Some((a,b)) = linear_regression(&time_list, &usage_list) {
163 if b != 0.0 {
164 let estimate = (1.0 - a) / b;
165 entry["estimated-full-date"] = Value::from(estimate.floor() as u64);
a26c27c8
DC
166 } else {
167 entry["estimated-full-date"] = Value::from(0);
ec8f0424
DC
168 }
169 }
bda48e04 170 }
ec8f0424
DC
171 },
172 _ => {},
bda48e04
DC
173 }
174
175 list.push(entry);
176 }
177
bda48e04
DC
178 Ok(list.into())
179}
180
20b3094b
DC
181#[api(
182 input: {
183 properties: {
184 since: {
185 type: u64,
186 description: "Only list tasks since this UNIX epoch.",
187 optional: true,
188 },
189 },
190 },
191 returns: {
192 description: "A list of tasks.",
193 type: Array,
194 items: { type: TaskListItem },
195 },
196 access: {
197 description: "Users can only see there own tasks, unless the have Sys.Audit on /system/tasks.",
198 permission: &Permission::Anybody,
199 },
200)]
201/// List tasks.
202pub fn list_tasks(
203 _param: Value,
204 rpcenv: &mut dyn RpcEnvironment,
205) -> Result<Vec<TaskListItem>, Error> {
206
e7cb4dc5 207 let userid: Userid = rpcenv.get_user().unwrap().parse()?;
20b3094b 208 let user_info = CachedUserInfo::new()?;
e7cb4dc5 209 let user_privs = user_info.lookup_privs(&userid, &["system", "tasks"]);
20b3094b
DC
210
211 let list_all = (user_privs & PRIV_SYS_AUDIT) != 0;
212
213 // TODO: replace with call that gets all task since 'since' epoch
214 let list: Vec<TaskListItem> = server::read_task_list()?
215 .into_iter()
216 .map(TaskListItem::from)
e7cb4dc5 217 .filter(|entry| list_all || entry.user == userid)
20b3094b
DC
218 .collect();
219
220 Ok(list.into())
221}
222
bda48e04
DC
223const SUBDIRS: SubdirMap = &[
224 ("datastore-usage", &Router::new().get(&API_METHOD_DATASTORE_STATUS)),
20b3094b 225 ("tasks", &Router::new().get(&API_METHOD_LIST_TASKS)),
bda48e04
DC
226];
227
228pub const ROUTER: Router = Router::new()
229 .get(&list_subdirs_api_method!(SUBDIRS))
230 .subdirs(SUBDIRS);