]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/api2/status.rs
move RRD code into proxmox-rrd crate
[proxmox-backup.git] / src / api2 / status.rs
index c44e73f12304b814b2cd8757962f854880908091..995e12cc7537f1bd8f819cbdf10df4726beb172f 100644 (file)
@@ -1,3 +1,5 @@
+//! Datastote status
+
 use proxmox::list_subdirs_api_method;
 
 use anyhow::{Error};
@@ -12,25 +14,16 @@ use proxmox::api::{
     SubdirMap,
 };
 
-use crate::api2::types::{
-    DATASTORE_SCHEMA,
-    RRDMode,
-    RRDTimeFrameResolution,
-    TaskListItem,
-    Userid,
+use pbs_api_types::{
+    Authid, DATASTORE_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
 };
+use proxmox_rrd::{RRDMode, RRDTimeFrameResolution};
+
+use pbs_datastore::DataStore;
+use pbs_config::CachedUserInfo;
 
-use crate::server;
-use crate::backup::{DataStore};
-use crate::config::datastore;
-use crate::tools::epoch_now_f64;
 use crate::tools::statistics::{linear_regression};
-use crate::config::cached_user_info::CachedUserInfo;
-use crate::config::acl::{
-    PRIV_SYS_AUDIT,
-    PRIV_DATASTORE_AUDIT,
-    PRIV_DATASTORE_BACKUP,
-};
+use crate::RRD_CACHE;
 
 #[api(
     returns: {
@@ -57,6 +50,7 @@ use crate::config::acl::{
                 },
                 history: {
                     type: Array,
+                    optional: true,
                     description: "A list of usages of the past (last Month).",
                     items: {
                         type: Number,
@@ -71,32 +65,52 @@ use crate::config::acl::{
                         of RRD data of the last Month. Missing if there are not enough data points yet.\
                         If the estimate lies in the past, the usage is decreasing.",
                 },
+                "error": {
+                    type: String,
+                    optional: true,
+                    description: "An error description, for example, when the datastore could not be looked up.",
+                },
             },
         },
     },
+    access: {
+        permission: &Permission::Anybody,
+    },
 )]
 /// List Datastore usages and estimates
-fn datastore_status(
+pub fn datastore_status(
     _param: Value,
     _info: &ApiMethod,
     rpcenv: &mut dyn RpcEnvironment,
     ) -> Result<Value, Error> {
 
-    let (config, _digest) = datastore::config()?;
+    let (config, _digest) = pbs_config::datastore::config()?;
 
-    let userid: Userid = rpcenv.get_user().unwrap().parse()?;
+    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
     let user_info = CachedUserInfo::new()?;
 
     let mut list = Vec::new();
 
     for (store, (_, _)) in &config.sections {
-        let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
+        let user_privs = user_info.lookup_privs(&auth_id, &["datastore", &store]);
         let allowed = (user_privs & (PRIV_DATASTORE_AUDIT| PRIV_DATASTORE_BACKUP)) != 0;
         if !allowed {
             continue;
         }
 
-        let datastore = DataStore::lookup_datastore(&store)?;
+        let datastore = match DataStore::lookup_datastore(&store) {
+            Ok(datastore) => datastore,
+            Err(err) => {
+                list.push(json!({
+                    "store": store,
+                    "total": -1,
+                    "used": -1,
+                    "avail": -1,
+                    "error": err.to_string()
+                }));
+                continue;
+            }
+        };
         let status = crate::tools::disks::disk_usage(&datastore.base_path())?;
 
         let mut entry = json!({
@@ -104,70 +118,59 @@ fn datastore_status(
             "total": status.total,
             "used": status.used,
             "avail": status.avail,
+            "gc-status": datastore.last_gc_status(),
         });
 
         let rrd_dir = format!("datastore/{}", store);
-        let now = epoch_now_f64()?;
-        let rrd_resolution = RRDTimeFrameResolution::Month;
-        let rrd_mode = RRDMode::Average;
+        let now = proxmox::tools::time::epoch_f64();
 
-        let total_res = crate::rrd::extract_cached_data(
+        let get_rrd = |what: &str| RRD_CACHE.extract_cached_data(
             &rrd_dir,
-            "total",
+            what,
             now,
-            rrd_resolution,
-            rrd_mode,
+            RRDTimeFrameResolution::Month,
+            RRDMode::Average,
         );
 
-        let used_res = crate::rrd::extract_cached_data(
-            &rrd_dir,
-            "used",
-            now,
-            rrd_resolution,
-            rrd_mode,
-        );
-
-        match (total_res, used_res) {
-            (Some((start, reso, total_list)), Some((_, _, used_list))) => {
-                let mut usage_list: Vec<f64> = Vec::new();
-                let mut time_list: Vec<u64> = Vec::new();
-                let mut history = Vec::new();
-
-                for (idx, used) in used_list.iter().enumerate() {
-                    let total = if idx < total_list.len() {
-                        total_list[idx]
-                    } else {
-                        None
-                    };
-
-                    match (total, used) {
-                        (Some(total), Some(used)) if total != 0.0 => {
-                            time_list.push(start + (idx as u64)*reso);
-                            let usage = used/total;
-                            usage_list.push(usage);
-                            history.push(json!(usage));
-                        },
-                        _ => {
-                            history.push(json!(null))
-                        }
+        let total_res = get_rrd("total");
+        let used_res = get_rrd("used");
+
+        if let (Some((start, reso, total_list)), Some((_, _, used_list))) = (total_res, used_res) {
+            let mut usage_list: Vec<f64> = Vec::new();
+            let mut time_list: Vec<u64> = Vec::new();
+            let mut history = Vec::new();
+
+            for (idx, used) in used_list.iter().enumerate() {
+                let total = if idx < total_list.len() {
+                    total_list[idx]
+                } else {
+                    None
+                };
+
+                match (total, used) {
+                    (Some(total), Some(used)) if total != 0.0 => {
+                        time_list.push(start + (idx as u64)*reso);
+                        let usage = used/total;
+                        usage_list.push(usage);
+                        history.push(json!(usage));
+                    },
+                    _ => {
+                        history.push(json!(null))
                     }
                 }
-
-                entry["history"] = history.into();
-
-                // we skip the calculation for datastores with not enough data
-                if usage_list.len() >= 7 {
-                    if let Some((a,b)) = linear_regression(&time_list, &usage_list) {
-                        if b != 0.0 {
-                            let estimate = (1.0 - a) / b;
-                            entry["estimated-full-date"] = Value::from(estimate.floor() as u64);
-                        } else {
-                            entry["estimated-full-date"] = Value::from(0);
-                        }
-                    }
-                }
-            },
-            _ => {},
+            }
+
+            entry["history-start"] = start.into();
+            entry["history-delta"] = reso.into();
+            entry["history"] = history.into();
+
+            // we skip the calculation for datastores with not enough data
+            if usage_list.len() >= 7 {
+                entry["estimated-full-date"] = match linear_regression(&time_list, &usage_list) {
+                    Some((a, b)) if b != 0.0 => Value::from(((1.0 - a) / b).floor() as u64),
+                    _ => Value::from(0),
+                };
+            }
         }
 
         list.push(entry);
@@ -176,51 +179,8 @@ fn datastore_status(
     Ok(list.into())
 }
 
-#[api(
-    input: {
-        properties: {
-            since: {
-                type: u64,
-                description: "Only list tasks since this UNIX epoch.",
-                optional: true,
-            },
-        },
-    },
-    returns: {
-        description: "A list of tasks.",
-        type: Array,
-        items: { type: TaskListItem },
-    },
-    access: {
-        description: "Users can only see there own tasks, unless the have Sys.Audit on /system/tasks.",
-        permission: &Permission::Anybody,
-    },
-)]
-/// List tasks.
-pub fn list_tasks(
-    _param: Value,
-    rpcenv: &mut dyn RpcEnvironment,
-) -> Result<Vec<TaskListItem>, Error> {
-
-    let userid: Userid = rpcenv.get_user().unwrap().parse()?;
-    let user_info = CachedUserInfo::new()?;
-    let user_privs = user_info.lookup_privs(&userid, &["system", "tasks"]);
-
-    let list_all = (user_privs & PRIV_SYS_AUDIT) != 0;
-
-    // TODO: replace with call that gets all task since 'since' epoch
-    let list: Vec<TaskListItem> = server::read_task_list()?
-        .into_iter()
-        .map(TaskListItem::from)
-        .filter(|entry| list_all || entry.user == userid)
-        .collect();
-
-    Ok(list.into())
-}
-
 const SUBDIRS: SubdirMap = &[
     ("datastore-usage", &Router::new().get(&API_METHOD_DATASTORE_STATUS)),
-    ("tasks", &Router::new().get(&API_METHOD_LIST_TASKS)),
 ];
 
 pub const ROUTER: Router = Router::new()