Compare commits
	
		
			2 Commits
		
	
	
		
			57c3b01e66
			...
			0f59f29ac4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0f59f29ac4 | |||
| 361f240762 | 
| @ -1,3 +1,8 @@ | |||||||
| Here lies all the data files required for an OKD cluster PXE boot setup. | Here lies all the data files required for an OKD cluster PXE boot setup. | ||||||
| 
 | 
 | ||||||
| This inclues ISO files, binary boot files, ipxe, etc. | This inclues ISO files, binary boot files, ipxe, etc. | ||||||
|  | 
 | ||||||
|  | TODO as of august 2025 : | ||||||
|  | 
 | ||||||
|  | - `harmony_inventory_agent` should be downloaded from official releases, this embedded version is practical for now though | ||||||
|  | - The cluster ssh key should be generated and handled by harmony with the private key saved in a secret store | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								data/pxe/okd/http_files/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								data/pxe/okd/http_files/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | harmony_inventory_agent filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9 filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/images filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/initrd.img filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/vmlinuz filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/images/efiboot.img filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/images/install.img filter=lfs diff=lfs merge=lfs -text | ||||||
|  | os/centos-stream-9/images/pxeboot filter=lfs diff=lfs merge=lfs -text | ||||||
							
								
								
									
										1
									
								
								data/pxe/okd/http_files/cluster_ssh_key.pub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/pxe/okd/http_files/cluster_ssh_key.pub
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBx6bDylvC68cVpjKfEFtLQJ/dOFi6PVS2vsIOqPDJIc jeangab@liliane2 | ||||||
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/harmony_inventory_agent
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/harmony_inventory_agent
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/efiboot.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/efiboot.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/install.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/install.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/pxeboot/vmlinuz
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/images/pxeboot/vmlinuz
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/initrd.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/initrd.img
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/vmlinuz
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/pxe/okd/http_files/os/centos-stream-9/vmlinuz
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										7
									
								
								examples/okd_pxe/ssh_example_key
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/okd_pxe/ssh_example_key
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | -----BEGIN OPENSSH PRIVATE KEY----- | ||||||
|  | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW | ||||||
|  | QyNTUxOQAAACAcemw8pbwuvHFaYynxBbS0Cf3ThYuj1Utr7CDqjwySHAAAAJikacCNpGnA | ||||||
|  | jQAAAAtzc2gtZWQyNTUxOQAAACAcemw8pbwuvHFaYynxBbS0Cf3ThYuj1Utr7CDqjwySHA | ||||||
|  | AAAECiiKk4V6Q5cVs6axDM4sjAzZn/QCZLQekmYQXS9XbEYxx6bDylvC68cVpjKfEFtLQJ | ||||||
|  | /dOFi6PVS2vsIOqPDJIcAAAAEGplYW5nYWJAbGlsaWFuZTIBAgMEBQ== | ||||||
|  | -----END OPENSSH PRIVATE KEY----- | ||||||
							
								
								
									
										1
									
								
								examples/okd_pxe/ssh_example_key.pub
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/okd_pxe/ssh_example_key.pub
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBx6bDylvC68cVpjKfEFtLQJ/dOFi6PVS2vsIOqPDJIc jeangab@liliane2 | ||||||
| @ -30,7 +30,7 @@ echo "Configuring kernel boot arguments..." | |||||||
| # - inst.ks:                CRITICAL: Points to our Kickstart file for automation. | # - inst.ks:                CRITICAL: Points to our Kickstart file for automation. | ||||||
| # - ip=dhcp:                Ensures the live environment configures its network. | # - ip=dhcp:                Ensures the live environment configures its network. | ||||||
| # - console=...:            Provides boot output on both serial and graphical consoles for debugging. | # - console=...:            Provides boot output on both serial and graphical consoles for debugging. | ||||||
| imgargs vmlinuz initrd=initrd.img inst.stage2=${os_base_url} inst.ks=${ks_url} ip=dhcp console=ttyS0,115200 console=tty1 | imgargs vmlinuz initrd=initrd.img inst.sshd inst.stage2=${os_base_url} inst.ks=${ks_url} ip=dhcp console=ttyS0,115200 console=tty1 | ||||||
| 
 | 
 | ||||||
| echo "Booting into CentOS Stream 9 live environment..." | echo "Booting into CentOS Stream 9 live environment..." | ||||||
| boot || goto failed | boot || goto failed | ||||||
|  | |||||||
| @ -1,66 +1,38 @@ | |||||||
| # ================================================================= | # --- Pre-Boot Scripting (The Main Goal) --- | ||||||
| #  Harmony Discovery Agent - Kickstart File (inventory.kickstart) |  | ||||||
| # ================================================================= |  | ||||||
| # |  | ||||||
| # This Kickstart file configures the CentOS Stream 9 live environment. |  | ||||||
| # It does NOT install to disk. It sets up SSH for remote access |  | ||||||
| # and downloads and runs the harmony-inventory-agent. |  | ||||||
| # |  | ||||||
| 
 |  | ||||||
| # --- System Configuration |  | ||||||
| lang en_US.UTF-8 |  | ||||||
| keyboard --xlayouts='us' |  | ||||||
| timezone America/New_York --isUtc |  | ||||||
| 
 |  | ||||||
| # --- Network Configuration |  | ||||||
| # Ensure the network is activated using DHCP. |  | ||||||
| network --bootproto=dhcp --device=link --activate |  | ||||||
| 
 |  | ||||||
| # --- Security Configuration |  | ||||||
| # Disable the firewall for this isolated provisioning network. |  | ||||||
| firewall --disabled |  | ||||||
| # Disable SELinux for simplicity in the live environment. |  | ||||||
| selinux --disabled |  | ||||||
| # Disable password-based root login for security. |  | ||||||
| rootpw --lock |  | ||||||
| 
 |  | ||||||
| # --- Service Configuration |  | ||||||
| # Ensure the SSH daemon is enabled. |  | ||||||
| services --enabled="sshd" |  | ||||||
| 
 |  | ||||||
| # We are running a live environment, so no disk partitioning. |  | ||||||
| # The 'liveimg' command would be used here if booting from a squashfs, |  | ||||||
| # but since we are booting from kernel/initrd, we just use the %post. |  | ||||||
| 
 |  | ||||||
| # Do not run the graphical initial setup wizard. |  | ||||||
| firstboot --disable |  | ||||||
| 
 |  | ||||||
| # --- Post-Boot Scripting |  | ||||||
| # This section runs after the live environment has booted into RAM. | # This section runs after the live environment has booted into RAM. | ||||||
| %post --log=/root/ks-post.log | # It sets up SSH and downloads/runs the harmony-inventory-agent. | ||||||
|  | %pre --log=/root/ks-pre.log | ||||||
| 
 | 
 | ||||||
| echo "Harmony Kickstart: Post-boot script started." | echo "Harmony Kickstart: Pre-boot script started." | ||||||
| 
 | 
 | ||||||
| # 1. Configure SSH Access | # 1. Configure SSH Access for Root | ||||||
| # Create the .ssh directory and set correct permissions. | # Create the .ssh directory and set correct permissions. | ||||||
| echo "  - Setting up SSH authorized_keys..." | echo "  - Setting up SSH authorized_keys for root..." | ||||||
| mkdir -p /root/.ssh | mkdir -p /root/.ssh | ||||||
| chmod 700 /root/.ssh | chmod 700 /root/.ssh | ||||||
| 
 | 
 | ||||||
| # Download the public key and place it in authorized_keys. | # Download the public key from the provisioning server. | ||||||
| curl -sSL "http://{{ gateway_ip }}:8080/{{ cluster_pubkey_filename }}" -o /root/.ssh/authorized_keys | # The -sS flags make curl silent but show errors. -L follows redirects. | ||||||
| chmod 600 /root/.ssh/authorized_keys | curl -vSL "http://{{ gateway_ip }}:8080/{{ cluster_pubkey_filename }}" -o /root/.ssh/authorized_keys | ||||||
| 
 | if [ $? -ne 0 ]; then | ||||||
| # SELinux context is handled by 'selinux --disabled' above, |     echo "  - ERROR: Failed to download SSH public key." | ||||||
| # but if SELinux were enabled, this would be essential: | else | ||||||
| # restorecon -R /root/.ssh |     echo "  - SSH key downloaded successfully." | ||||||
|  |     chmod 600 /root/.ssh/authorized_keys | ||||||
|  | fi | ||||||
| 
 | 
 | ||||||
| # 2. Download the Harmony Inventory Agent | # 2. Download the Harmony Inventory Agent | ||||||
| echo "  - Downloading harmony-inventory-agent..." | echo "  - Downloading harmony-inventory-agent..." | ||||||
| curl -sSL "http://{{ gateway_ip }}:8080/{{ harmony_inventory_agent }}" -o /usr/local/bin/harmony-inventory-agent | curl -vSL "http://{{ gateway_ip }}:8080/{{ harmony_inventory_agent }}" -o /usr/bin/harmony-inventory-agent | ||||||
| chmod +x /usr/local/bin/harmony-inventory-agent | if [ $? -ne 0 ]; then | ||||||
|  |     echo "  - ERROR: Failed to download harmony_inventory_agent." | ||||||
|  | else | ||||||
|  |     echo "  - Agent binary downloaded successfully." | ||||||
|  |     chmod +x /usr/bin/harmony-inventory-agent | ||||||
|  | fi | ||||||
| 
 | 
 | ||||||
| # 3. Create a systemd service to run the agent persistently | # 3. Create a systemd service to run the agent persistently. | ||||||
|  | # This is the most robust method to ensure the agent stays running. | ||||||
| echo "  - Creating systemd service for the agent..." | echo "  - Creating systemd service for the agent..." | ||||||
| cat > /etc/systemd/system/harmony-agent.service << EOF | cat > /etc/systemd/system/harmony-agent.service << EOF | ||||||
| [Unit] | [Unit] | ||||||
| @ -69,8 +41,9 @@ After=network-online.target | |||||||
| Wants=network-online.target | Wants=network-online.target | ||||||
| 
 | 
 | ||||||
| [Service] | [Service] | ||||||
| ExecStart=/usr/local/bin/harmony-inventory-agent | Type=simple | ||||||
| Restart=always | ExecStart=/usr/bin/harmony-inventory-agent | ||||||
|  | Restart=on-failure | ||||||
| RestartSec=5 | RestartSec=5 | ||||||
| 
 | 
 | ||||||
| [Install] | [Install] | ||||||
| @ -78,15 +51,77 @@ WantedBy=multi-user.target | |||||||
| EOF | EOF | ||||||
| 
 | 
 | ||||||
| # 4. Enable and start the service | # 4. Enable and start the service | ||||||
|  | # The 'systemctl' commands will work correctly within the chroot environment of the %pre script. | ||||||
| echo "  - Enabling and starting harmony-agent.service..." | echo "  - Enabling and starting harmony-agent.service..." | ||||||
| systemctl daemon-reload | systemctl daemon-reload | ||||||
| systemctl enable --now harmony-agent.service | systemctl enable --now harmony-agent.service | ||||||
| 
 | 
 | ||||||
| echo "Harmony Kickstart: Post-boot script finished. The inventory agent is running." | # Check if the service started correctly | ||||||
|  | systemctl is-active --quiet harmony-agent.service | ||||||
|  | if [ $? -eq 0 ]; then | ||||||
|  |     echo "  - Harmony Inventory Agent service is now running." | ||||||
|  | else | ||||||
|  |     echo "  - ERROR: Harmony Inventory Agent service failed to start." | ||||||
|  | fi | ||||||
| 
 | 
 | ||||||
| curl localhost:8080/inventory | tee -a /tmp/harmony_inventory.json | echo "Harmony Kickstart: Pre-boot script finished. The machine is ready for inventory." | ||||||
|  | 
 | ||||||
|  | echo "Running cat - to pause system indefinitely" | ||||||
|  | cat - | ||||||
| 
 | 
 | ||||||
| %end | %end | ||||||
| 
 | 
 | ||||||
| # Do not automatically reboot or poweroff. | # ================================================================= | ||||||
| # The machine should remain running for inventory scraping. | #  Harmony Discovery Agent - Kickstart File (NON-INSTALL, LIVE BOOT) | ||||||
|  | # ================================================================= | ||||||
|  | # | ||||||
|  | # This file achieves a fully automated, non-interactive boot into a | ||||||
|  | # live CentOS environment. It does NOT install to disk. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # --- Automation and Interaction Control --- | ||||||
|  | # Perform the installation in command-line mode. This is critical for | ||||||
|  | # preventing Anaconda from starting a UI and halting for input. | ||||||
|  | cmdline | ||||||
|  | 
 | ||||||
|  | # Accept the End User License Agreement to prevent a prompt. | ||||||
|  | eula --agreed | ||||||
|  | 
 | ||||||
|  | # --- Core System Configuration (Required by Anaconda) --- | ||||||
|  | # Set keyboard and language. These are mandatory. | ||||||
|  | keyboard --vckeymap=us --xlayouts='us' | ||||||
|  | lang en_US.UTF-8 | ||||||
|  | 
 | ||||||
|  | # Configure networking. This is essential for the %post script to work. | ||||||
|  | # The --activate flag ensures this device is brought up in the installer environment. | ||||||
|  | network --bootproto=dhcp --device=link --activate | ||||||
|  | 
 | ||||||
|  | # Set a locked root password. This is a mandatory command. | ||||||
|  | rootpw --lock | ||||||
|  | 
 | ||||||
|  | # Set the timezone. This is a mandatory command. | ||||||
|  | timezone UTC | ||||||
|  | 
 | ||||||
|  | # --- Disable Installation-Specific Features --- | ||||||
|  | # CRITICAL: Do not install a bootloader. The --disabled flag prevents | ||||||
|  | # this step and avoids errors about where to install it. | ||||||
|  | bootloader --disabled | ||||||
|  | 
 | ||||||
|  | # CRITICAL: Ignore all disks. This prevents Anaconda from stopping at the | ||||||
|  | # "Installation Destination" screen asking where to install. | ||||||
|  | # ignoredisk --drives /dev/sda | ||||||
|  | 
 | ||||||
|  | # Do not run the Initial Setup wizard on first boot. | ||||||
|  | firstboot --disable | ||||||
|  | 
 | ||||||
|  | # --- Package Selection --- | ||||||
|  | # We are not installing, so this section can be minimal. | ||||||
|  | # An empty %packages section is valid and ensures no time is wasted | ||||||
|  | # resolving dependencies for an installation that will not happen. | ||||||
|  | %packages | ||||||
|  | %end | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # IMPORTANT: Do not include a final action command like 'reboot' or 'poweroff'. | ||||||
|  | # The default action is 'halt', which in cmdline mode will leave the system | ||||||
|  | # running in the live environment with the agent active, which is the desired state. | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| use log::debug; | use log::{debug, warn}; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use serde_json::Value; | use serde_json::Value; | ||||||
| use std::fs; | use std::fs; | ||||||
| @ -104,48 +104,58 @@ impl PhysicalHost { | |||||||
| 
 | 
 | ||||||
|     fn all_tools_available() -> Result<(), String> { |     fn all_tools_available() -> Result<(), String> { | ||||||
|         let required_tools = [ |         let required_tools = [ | ||||||
|             ("lsblk", "--version"), |             ("lsblk", Some("--version")), | ||||||
|             ("lspci", "--version"), |             ("lspci", Some("--version")), | ||||||
|             ("lsmod", "--version"), |             ("lsmod", None), | ||||||
|             ("dmidecode", "--version"), |             ("dmidecode", Some("--version")), | ||||||
|             ("smartctl", "--version"), |             ("smartctl", Some("--version")), | ||||||
|             ("ip", "route"), // No version flag available
 |             ("ip", Some("route")), // No version flag available
 | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         let mut missing_tools = Vec::new(); |         let mut missing_tools = Vec::new(); | ||||||
| 
 | 
 | ||||||
|  |         debug!("Looking for required_tools {required_tools:?}"); | ||||||
|         for (tool, tool_arg) in required_tools.iter() { |         for (tool, tool_arg) in required_tools.iter() { | ||||||
|             // First check if tool exists in PATH using which(1)
 |             // First check if tool exists in PATH using which(1)
 | ||||||
|             let exists = if let Ok(output) = Command::new("which").arg(tool).output() { |             let mut exists = if let Ok(output) = Command::new("which").arg(tool).output() { | ||||||
|                 output.status.success() |                 output.status.success() | ||||||
|             } else { |             } else { | ||||||
|                 // Fallback: manual PATH search if which(1) is unavailable
 |                 false | ||||||
|                 if let Ok(path_var) = std::env::var("PATH") { |  | ||||||
|                     path_var.split(':').any(|dir| { |  | ||||||
|                         let tool_path = std::path::Path::new(dir).join(tool); |  | ||||||
|                         tool_path.exists() && Self::is_executable(&tool_path) |  | ||||||
|                     }) |  | ||||||
|                 } else { |  | ||||||
|                     false |  | ||||||
|                 } |  | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             if !exists { |             if !exists { | ||||||
|  |                 // Fallback: manual PATH search if which(1) is unavailable
 | ||||||
|  |                 debug!("Looking for {tool} in path"); | ||||||
|  |                 if let Ok(path_var) = std::env::var("PATH") { | ||||||
|  |                     debug!("PATH is {path_var}"); | ||||||
|  |                     exists = path_var.split(':').any(|dir| { | ||||||
|  |                         let tool_path = std::path::Path::new(dir).join(tool); | ||||||
|  |                         tool_path.exists() && Self::is_executable(&tool_path) | ||||||
|  |                     }) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if !exists { | ||||||
|  |                 warn!("Unable to find tool {tool} from PATH"); | ||||||
|                 missing_tools.push(*tool); |                 missing_tools.push(*tool); | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // Verify tool is functional by checking version/help output
 |             // Verify tool is functional by checking version/help output
 | ||||||
|             let mut cmd = Command::new(tool); |             let mut cmd = Command::new(tool); | ||||||
|             cmd.arg(tool_arg); |             if let Some(tool_arg) = tool_arg { | ||||||
|  |                 cmd.arg(tool_arg); | ||||||
|  |             } | ||||||
|             cmd.stdout(std::process::Stdio::null()); |             cmd.stdout(std::process::Stdio::null()); | ||||||
|             cmd.stderr(std::process::Stdio::null()); |             cmd.stderr(std::process::Stdio::null()); | ||||||
| 
 | 
 | ||||||
|             if let Ok(status) = cmd.status() { |             if let Ok(status) = cmd.status() { | ||||||
|                 if !status.success() { |                 if !status.success() { | ||||||
|  |                     warn!("Unable to test {tool} status failed"); | ||||||
|                     missing_tools.push(*tool); |                     missing_tools.push(*tool); | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|  |                 warn!("Unable to test {tool}"); | ||||||
|                 missing_tools.push(*tool); |                 missing_tools.push(*tool); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -167,6 +177,7 @@ impl PhysicalHost { | |||||||
| 
 | 
 | ||||||
|     #[cfg(unix)] |     #[cfg(unix)] | ||||||
|     fn is_executable(path: &std::path::Path) -> bool { |     fn is_executable(path: &std::path::Path) -> bool { | ||||||
|  |         debug!("Checking if {} is executable", path.to_string_lossy()); | ||||||
|         use std::os::unix::fs::PermissionsExt; |         use std::os::unix::fs::PermissionsExt; | ||||||
| 
 | 
 | ||||||
|         match std::fs::metadata(path) { |         match std::fs::metadata(path) { | ||||||
| @ -285,11 +296,11 @@ impl PhysicalHost { | |||||||
|             if device_path.exists() { |             if device_path.exists() { | ||||||
|                 if drive.model.is_empty() { |                 if drive.model.is_empty() { | ||||||
|                     drive.model = Self::read_sysfs_string(&device_path.join("device/model")) |                     drive.model = Self::read_sysfs_string(&device_path.join("device/model")) | ||||||
|                         .map_err(|e| format!("Failed to read model for {}: {}", name, e))?; |                         .unwrap_or(format!("Failed to read model for {}", name)); | ||||||
|                 } |                 } | ||||||
|                 if drive.serial.is_empty() { |                 if drive.serial.is_empty() { | ||||||
|                     drive.serial = Self::read_sysfs_string(&device_path.join("device/serial")) |                     drive.serial = Self::read_sysfs_string(&device_path.join("device/serial")) | ||||||
|                         .map_err(|e| format!("Failed to read serial for {}: {}", name, e))?; |                         .unwrap_or(format!("Failed to read serial for {}", name)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -655,6 +666,10 @@ impl PhysicalHost { | |||||||
|             Ok("IDE".to_string()) |             Ok("IDE".to_string()) | ||||||
|         } else if device_name.starts_with("vd") { |         } else if device_name.starts_with("vd") { | ||||||
|             Ok("VirtIO".to_string()) |             Ok("VirtIO".to_string()) | ||||||
|  |         } else if device_name.starts_with("sr") { | ||||||
|  |             Ok("CDROM".to_string()) | ||||||
|  |         } else if device_name.starts_with("zram") { | ||||||
|  |             Ok("Ramdisk".to_string()) | ||||||
|         } else { |         } else { | ||||||
|             // Try to determine from device path
 |             // Try to determine from device path
 | ||||||
|             let subsystem = Self::read_sysfs_string(&device_path.join("device/subsystem"))?; |             let subsystem = Self::read_sysfs_string(&device_path.join("device/subsystem"))?; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user