[pbs-devel] [PATCH proxmox-backup v2 1/3] api2: disks endpoint return partitions
Hannes Laimer
h.laimer at proxmox.com
Wed Jun 8 10:51:51 CEST 2022
Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
src/api2/node/disks/directory.rs | 2 +-
src/api2/node/disks/mod.rs | 11 ++-
src/api2/node/disks/zfs.rs | 2 +-
src/tools/disks/mod.rs | 132 ++++++++++++++++++++++++++++++-
4 files changed, 140 insertions(+), 7 deletions(-)
diff --git a/src/api2/node/disks/directory.rs b/src/api2/node/disks/directory.rs
index f4d85d0a..123a8d7b 100644
--- a/src/api2/node/disks/directory.rs
+++ b/src/api2/node/disks/directory.rs
@@ -147,7 +147,7 @@ pub fn create_datastore_disk(
let auth_id = rpcenv.get_auth_id().unwrap();
- let info = get_disk_usage_info(&disk, true)?;
+ let info = get_disk_usage_info(&disk, true, false)?;
if info.used != DiskUsageType::Unused {
bail!("disk '{}' is already in use.", disk);
diff --git a/src/api2/node/disks/mod.rs b/src/api2/node/disks/mod.rs
index c44ccfee..478829fb 100644
--- a/src/api2/node/disks/mod.rs
+++ b/src/api2/node/disks/mod.rs
@@ -33,6 +33,12 @@ pub mod zfs;
optional: true,
default: false,
},
+ "include-partitions": {
+ description: "Include partitions.",
+ type: bool,
+ optional: true,
+ default: false,
+ },
"usage-type": {
type: DiskUsageType,
optional: true,
@@ -53,11 +59,12 @@ pub mod zfs;
/// List local disks
pub fn list_disks(
skipsmart: bool,
+ include_partitions: bool,
usage_type: Option<DiskUsageType>,
) -> Result<Vec<DiskUsageInfo>, Error> {
let mut list = Vec::new();
- for (_, info) in get_disks(None, skipsmart)? {
+ for (_, info) in get_disks(None, skipsmart, include_partitions)? {
if let Some(ref usage_type) = usage_type {
if info.used == *usage_type {
list.push(info);
@@ -140,7 +147,7 @@ pub fn initialize_disk(
let auth_id = rpcenv.get_auth_id().unwrap();
- let info = get_disk_usage_info(&disk, true)?;
+ let info = get_disk_usage_info(&disk, true, false)?;
if info.used != DiskUsageType::Unused {
bail!("disk '{}' is already in use.", disk);
diff --git a/src/api2/node/disks/zfs.rs b/src/api2/node/disks/zfs.rs
index dac6f535..5cb23e70 100644
--- a/src/api2/node/disks/zfs.rs
+++ b/src/api2/node/disks/zfs.rs
@@ -174,7 +174,7 @@ pub fn create_zpool(
.map(|v| v.as_str().unwrap().to_string())
.collect();
- let disk_map = crate::tools::disks::get_disks(None, true)?;
+ let disk_map = crate::tools::disks::get_disks(None, true, false)?;
for disk in devices.iter() {
match disk_map.get(disk) {
Some(info) => {
diff --git a/src/tools/disks/mod.rs b/src/tools/disks/mod.rs
index 568dccbf..ea4c687a 100644
--- a/src/tools/disks/mod.rs
+++ b/src/tools/disks/mod.rs
@@ -602,6 +602,26 @@ fn get_file_system_devices(lsblk_info: &[LsblkInfo]) -> Result<HashSet<u64>, Err
Ok(device_set)
}
+#[api()]
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum PartitionUsageType {
+ /// Partition is not used (as far we can tell)
+ Unused,
+ /// Partition is used by LVM
+ LVM,
+ /// Partition is used by ZFS
+ ZFS,
+ /// Partition is ZFS reserved
+ ZfsReserved,
+ /// Partition is an EFI partition
+ EFI,
+ /// Partition is a BIOS partition
+ BIOS,
+ /// Partition contains a file system label
+ FileSystem,
+}
+
#[api()]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
@@ -622,6 +642,27 @@ pub enum DiskUsageType {
FileSystem,
}
+#[api()]
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Baisc information about a partition
+pub struct PartitionInfo {
+ /// The partition name
+ pub name: String,
+ /// What the partition is used for
+ pub used: PartitionUsageType,
+ /// Is the partition mounted
+ pub mounted: bool,
+ /// The filesystem of the partition
+ pub filesystem: Option<String>,
+ /// The partition devpath
+ pub devpath: Option<String>,
+ /// Size in bytes
+ pub size: Option<u64>,
+ /// GPT partition
+ pub gpt: bool,
+}
+
#[api(
properties: {
used: {
@@ -632,6 +673,12 @@ pub enum DiskUsageType {
},
status: {
type: SmartStatus,
+ },
+ partitions: {
+ optional: true,
+ items: {
+ type: PartitionInfo
+ }
}
}
)]
@@ -656,6 +703,8 @@ pub struct DiskUsageInfo {
pub size: u64,
/// Serisal number
pub serial: Option<String>,
+ /// Partitions on the device
+ pub partitions: Option<Vec<PartitionInfo>>,
/// Linux device path (/dev/xxx)
pub devpath: Option<String>,
/// Set if disk contains a GPT partition table
@@ -733,10 +782,14 @@ fn scan_partitions(
}
/// Get disk usage information for a single disk
-pub fn get_disk_usage_info(disk: &str, no_smart: bool) -> Result<DiskUsageInfo, Error> {
+pub fn get_disk_usage_info(
+ disk: &str,
+ no_smart: bool,
+ include_partitions: bool,
+) -> Result<DiskUsageInfo, Error> {
let mut filter = Vec::new();
filter.push(disk.to_string());
- let mut map = get_disks(Some(filter), no_smart)?;
+ let mut map = get_disks(Some(filter), no_smart, include_partitions)?;
if let Some(info) = map.remove(disk) {
Ok(info)
} else {
@@ -744,12 +797,72 @@ pub fn get_disk_usage_info(disk: &str, no_smart: bool) -> Result<DiskUsageInfo,
}
}
+fn get_partitions_info(
+ partitions: HashMap<u64, Disk>,
+ lvm_devices: &HashSet<u64>,
+ zfs_devices: &HashSet<u64>,
+ file_system_devices: &HashSet<u64>,
+) -> Vec<PartitionInfo> {
+ let lsblk_infos = get_lsblk_info().ok();
+ partitions
+ .iter()
+ .map(|(_nr, disk)| {
+ let devpath = disk
+ .device_path()
+ .map(|p| p.to_owned())
+ .map(|p| p.to_string_lossy().to_string());
+
+ let mut used = PartitionUsageType::Unused;
+
+ if let Some(devnum) = disk.devnum().ok() {
+ if lvm_devices.contains(&devnum) {
+ used = PartitionUsageType::LVM;
+ } else if zfs_devices.contains(&devnum) {
+ used = PartitionUsageType::ZFS;
+ } else if file_system_devices.contains(&devnum) {
+ used = PartitionUsageType::FileSystem;
+ }
+ }
+
+ let mounted = disk.is_mounted().unwrap_or(false);
+ let mut filesystem = None;
+ if let (Some(devpath), Some(infos)) = (devpath.as_ref(), lsblk_infos.as_ref()) {
+ for info in infos.iter().filter(|i| i.path.eq(devpath)) {
+ used = match info.partition_type.as_deref() {
+ Some("21686148-6449-6e6f-744e-656564454649") => PartitionUsageType::BIOS,
+ Some("c12a7328-f81f-11d2-ba4b-00a0c93ec93b") => PartitionUsageType::EFI,
+ Some("6a945a3b-1dd2-11b2-99a6-080020736631") => {
+ PartitionUsageType::ZfsReserved
+ }
+ _ => used,
+ };
+ if used == PartitionUsageType::FileSystem {
+ filesystem = info.file_system_type.clone();
+ }
+ }
+ }
+
+ PartitionInfo {
+ name: disk.sysname().to_str().unwrap_or("?").to_string(),
+ devpath,
+ used,
+ mounted,
+ filesystem,
+ size: disk.size().ok(),
+ gpt: disk.has_gpt(),
+ }
+ })
+ .collect()
+}
+
/// Get disk usage information for multiple disks
pub fn get_disks(
// filter - list of device names (without leading /dev)
disks: Option<Vec<String>>,
// do no include data from smartctl
no_smart: bool,
+ // include partitions
+ include_partitions: bool,
) -> Result<HashMap<String, DiskUsageInfo>, Error> {
let disk_manager = DiskManage::new();
@@ -837,6 +950,19 @@ pub fn get_disks(
let wwn = disk.wwn().map(|s| s.to_string_lossy().into_owned());
+ let partitions: Option<Vec<PartitionInfo>> = if include_partitions {
+ disk.partitions().map_or(None, |parts| {
+ Some(get_partitions_info(
+ parts,
+ &lvm_devices,
+ &zfs_devices,
+ &file_system_devices,
+ ))
+ })
+ } else {
+ None
+ };
+
if usage != DiskUsageType::Mounted {
match scan_partitions(disk_manager.clone(), &lvm_devices, &zfs_devices, &name) {
Ok(part_usage) => {
@@ -870,6 +996,7 @@ pub fn get_disks(
name: name.clone(),
vendor,
model,
+ partitions,
serial,
devpath,
size,
@@ -989,7 +1116,6 @@ pub fn create_file_system(disk: &Disk, fs_type: FileSystemType) -> Result<(), Er
Ok(())
}
-
/// Block device name completion helper
pub fn complete_disk_name(_arg: &str, _param: &HashMap<String, String>) -> Vec<String> {
let dir =
--
2.30.2
More information about the pbs-devel
mailing list