public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v15 25/26] bin: debug: add inspect device command
Date: Mon, 25 Nov 2024 17:22:12 +0100	[thread overview]
Message-ID: <20241125162213.157011-26-h.laimer@proxmox.com> (raw)
In-Reply-To: <20241125162213.157011-1-h.laimer@proxmox.com>

... to get information about (removable) datastores a device contains

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
 src/bin/proxmox_backup_debug/inspect.rs | 149 ++++++++++++++++++++++++
 1 file changed, 149 insertions(+)

diff --git a/src/bin/proxmox_backup_debug/inspect.rs b/src/bin/proxmox_backup_debug/inspect.rs
index 28a472b0f..17df09be2 100644
--- a/src/bin/proxmox_backup_debug/inspect.rs
+++ b/src/bin/proxmox_backup_debug/inspect.rs
@@ -331,6 +331,151 @@ fn inspect_file(
     Ok(())
 }
 
+/// Return the count of VM, CT and host backup groups and the count of namespaces
+/// as this tuple (vm, ct, host, ns)
+fn get_basic_ds_info(path: String) -> Result<(i64, i64, i64, i64), Error> {
+    let mut vms = 0;
+    let mut cts = 0;
+    let mut hosts = 0;
+    let mut ns = 0;
+    let mut walker = WalkDir::new(path).into_iter();
+
+    while let Some(entry_result) = walker.next() {
+        let entry = entry_result?;
+        if !entry.file_type().is_dir() {
+            continue;
+        }
+
+        let Some(name) = entry.path().file_name().and_then(|a| a.to_str()) else {
+            continue;
+        };
+
+        if name == ".chunks" {
+            walker.skip_current_dir();
+            continue;
+        }
+
+        let dir_count = std::fs::read_dir(entry.path())?
+            .filter_map(Result::ok)
+            .filter(|entry| entry.path().is_dir())
+            .count() as i64;
+
+        match name {
+            "ns" => ns += dir_count,
+            "vm" => {
+                vms += dir_count;
+                walker.skip_current_dir();
+            }
+            "ct" => {
+                cts += dir_count;
+                walker.skip_current_dir();
+            }
+            "host" => {
+                hosts += dir_count;
+                walker.skip_current_dir();
+            }
+            _ => {
+                // root or ns dir
+            }
+        }
+    }
+
+    Ok((vms, cts, hosts, ns))
+}
+
+#[api(
+    input: {
+        properties: {
+            device: {
+                description: "Device path, usually /dev/...",
+                type: String,
+            },
+            "output-format": {
+                schema: OUTPUT_FORMAT,
+                optional: true,
+            },
+        }
+    }
+)]
+/// Inspect a device for possible datastores on it
+fn inspect_device(device: String, param: Value) -> Result<(), Error> {
+    let output_format = get_output_format(&param);
+    let tmp_mount_path = format!(
+        "{}/{:x}",
+        pbs_buildcfg::rundir!("/mount"),
+        proxmox_uuid::Uuid::generate()
+    );
+
+    let default_options = proxmox_sys::fs::CreateOptions::new();
+    proxmox_sys::fs::create_path(
+        &tmp_mount_path,
+        Some(default_options.clone()),
+        Some(default_options.clone()),
+    )?;
+    let mut mount_cmd = std::process::Command::new("mount");
+    mount_cmd.arg(device.clone());
+    mount_cmd.arg(tmp_mount_path.clone());
+    proxmox_sys::command::run_command(mount_cmd, None)?;
+
+    let mut walker = WalkDir::new(tmp_mount_path.clone()).into_iter();
+
+    let mut stores = Vec::new();
+
+    let mut ds_count = 0;
+    while let Some(entry_result) = walker.next() {
+        let entry = entry_result?;
+
+        if entry.file_type().is_dir()
+            && entry
+                .file_name()
+                .to_str()
+                .map_or(false, |name| name == ".chunks")
+        {
+            let store_path = entry
+                .path()
+                .to_str()
+                .and_then(|n| n.strip_suffix("/.chunks"));
+
+            if let Some(store_path) = store_path {
+                ds_count += 1;
+                let (vm, ct, host, ns) = get_basic_ds_info(store_path.to_string())?;
+                stores.push(json!({
+                    "path": store_path.strip_prefix(&tmp_mount_path).unwrap_or("???"),
+                    "vm-count": vm,
+                    "ct-count": ct,
+                    "host-count": host,
+                    "ns-count": ns,
+                }));
+            };
+
+            walker.skip_current_dir();
+        }
+    }
+
+    let mut umount_cmd = std::process::Command::new("umount");
+    umount_cmd.arg(tmp_mount_path.clone());
+    proxmox_sys::command::run_command(umount_cmd, None)?;
+    std::fs::remove_dir(std::path::Path::new(&tmp_mount_path))?;
+
+    if output_format == "text" {
+        println!("Device containes {} stores", ds_count);
+        println!("---------------");
+        for s in stores {
+            println!(
+                "Datastore at {} | VM: {}, CT: {}, HOST: {}, NS: {}",
+                s["path"], s["vm-count"], s["ct-count"], s["host-count"], s["ns-count"]
+            );
+        }
+    } else {
+        format_and_print_result(
+            &json!({"store_count": stores.len(), "stores": stores}),
+            &output_format,
+        );
+    }
+
+    Ok(())
+}
+
 pub fn inspect_commands() -> CommandLineInterface {
     let cmd_def = CliCommandMap::new()
         .insert(
@@ -340,6 +485,10 @@ pub fn inspect_commands() -> CommandLineInterface {
         .insert(
             "file",
             CliCommand::new(&API_METHOD_INSPECT_FILE).arg_param(&["file"]),
+        )
+        .insert(
+            "device",
+            CliCommand::new(&API_METHOD_INSPECT_DEVICE).arg_param(&["device"]),
         );
 
     cmd_def.into()
-- 
2.39.5



_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


  parent reply	other threads:[~2024-11-25 16:23 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-25 16:21 [pbs-devel] [PATCH proxmox-backup v15 00/26] add removable datastores Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 01/26] pbs-api-types: add backing-device to DataStoreConfig Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 02/26] maintenance: make is_offline more generic Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 03/26] maintenance: add 'Unmount' maintenance type Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 04/26] datastore: add helper for checking if a datastore is mounted Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 05/26] api: admin: add (un)mount endpoint for removable datastores Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 06/26] api: removable datastore creation Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 07/26] api: add check for nested datastores on creation Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 08/26] pbs-api-types: add mount_status field to DataStoreListItem Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 09/26] bin: manager: add (un)mount command Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 10/26] add auto-mounting for removable datastores Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 11/26] datastore: handle deletion of removable datastore properly Hannes Laimer
2024-11-25 16:21 ` [pbs-devel] [PATCH proxmox-backup v15 12/26] docs: add removable datastores section Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 13/26] ui: add partition selector form Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 14/26] ui: add removable datastore creation support Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 15/26] ui: add (un)mount button to summary Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 16/26] ui: tree: render unmounted datastores correctly Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 17/26] ui: utils: make parseMaintenanceMode more robust Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 18/26] ui: add datastore status mask for unmounted removable datastores Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 19/26] ui: maintenance: fix disable msg field if no type is selected Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 20/26] ui: render 'unmount' maintenance mode correctly Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 21/26] api: node: allow creation of removable datastore through directory endpoint Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 22/26] api: node: include removable datastores in directory list Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 23/26] node: disks: replace BASE_MOUNT_DIR with DATASTORE_MOUNT_DIR Hannes Laimer
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 24/26] ui: support create removable datastore through directory creation Hannes Laimer
2024-11-25 16:22 ` Hannes Laimer [this message]
2024-11-25 16:22 ` [pbs-devel] [PATCH proxmox-backup v15 26/26] api: disks: only return UUID of partitions if it actually is one Hannes Laimer
2024-11-25 20:48 ` [pbs-devel] applied-series: [PATCH proxmox-backup v15 00/26] add removable datastores Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241125162213.157011-26-h.laimer@proxmox.com \
    --to=h.laimer@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal