Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 110 additions & 18 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,12 @@ def format_attr(attr, value):

def run_command(cmd, check=True, **kwargs):
import subprocess
from test.support import has_subprocess_support

if not has_subprocess_support:
# subprocess is not supported by the current platform
return ''

timeout = COMMAND_TIMEOUT

cmd_str = ' '.join(cmd)
Expand Down Expand Up @@ -963,6 +969,24 @@ def winreg_query(path):
return None


def wmi_query(query):
try:
import _wmi
except ImportError:
return {}

try:
data = _wmi.exec_query(query)
except OSError:
return {}

dict_data = {}
for item in data.split("\0"):
key, _, value = item.partition("=")
dict_data[key] = value
return dict_data


def collect_windows(info_add):
if not MS_WINDOWS:
# Code specific to Windows
Expand Down Expand Up @@ -1009,22 +1033,14 @@ def collect_windows(info_add):
call_func(info_add, 'windows.ansi_code_page', _winapi, 'GetACP')
call_func(info_add, 'windows.oem_code_page', _winapi, 'GetOEMCP')

# windows.version_caption: "wmic os get Caption,Version /value" command
output = run_command(["wmic", "os", "get", "Caption,Version", "/value"],
# When wmic.exe output is redirected to a pipe,
# it uses the OEM code page
encoding="oem")
if output:
for line in output.splitlines():
line = line.strip()
if line.startswith('Caption='):
line = line.removeprefix('Caption=').strip()
if line:
info_add('windows.version_caption', line)
elif line.startswith('Version='):
line = line.removeprefix('Version=').strip()
if line:
info_add('windows.version', line)
# Get operating system caption and version using WMI
data = wmi_query("SELECT Caption, Version FROM Win32_OperatingSystem")
caption = data.get('Caption', '')
if caption:
info_add('windows.version_caption', caption)
version = data.get('Version', '')
if version:
info_add('windows.version', version)

# windows.ver: "ver" command
output = run_command(["ver"], shell=True)
Expand Down Expand Up @@ -1142,7 +1158,83 @@ def get_machine_id():
return None


def detect_virt():
def detect_virt_windows(info_add):
# On Windows, use WMI to detect the virtualization.
#
# Microsoft Hyper-V:
# - Win32_Bios.Version = "VRTUAL - 1"
# - Win32_ComputerSystem.Model = "Virtual Machine"
# - Win32_ComputerSystem.Manufacturer = "Microsoft Corporation"
#
# VMware:
# - Win32_ComputerSystem.Model = "VMware"
# - Win32_ComputerSystem.Manufacturer = "VMware"
# - Win32_Bios.SerialNumber starts with "VMware-"
#
# QEMU:
# - Win32_ComputerSystem.Manufacturer = "QEMU"
# - Win32_ComputerSystem.Model = "Standard PC (Q35 + ICH9, 2009)"
# - Win32_Bios.Version = "BOCHS - 1"
# - Win32_Bios.Manufacturer = "EDK II"
#
# Parallels:
# - Win32_Bios.Version = "PARALLELS"
#
# VirtualBox:
# - Win32_Bios.Version = "VBOX"
# - Win32_ComputerSystem.Model = "VirtualBox"
# - Win32_ComputerSystem.Manufacturer = "innotek GmbH"

KNOWN_VIRT = (
'QEMU',
'VMware',
'VirtualBox',
'Xen',
'oVirt',
)
KNOWN_BIOS_VERSIONS = {
"VRTUAL - 1": "Microsoft Hyper-V",
"PARALLELS": "Parallels",
"VBOX": "VirtualBox",
}

computer = wmi_query("SELECT Model, Manufacturer FROM Win32_ComputerSystem")
computer_model = computer.get('Model', '')
if computer_model in KNOWN_VIRT:
return computer_model
computer_manufacturer = computer.get('Manufacturer', '')
if computer_manufacturer in KNOWN_VIRT:
return computer_manufacturer

bios = wmi_query("SELECT Version, Manufacturer FROM Win32_Bios")

bios_version = bios.get('Version', '')
if bios_version in KNOWN_VIRT:
return bios_version
try:
return KNOWN_BIOS_VERSIONS[bios_version]
except KeyError:
pass

bios_manufacturer = bios.get('Manufacturer', '')
if bios_manufacturer in KNOWN_VIRT:
return bios_manufacturer

# Log the values to update the code if a new VM is discovered
if computer_model:
info_add('system.computer.model', computer_model)
if computer_manufacturer:
info_add('system.computer.manufacturer', computer_manufacturer)
if bios_version:
info_add('system.bios.version', bios_version)
if bios_manufacturer:
info_add('system.bios.manufacturer', bios_manufacturer)


def detect_virt(info_add):
if MS_WINDOWS:
return detect_virt_windows(info_add)

# Run systemd-detect-virt command
virt = run_command(["systemd-detect-virt"], check=False)
if virt and virt != "none":
Expand Down Expand Up @@ -1200,7 +1292,7 @@ def collect_system(info_add):
uptime = f'{uptime} sec'
info_add('system.uptime', uptime)

virt = detect_virt()
virt = detect_virt(info_add)
if virt:
info_add('system.virt', virt)

Expand Down
Loading