From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id D9A421FF16E for ; Wed, 13 Nov 2024 16:01:28 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 50F9918919; Wed, 13 Nov 2024 16:01:20 +0100 (CET) From: Hannes Laimer To: pbs-devel@lists.proxmox.com Date: Wed, 13 Nov 2024 16:01:02 +0100 Message-Id: <20241113150102.164820-27-h.laimer@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241113150102.164820-1-h.laimer@proxmox.com> References: <20241113150102.164820-1-h.laimer@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.022 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup v13 26/26] bin: debug: add inspect device command X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" ... to get information about (removable) datastores a device contains Signed-off-by: Hannes Laimer --- new since v12. Something like this would also make sense to somehow integrate into the UI, making it easier to select and add existsing datastores on the device. But since the device has to be mounted, I was not sure where it makes sense, except maybe after selecting a device, so the `path` field could be some sort of selection. But we'd need a new endpoint and this can definitely also be added later, so I did not include anything in this series. 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 28a472b0..17df09be 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(¶m); + 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