Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

308 lines
10 KiB
Python

# Copyright Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
"""Platform detection for OS, kernel, hostname, IP, and BIOS information."""
import platform
import socket
from dataclasses import dataclass
@dataclass
class PlatformInfo:
"""Platform information dataclass with OS, kernel, hostname, and BIOS details."""
os_name: str = "Unknown"
os_version: str = "Unknown"
kernel: str = "Unknown"
hostname: str = "Unknown"
architecture: str = "Unknown"
sbios: str = "Unknown"
@property
def kernel_release(self) -> str:
"""Get kernel release version (alias for kernel attribute)."""
return self.kernel
def __str__(self):
return f"{self.os_name} {self.os_version} (Kernel: {self.kernel})"
class PlatformDetector:
"""Platform detector for OS, kernel, BIOS, and network information."""
@staticmethod
def get_sbios_version() -> str:
"""Get SBIOS/BIOS version using dmidecode (Linux) or WMI (Windows).
Returns:
str: SBIOS version or "Unknown" if detection fails
Note:
Linux requires root/sudo for dmidecode; falls back to sysfs.
Windows uses WMIC or PowerShell WMI queries.
"""
import subprocess
import platform
os_type = platform.system()
# Windows detection
if os_type == "Windows":
try:
# Method 1: WMIC (Windows Management Instrumentation Command-line)
result = subprocess.run(
["wmic", "bios", "get", "smbiosbiosversion"],
capture_output=True,
text=True,
timeout=5,
shell=True,
)
if result.returncode == 0:
lines = result.stdout.strip().split("\n")
# Skip header line and get version
if len(lines) > 1:
bios_version = lines[1].strip()
if bios_version:
return bios_version
except Exception:
pass
try:
# Method 2: PowerShell WMI query
result = subprocess.run(
[
"powershell",
"-Command",
"Get-WmiObject",
"Win32_BIOS",
"|",
"Select-Object",
"-ExpandProperty",
"SMBIOSBIOSVersion",
],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
except Exception:
pass
# Linux detection
elif os_type == "Linux":
import logging
logger = logging.getLogger(__name__)
# Method 1: dmidecode (requires root/sudo)
try:
logger.debug("Trying dmidecode for SBIOS...")
result = subprocess.run(
["dmidecode", "-s", "bios-version"],
capture_output=True,
text=True,
timeout=5,
stderr=subprocess.PIPE,
)
if result.returncode == 0 and result.stdout.strip():
logger.debug(f"SBIOS from dmidecode: {result.stdout.strip()}")
return result.stdout.strip()
else:
logger.debug(
f"dmidecode failed: returncode={result.returncode}, stderr={result.stderr[:100]}"
)
except FileNotFoundError:
logger.debug("dmidecode command not found")
except (subprocess.TimeoutExpired, PermissionError) as e:
logger.debug(f"dmidecode error: {e}")
# Method 2: /sys/class/dmi/id/bios_version
try:
logger.debug("Trying /sys/class/dmi/id/bios_version...")
with open("/sys/class/dmi/id/bios_version", "r") as f:
bios_content = f.read().strip()
if bios_content:
logger.debug(f"SBIOS from sysfs: {bios_content}")
return bios_content
except FileNotFoundError:
logger.debug("/sys/class/dmi/id/bios_version not found")
except PermissionError:
logger.debug("/sys/class/dmi/id/bios_version permission denied")
except IOError as e:
logger.debug(f"/sys/class/dmi/id/bios_version error: {e}")
# Method 3: /sys/devices/virtual/dmi/id/bios_version
try:
logger.debug("Trying /sys/devices/virtual/dmi/id/bios_version...")
with open("/sys/devices/virtual/dmi/id/bios_version", "r") as f:
bios_content = f.read().strip()
if bios_content:
logger.debug(f"SBIOS from alternate sysfs: {bios_content}")
return bios_content
except FileNotFoundError:
logger.debug("/sys/devices/virtual/dmi/id/bios_version not found")
except PermissionError:
logger.debug(
"/sys/devices/virtual/dmi/id/bios_version permission denied"
)
except IOError as e:
logger.debug(f"/sys/devices/virtual/dmi/id/bios_version error: {e}")
logger.debug("All SBIOS detection methods failed")
# macOS detection
elif os_type == "Darwin":
try:
result = subprocess.run(
["system_profiler", "SPHardwareDataType"],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0:
# Parse for Boot ROM Version
import re
match = re.search(r"Boot ROM Version:\s*(.+)", result.stdout)
if match:
return match.group(1).strip()
except Exception:
pass
return "Unknown"
@staticmethod
def get_system_ip() -> str:
"""Get system's primary IP address using socket routing.
Returns:
str: IP address or '0.0.0.0' if detection fails
"""
try:
# Create a socket to determine the primary network interface
# This doesn't actually connect, just determines routing
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
try:
# Connect to a public DNS server (doesn't send data)
s.connect(("8.8.8.8", 80))
ip_address = s.getsockname()[0]
except Exception:
ip_address = "0.0.0.0"
finally:
s.close()
return ip_address
except Exception:
# Fallback: try to get IP from hostname
try:
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
# Avoid localhost
if ip_address.startswith("127."):
return "0.0.0.0"
return ip_address
except Exception:
return "0.0.0.0"
@staticmethod
def detect() -> PlatformInfo:
"""Detect complete platform information.
Returns:
PlatformInfo: Platform details including OS, kernel, hostname, and BIOS
"""
# Initialize with defaults
os_name = "Unknown"
os_version = "Unknown"
kernel = "Unknown"
hostname = "Unknown"
architecture = "Unknown"
sbios = "Unknown"
# Get OS name
try:
os_name = platform.system()
except Exception:
pass
# Get OS version
try:
if os_name == "Linux":
try:
with open("/etc/os-release", "r") as f:
os_release = f.read()
# Extract NAME and VERSION_ID
import re
name_match = re.search(r'NAME="?([^"\n]+)"?', os_release)
version_match = re.search(r'VERSION_ID="?([^"\n]+)"?', os_release)
if name_match:
os_name = name_match.group(1).strip()
if version_match:
os_version = version_match.group(1).strip()
else:
os_version = platform.release()
except Exception:
os_version = platform.release()
elif os_name == "Windows":
# Windows version detection
try:
os_version = platform.release() # e.g., "10", "11"
# Get more detailed version if available
win_ver = platform.win32_ver()
if win_ver[0]:
os_version = (
f"{win_ver[0]} {win_ver[1]}" # e.g., "10 10.0.19041"
)
except Exception:
os_version = platform.release()
elif os_name == "Darwin":
# macOS version detection
try:
os_version = platform.mac_ver()[0]
except Exception:
os_version = platform.release()
else:
os_version = platform.release()
except Exception:
pass
# Get kernel
try:
kernel = platform.release()
except Exception:
pass
# Get hostname
try:
hostname = socket.gethostname()
except Exception:
pass
# Get architecture
try:
architecture = platform.machine()
except Exception:
pass
# Get SBIOS version using helper method
try:
sbios = PlatformDetector.get_sbios_version()
except Exception:
pass
return PlatformInfo(
os_name=os_name,
os_version=os_version,
kernel=kernel,
hostname=hostname,
architecture=architecture,
sbios=sbios,
)