From c26aad405f326732338f0ced76efeaa51f52b088 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 5 Jun 2020 10:00:05 +0200 Subject: [PATCH] src/tools/disks.rs: implement get_disks (similar to the one in PVE::Diskmanage) But no ceph support for now. Also no support for old cciss block devices. --- src/tools/disks.rs | 199 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/src/tools/disks.rs b/src/tools/disks.rs index 966f4946..68ef6305 100644 --- a/src/tools/disks.rs +++ b/src/tools/disks.rs @@ -562,3 +562,202 @@ pub fn get_partition_type_info() -> Result>, Error> } Ok(res) } + +#[derive(Debug, PartialEq)] +pub enum DiskUsageType { + Unused, + Mounted, + LVM, + ZFS, + DeviceMapper, + Partitions, +} + +#[derive(Debug)] +pub struct DiskUsageInfo { + pub name: String, + pub used: DiskUsageType, + pub disk_type: DiskType, + pub vendor: Option, + pub model: Option, + pub wwn: Option, + pub size: u64, + pub serial: Option, + pub devpath: Option, + pub gpt: bool, + pub rpm: Option, +} + +fn scan_partitions( + disk_manager: Arc, + lvm_devices: &HashSet, + zfs_devices: &HashSet, + device: &str, +) -> Result { + + let mut sys_path = std::path::PathBuf::from("/sys/block"); + sys_path.push(device); + + let mut used = DiskUsageType::Unused; + + let mut found_lvm = false; + let mut found_zfs = false; + let mut found_mountpoints = false; + let mut found_dm = false; + let mut found_partitions = false; + + for item in crate::tools::fs::read_subdir(libc::AT_FDCWD, &sys_path)? { + let item = item?; + let name = match item.file_name().to_str() { + Ok(name) => name, + Err(_) => continue, // skip non utf8 entries + }; + if !name.starts_with(device) { continue; } + + found_partitions = true; + + let mut part_path = sys_path.clone(); + part_path.push(name); + + let data = disk_manager.clone().disk_by_sys_path(&part_path)?; + + if lvm_devices.contains(name) { + found_lvm = true; + } + + if data.is_mounted()? { + found_mountpoints = true; + } + + if data.has_holders()? { + found_dm = true; + } + + if zfs_devices.contains(name) { + found_zfs = true; + } + } + + if found_mountpoints { + used = DiskUsageType::Mounted; + } else if found_lvm { + used = DiskUsageType::LVM; + } else if found_zfs { + used = DiskUsageType::ZFS; + } else if found_dm { + used = DiskUsageType::DeviceMapper; + } else if found_partitions { + used = DiskUsageType::Partitions; + } + + Ok(used) +} + +pub fn get_disks( + // filter - list of device names (without leading /dev) + disks: Option>, + // do no include data from smartctl + no_smart: bool, +) -> Result, Error> { + + let disk_manager = DiskManage::new(); + + let partition_type_map = get_partition_type_info()?; + + let zfs_devices = zfs_devices(&partition_type_map, None)?; + + let lvm_devices = get_lvm_devices(&partition_type_map)?; + + // fixme: ceph journals/volumes + + lazy_static::lazy_static!{ + static ref ISCSI_PATH_REGEX: regex::Regex = + regex::Regex::new(r"host[^/]*/session[^/]*").unwrap(); + static ref BLOCKDEV_REGEX: regex::Regex = + regex::Regex::new(r"^(:?(:?h|s|x?v)d[a-z]+)|(:?nvme\d+n\d+)$").unwrap(); + } + + let mut result = HashMap::new(); + + for item in crate::tools::fs::scan_subdir(libc::AT_FDCWD, "/sys/block", &BLOCKDEV_REGEX)? { + let item = item?; + + let name = item.file_name().to_str().unwrap().to_string(); + + if let Some(ref disks) = disks { + if !disks.contains(&name) { continue; } + } + + let sys_path = format!("/sys/block/{}", name); + + if let Ok(target) = std::fs::read_link(&sys_path) { + if let Some(target) = target.to_str() { + if ISCSI_PATH_REGEX.is_match(target) { continue; } // skip iSCSI devices + } + } + + let data = disk_manager.clone().disk_by_sys_path(&sys_path)?; + + let size = match data.size() { + Ok(size) => size, + Err(_) => continue, // skip devices with unreadable size + }; + + let disk_type = match data.guess_disk_type() { + Ok(disk_type) => disk_type, + Err(_) => continue, // skip devices with undetectable type + }; + + let mut usage = DiskUsageType::Unused; + + if lvm_devices.contains(&name) { + usage = DiskUsageType::LVM; + } + + match data.is_mounted() { + Ok(true) => usage = DiskUsageType::Mounted, + Ok(false) => {}, + Err(_) => continue, // skip devices with undetectable mount status + } + + if zfs_devices.contains(&name) { + usage = DiskUsageType::ZFS; + } + + let vendor = data.vendor().unwrap_or(None). + map(|s| s.to_string_lossy().trim().to_string()); + + let model = data.model().map(|s| s.to_string_lossy().into_owned()); + + let serial = data.serial().map(|s| s.to_string_lossy().into_owned()); + + let devpath = data.device_path().map(|p| p.to_owned()); + + let wwn = data.wwn().map(|s| s.to_string_lossy().into_owned()); + + if usage != DiskUsageType::Mounted { + match scan_partitions(disk_manager.clone(), &lvm_devices, &zfs_devices, &name) { + Ok(part_usage) => { + if part_usage != DiskUsageType::Unused { + usage = part_usage; + } + }, + Err(_) => continue, // skip devices if scan_partitions fail + }; + } + + let info = DiskUsageInfo { + name: name.clone(), + vendor, model, serial, devpath, size, wwn, disk_type, + used: usage, + gpt: data.has_gpt(), + rpm: data.ata_rotation_rate_rpm(), + }; + + println!("GOT {:?}", info); + + result.insert(name, info); + } + + Ok(result) +}