]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/api2/node/disks/directory.rs
disks: use builder pattern for querying disk usage
[proxmox-backup.git] / src / api2 / node / disks / directory.rs
index 75e0ea027513fe4352801c0f95710172b90102b4..cada95cdb499f53f701a47e22259860cd75289ae 100644 (file)
@@ -1,23 +1,26 @@
+use ::serde::{Deserialize, Serialize};
 use anyhow::{bail, Error};
 use serde_json::json;
-use ::serde::{Deserialize, Serialize};
 
-use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
-use proxmox::api::section_config::SectionConfigData;
-use proxmox::api::router::Router;
+use proxmox_router::{Permission, Router, RpcEnvironment, RpcEnvironmentType};
+use proxmox_schema::api;
+use proxmox_section_config::SectionConfigData;
+use proxmox_sys::task_log;
+
+use pbs_api_types::{
+    DataStoreConfig, BLOCKDEVICE_NAME_SCHEMA, DATASTORE_SCHEMA, NODE_SCHEMA, PRIV_SYS_AUDIT,
+    PRIV_SYS_MODIFY, UPID_SCHEMA,
+};
 
-use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
 use crate::tools::disks::{
-    DiskManage, FileSystemType, DiskUsageType,
-    create_file_system, create_single_linux_partition, get_fs_uuid, get_disk_usage_info,
+    create_file_system, create_single_linux_partition, get_fs_uuid, DiskManage, DiskUsageQuery,
+    DiskUsageType, FileSystemType,
 };
 use crate::tools::systemd::{self, types::*};
 
-use crate::server::WorkerTask;
+use proxmox_rest_server::WorkerTask;
 
-use crate::api2::types::*;
-use crate::config::datastore::{self, DataStoreConfig};
-use crate::backup::open_backup_lockfile;
+const BASE_MOUNT_DIR: &str = "/mnt/datastore/";
 
 #[api(
     properties: {
@@ -28,11 +31,13 @@ use crate::backup::open_backup_lockfile;
     },
 )]
 #[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all="kebab-case")]
+#[serde(rename_all = "kebab-case")]
 /// Datastore mount info.
 pub struct DatastoreMountInfo {
     /// The path of the mount unit.
     pub unitfile: String,
+    /// The name of the mount
+    pub name: String,
     /// The mount path.
     pub path: String,
     /// The mounted device.
@@ -64,8 +69,7 @@ pub struct DatastoreMountInfo {
     },
 )]
 /// List systemd datastore mount units.
-pub fn  list_datastore_mounts() -> Result<Vec<DatastoreMountInfo>, Error> {
-
+pub fn list_datastore_mounts() -> Result<Vec<DatastoreMountInfo>, Error> {
     lazy_static::lazy_static! {
         static ref MOUNT_NAME_REGEX: regex::Regex = regex::Regex::new(r"^mnt-datastore-(.+)\.mount$").unwrap();
     }
@@ -73,7 +77,7 @@ pub fn  list_datastore_mounts() -> Result<Vec<DatastoreMountInfo>, Error> {
     let mut list = Vec::new();
 
     let basedir = "/etc/systemd/system";
-    for item in pbs_tools::fs::scan_subdir(libc::AT_FDCWD, basedir, &MOUNT_NAME_REGEX)? {
+    for item in proxmox_sys::fs::scan_subdir(libc::AT_FDCWD, basedir, &MOUNT_NAME_REGEX)? {
         let item = item?;
         let name = item.file_name().to_string_lossy().to_string();
 
@@ -81,8 +85,15 @@ pub fn  list_datastore_mounts() -> Result<Vec<DatastoreMountInfo>, Error> {
         let config = systemd::config::parse_systemd_mount(&unitfile)?;
         let data: SystemdMountSection = config.lookup("Mount", "Mount")?;
 
+        let name = data
+            .Where
+            .strip_prefix(BASE_MOUNT_DIR)
+            .unwrap_or_else(|| &data.Where)
+            .to_string();
+
         list.push(DatastoreMountInfo {
             unitfile,
+            name,
             device: data.What,
             path: data.Where,
             filesystem: data.Type,
@@ -132,33 +143,35 @@ pub fn create_datastore_disk(
     filesystem: Option<FileSystemType>,
     rpcenv: &mut dyn RpcEnvironment,
 ) -> Result<String, Error> {
-
     let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
 
-    let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
+    let auth_id = rpcenv.get_auth_id().unwrap();
 
-    let info = get_disk_usage_info(&disk, true)?;
+    let info = DiskUsageQuery::new().smart(false).find(&disk)?;
 
     if info.used != DiskUsageType::Unused {
         bail!("disk '{}' is already in use.", disk);
     }
 
-    let mount_point = format!("/mnt/datastore/{}", &name);
+    let mount_point = format!("{}{}", BASE_MOUNT_DIR, &name);
 
     // check if the default path does exist already and bail if it does
     let default_path = std::path::PathBuf::from(&mount_point);
 
     match std::fs::metadata(&default_path) {
-        Err(_) => {}, // path does not exist
+        Err(_) => {} // path does not exist
         Ok(_) => {
             bail!("path {:?} already exists", default_path);
         }
     }
 
     let upid_str = WorkerTask::new_thread(
-        "dircreate", Some(name.clone()), auth_id, to_stdout, move |worker|
-        {
-            worker.log(format!("create datastore '{}' on disk {}", name, disk));
+        "dircreate",
+        Some(name.clone()),
+        auth_id,
+        to_stdout,
+        move |worker| {
+            task_log!(worker, "create datastore '{}' on disk {}", name, disk);
 
             let add_datastore = add_datastore.unwrap_or(false);
             let filesystem = filesystem.unwrap_or(FileSystemType::Ext4);
@@ -173,28 +186,35 @@ pub fn create_datastore_disk(
             let uuid = get_fs_uuid(&partition)?;
             let uuid_path = format!("/dev/disk/by-uuid/{}", uuid);
 
-            let mount_unit_name = create_datastore_mount_unit(&name, &mount_point, filesystem, &uuid_path)?;
+            let mount_unit_name =
+                create_datastore_mount_unit(&name, &mount_point, filesystem, &uuid_path)?;
 
-            systemd::reload_daemon()?;
-            systemd::enable_unit(&mount_unit_name)?;
-            systemd::start_unit(&mount_unit_name)?;
+            crate::tools::systemd::reload_daemon()?;
+            crate::tools::systemd::enable_unit(&mount_unit_name)?;
+            crate::tools::systemd::start_unit(&mount_unit_name)?;
 
             if add_datastore {
-                let lock = open_backup_lockfile(datastore::DATASTORE_CFG_LOCKFILE, None, true)?;
+                let lock = pbs_config::datastore::lock_config()?;
                 let datastore: DataStoreConfig =
                     serde_json::from_value(json!({ "name": name, "path": mount_point }))?;
 
-                let (config, _digest) = datastore::config()?;
+                let (config, _digest) = pbs_config::datastore::config()?;
 
                 if config.sections.get(&datastore.name).is_some() {
                     bail!("datastore '{}' already exists.", datastore.name);
                 }
 
-                crate::api2::config::datastore::do_create_datastore(lock, config, datastore, Some(&worker))?;
+                crate::api2::config::datastore::do_create_datastore(
+                    lock,
+                    config,
+                    datastore,
+                    Some(&worker),
+                )?;
             }
 
             Ok(())
-        })?;
+        },
+    )?;
 
     Ok(upid_str)
 }
@@ -217,23 +237,25 @@ pub fn create_datastore_disk(
 )]
 /// Remove a Filesystem mounted under '/mnt/datastore/<name>'.".
 pub fn delete_datastore_disk(name: String) -> Result<(), Error> {
-
-    let path = format!("/mnt/datastore/{}", name);
+    let path = format!("{}{}", BASE_MOUNT_DIR, name);
     // path of datastore cannot be changed
-    let (config, _) = crate::config::datastore::config()?;
+    let (config, _) = pbs_config::datastore::config()?;
     let datastores: Vec<DataStoreConfig> = config.convert_to_typed_array("datastore")?;
-    let conflicting_datastore: Option<DataStoreConfig> = datastores.into_iter()
-        .find(|ds| ds.path == path);
+    let conflicting_datastore: Option<DataStoreConfig> =
+        datastores.into_iter().find(|ds| ds.path == path);
 
     if let Some(conflicting_datastore) = conflicting_datastore {
-        bail!("Can't remove '{}' since it's required by datastore '{}'",
-              conflicting_datastore.path, conflicting_datastore.name);
+        bail!(
+            "Can't remove '{}' since it's required by datastore '{}'",
+            conflicting_datastore.path,
+            conflicting_datastore.name
+        );
     }
 
     // disable systemd mount-unit
-    let mut mount_unit_name = systemd::escape_unit(&path, true);
+    let mut mount_unit_name = proxmox_sys::systemd::escape_unit(&path, true);
     mount_unit_name.push_str(".mount");
-    systemd::disable_unit(&mount_unit_name)?;
+    crate::tools::systemd::disable_unit(&mount_unit_name)?;
 
     // delete .mount-file
     let mount_unit_path = format!("/etc/systemd/system/{}", mount_unit_name);
@@ -244,39 +266,39 @@ pub fn delete_datastore_disk(name: String) -> Result<(), Error> {
     // try to unmount, if that fails tell the user to reboot or unmount manually
     let mut command = std::process::Command::new("umount");
     command.arg(&path);
-    match crate::tools::run_command(command, None) {
+    match proxmox_sys::command::run_command(command, None) {
         Err(_) => bail!(
             "Could not umount '{}' since it is busy. It will stay mounted \
              until the next reboot or until unmounted manually!",
             path
         ),
-        Ok(_) => Ok(())
+        Ok(_) => Ok(()),
     }
 }
 
-const ITEM_ROUTER: Router = Router::new()
-    .delete(&API_METHOD_DELETE_DATASTORE_DISK);
+const ITEM_ROUTER: Router = Router::new().delete(&API_METHOD_DELETE_DATASTORE_DISK);
 
 pub const ROUTER: Router = Router::new()
     .get(&API_METHOD_LIST_DATASTORE_MOUNTS)
     .post(&API_METHOD_CREATE_DATASTORE_DISK)
     .match_all("name", &ITEM_ROUTER);
 
-
 fn create_datastore_mount_unit(
     datastore_name: &str,
     mount_point: &str,
     fs_type: FileSystemType,
     what: &str,
 ) -> Result<String, Error> {
-
-    let mut mount_unit_name = systemd::escape_unit(&mount_point, true);
+    let mut mount_unit_name = proxmox_sys::systemd::escape_unit(mount_point, true);
     mount_unit_name.push_str(".mount");
 
     let mount_unit_path = format!("/etc/systemd/system/{}", mount_unit_name);
 
     let unit = SystemdUnitSection {
-        Description: format!("Mount datatstore '{}' under '{}'", datastore_name, mount_point),
+        Description: format!(
+            "Mount datatstore '{}' under '{}'",
+            datastore_name, mount_point
+        ),
         ..Default::default()
     };