diff --git a/harmony_inventory_agent/src/hwinfo.rs b/harmony_inventory_agent/src/hwinfo.rs index 5cea184..c1b32bd 100644 --- a/harmony_inventory_agent/src/hwinfo.rs +++ b/harmony_inventory_agent/src/hwinfo.rs @@ -115,82 +115,79 @@ impl PhysicalHost { ]) .output() && output.status.success() - && let Ok(json) = serde_json::from_slice::(&output.stdout) - && let Some(blockdevices) = json.get("blockdevices").and_then(|v| v.as_array()) - { - for device in blockdevices { - let name = device - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string(); - if name.is_empty() { - continue; - } + && let Ok(json) = serde_json::from_slice::(&output.stdout) + && let Some(blockdevices) = json.get("blockdevices").and_then(|v| v.as_array()) + { + for device in blockdevices { + let name = device + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string(); + if name.is_empty() { + continue; + } - let model = device - .get("model") - .and_then(|v| v.as_str()) - .map(|s| s.trim().to_string()) - .unwrap_or_default(); + let model = device + .get("model") + .and_then(|v| v.as_str()) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); - let serial = device - .get("serial") - .and_then(|v| v.as_str()) - .map(|s| s.trim().to_string()) - .unwrap_or_default(); + let serial = device + .get("serial") + .and_then(|v| v.as_str()) + .map(|s| s.trim().to_string()) + .unwrap_or_default(); - let size_str = - device.get("size").and_then(|v| v.as_str()).unwrap_or("0"); - let size_bytes = Self::parse_size(size_str).unwrap_or(0); + let size_str = device.get("size").and_then(|v| v.as_str()).unwrap_or("0"); + let size_bytes = Self::parse_size(size_str).unwrap_or(0); - let rotational = device - .get("rota") - .and_then(|v| v.as_bool()) - .unwrap_or(false); + let rotational = device + .get("rota") + .and_then(|v| v.as_bool()) + .unwrap_or(false); - let wwn = device - .get("wwn") - .and_then(|v| v.as_str()) - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty() && s != "null"); + let wwn = device + .get("wwn") + .and_then(|v| v.as_str()) + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty() && s != "null"); - let device_path = Path::new("/sys/block").join(&name); + let device_path = Path::new("/sys/block").join(&name); - let mut drive = StorageDrive { - name: name.clone(), - model, - serial, - size_bytes, - logical_block_size: Self::read_sysfs_u32( - &device_path.join("queue/logical_block_size"), - ) - .unwrap_or(512), - physical_block_size: Self::read_sysfs_u32( - &device_path.join("queue/physical_block_size"), - ) - .unwrap_or(512), - rotational, - wwn, - interface_type: Self::get_interface_type(&name, &device_path), - smart_status: Self::get_smart_status(&name), - }; + let mut drive = StorageDrive { + name: name.clone(), + model, + serial, + size_bytes, + logical_block_size: Self::read_sysfs_u32( + &device_path.join("queue/logical_block_size"), + ) + .unwrap_or(512), + physical_block_size: Self::read_sysfs_u32( + &device_path.join("queue/physical_block_size"), + ) + .unwrap_or(512), + rotational, + wwn, + interface_type: Self::get_interface_type(&name, &device_path), + smart_status: Self::get_smart_status(&name), + }; - // Enhance with additional sysfs info if available - if device_path.exists() { - if drive.model.is_empty() { - drive.model = - Self::read_sysfs_string(&device_path.join("device/model")); - } - if drive.serial.is_empty() { - drive.serial = - Self::read_sysfs_string(&device_path.join("device/serial")); - } - } - - drives.push(drive); - } + // Enhance with additional sysfs info if available + if device_path.exists() { + if drive.model.is_empty() { + drive.model = Self::read_sysfs_string(&device_path.join("device/model")); } + if drive.serial.is_empty() { + drive.serial = Self::read_sysfs_string(&device_path.join("device/serial")); + } + } + + drives.push(drive); + } + } drives } @@ -206,55 +203,58 @@ impl PhysicalHost { .args(["-nn", "-d", "::0100", "-J"]) // Storage controllers class with JSON .output() && output.status.success() - && let Ok(json) = serde_json::from_slice::(&output.stdout) - && let Some(devices) = json.as_array() { - for device in devices { - if let Some(device_info) = device.as_object() - && let Some(name) = device_info - .get("device") - .and_then(|v| v.as_object()) - .and_then(|v| v.get("name")) - .and_then(|v| v.as_str()) - { - controller.name = name.to_string(); - break; - } - } - } + && let Ok(json) = serde_json::from_slice::(&output.stdout) + && let Some(devices) = json.as_array() + { + for device in devices { + if let Some(device_info) = device.as_object() + && let Some(name) = device_info + .get("device") + .and_then(|v| v.as_object()) + .and_then(|v| v.get("name")) + .and_then(|v| v.as_str()) + { + controller.name = name.to_string(); + break; + } + } + } // Fallback to text output if JSON fails if controller.name == "Unknown" && let Ok(output) = Command::new("lspci") .args(["-nn", "-d", "::0100"]) // Storage controllers class .output() - && output.status.success() { - let output_str = String::from_utf8_lossy(&output.stdout); - if let Some(line) = output_str.lines().next() { - let parts: Vec<&str> = line.split(':').collect(); - if parts.len() > 2 { - controller.name = parts[2].trim().to_string(); - } - } + && output.status.success() + { + let output_str = String::from_utf8_lossy(&output.stdout); + if let Some(line) = output_str.lines().next() { + let parts: Vec<&str> = line.split(':').collect(); + if parts.len() > 2 { + controller.name = parts[2].trim().to_string(); } + } + } // Try to get driver info from lsmod if let Ok(output) = Command::new("lsmod").output() - && output.status.success() { - let output_str = String::from_utf8_lossy(&output.stdout); - for line in output_str.lines() { - if line.contains("ahci") - || line.contains("nvme") - || line.contains("megaraid") - || line.contains("mpt3sas") - { - let parts: Vec<&str> = line.split_whitespace().collect(); - if !parts.is_empty() { - controller.driver = parts[0].to_string(); - break; - } + && output.status.success() + { + let output_str = String::from_utf8_lossy(&output.stdout); + for line in output_str.lines() { + if line.contains("ahci") + || line.contains("nvme") + || line.contains("megaraid") + || line.contains("mpt3sas") + { + let parts: Vec<&str> = line.split_whitespace().collect(); + if !parts.is_empty() { + controller.driver = parts[0].to_string(); + break; } } } + } controller } @@ -263,53 +263,55 @@ impl PhysicalHost { let mut modules = Vec::new(); if let Ok(output) = Command::new("dmidecode").arg("--type").arg("17").output() - && output.status.success() { - let output_str = String::from_utf8_lossy(&output.stdout); - let sections: Vec<&str> = output_str.split("Memory Device").collect(); + && output.status.success() + { + let output_str = String::from_utf8_lossy(&output.stdout); + let sections: Vec<&str> = output_str.split("Memory Device").collect(); - for section in sections.into_iter().skip(1) { - let mut module = MemoryModule { - size_bytes: 0, - speed_mhz: None, - manufacturer: None, - part_number: None, - serial_number: None, - rank: None, - }; + for section in sections.into_iter().skip(1) { + let mut module = MemoryModule { + size_bytes: 0, + speed_mhz: None, + manufacturer: None, + part_number: None, + serial_number: None, + rank: None, + }; - for line in section.lines() { - let line = line.trim(); - if let Some(size_str) = line.strip_prefix("Size: ") { - if size_str != "No Module Installed" - && let Some((num, unit)) = size_str.split_once(' ') - && let Ok(num) = num.parse::() { - module.size_bytes = match unit { - "MB" => num * 1024 * 1024, - "GB" => num * 1024 * 1024 * 1024, - "KB" => num * 1024, - _ => 0, - }; - } - } else if let Some(speed_str) = line.strip_prefix("Speed: ") { - if let Some((num, _unit)) = speed_str.split_once(' ') { - module.speed_mhz = num.parse().ok(); - } - } else if let Some(man) = line.strip_prefix("Manufacturer: ") { - module.manufacturer = Some(man.to_string()); - } else if let Some(part) = line.strip_prefix("Part Number: ") { - module.part_number = Some(part.to_string()); - } else if let Some(serial) = line.strip_prefix("Serial Number: ") { - module.serial_number = Some(serial.to_string()); - } else if let Some(rank) = line.strip_prefix("Rank: ") { - module.rank = rank.parse().ok(); + for line in section.lines() { + let line = line.trim(); + if let Some(size_str) = line.strip_prefix("Size: ") { + if size_str != "No Module Installed" + && let Some((num, unit)) = size_str.split_once(' ') + && let Ok(num) = num.parse::() + { + module.size_bytes = match unit { + "MB" => num * 1024 * 1024, + "GB" => num * 1024 * 1024 * 1024, + "KB" => num * 1024, + _ => 0, + }; } - } - - if module.size_bytes > 0 { - modules.push(module); + } else if let Some(speed_str) = line.strip_prefix("Speed: ") { + if let Some((num, _unit)) = speed_str.split_once(' ') { + module.speed_mhz = num.parse().ok(); + } + } else if let Some(man) = line.strip_prefix("Manufacturer: ") { + module.manufacturer = Some(man.to_string()); + } else if let Some(part) = line.strip_prefix("Part Number: ") { + module.part_number = Some(part.to_string()); + } else if let Some(serial) = line.strip_prefix("Serial Number: ") { + module.serial_number = Some(serial.to_string()); + } else if let Some(rank) = line.strip_prefix("Rank: ") { + module.rank = rank.parse().ok(); } } + + if module.size_bytes > 0 { + modules.push(module); + } } + } modules } @@ -518,51 +520,51 @@ impl PhysicalHost { .args(["-j", "-4", "addr", "show", iface_name]) .output() && output.status.success() - && let Ok(json) = serde_json::from_slice::(&output.stdout) - && let Some(addrs) = json.as_array() { - for addr_info in addrs { - if let Some(addr_info_obj) = addr_info.as_object() - && let Some(addr_info) = - addr_info_obj.get("addr_info").and_then(|v| v.as_array()) - { - for addr in addr_info { - if let Some(addr_obj) = addr.as_object() - && let Some(ip) = - addr_obj.get("local").and_then(|v| v.as_str()) - { - ipv4.push(ip.to_string()); - } - } - } + && let Ok(json) = serde_json::from_slice::(&output.stdout) + && let Some(addrs) = json.as_array() + { + for addr_info in addrs { + if let Some(addr_info_obj) = addr_info.as_object() + && let Some(addr_info) = + addr_info_obj.get("addr_info").and_then(|v| v.as_array()) + { + for addr in addr_info { + if let Some(addr_obj) = addr.as_object() + && let Some(ip) = addr_obj.get("local").and_then(|v| v.as_str()) + { + ipv4.push(ip.to_string()); } } + } + } + } // Get IPv6 addresses using JSON output if let Ok(output) = Command::new("ip") .args(["-j", "-6", "addr", "show", iface_name]) .output() && output.status.success() - && let Ok(json) = serde_json::from_slice::(&output.stdout) - && let Some(addrs) = json.as_array() { - for addr_info in addrs { - if let Some(addr_info_obj) = addr_info.as_object() - && let Some(addr_info) = - addr_info_obj.get("addr_info").and_then(|v| v.as_array()) - { - for addr in addr_info { - if let Some(addr_obj) = addr.as_object() - && let Some(ip) = - addr_obj.get("local").and_then(|v| v.as_str()) - { - // Skip link-local addresses - if !ip.starts_with("fe80::") { - ipv6.push(ip.to_string()); - } - } - } - } + && let Ok(json) = serde_json::from_slice::(&output.stdout) + && let Some(addrs) = json.as_array() + { + for addr_info in addrs { + if let Some(addr_info_obj) = addr_info.as_object() + && let Some(addr_info) = + addr_info_obj.get("addr_info").and_then(|v| v.as_array()) + { + for addr in addr_info { + if let Some(addr_obj) = addr.as_object() + && let Some(ip) = addr_obj.get("local").and_then(|v| v.as_str()) + { + // Skip link-local addresses + if !ip.starts_with("fe80::") { + ipv6.push(ip.to_string()); + } } } + } + } + } (ipv4, ipv6) }