-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
win_guest_debugging_tool: Support new feature cases
win_guest_debugging_tool is a new feature for windows guest to gather a wide range of information. including system configuration event logs, drivers, registry settings, update logs, services, uptime, processes, installed applications,network configuration installed KBs (knowledge base articleand optionally, memory dumps It's a powershell script is designed for comprehensive system diagnostics. Signed-off-by: Dehan Meng <demeng@redhat.com>
Showing
2 changed files
with
881 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
- win_guest_debugging_tool: install setup image_copy unattended_install.cdrom | ||
only Windows | ||
type = win_guest_debugging_tool | ||
tmp_dir = %TEMP% | ||
runtimeout = 360 | ||
shutdown_command = "shutdown -s -t 0" | ||
reboot_command = "shutdown -r -t 0" | ||
cmd_unrestrict_policy = 'powershell.exe Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Force' | ||
test_tmp_dir = "%TEMP%\testtmpdir" | ||
cmd_create_dir = "mkdir %s >nul 2>&1" | ||
cmd_remove_dir = "rmdir /S /Q %s" | ||
cdroms += " virtio" | ||
cdrom_virtio = isos/windows/virtio-win.iso | ||
cmd_findstr_in_file = type %s | findstr "%s" | ||
include_sensitive_data = False | ||
target_files = "msinfo32.txt,system.evtx,security.evtx,application.evtx,drv_list.csv,virtio_disk.txt,WindowsUpdate.log,Services.csv,WindowsUptime.txt,RunningProcesses.csv,InstalledApplications.csv,InstalledKBs.csv,NetworkInterfaces.txt,IPConfiguration.txt,setupapi.dev.log,setupapi.setup.log,setupapi.offline.log,ErrorWindowsUpdate.log,OutputWindowsUpdate.log,LocaleMetaData" | ||
target_dump_files = "MEMORY.DMP,Minidump" | ||
script_name = "CollectSystemInfo.ps1" | ||
cmd_search_file_global = powershell.exe -Command "Get-PSDrive -PSProvider FileSystem | ForEach-Object { Get-ChildItem -Path $_.Root -Recurse -Filter '%s' -ErrorAction SilentlyContinue } | ForEach-Object { Join-Path -Path $_.Directory.FullName -ChildPath $_.Name }" | ||
variants: | ||
- check_script_execution: | ||
windegtool_check_type = script_execution | ||
- check_zip_package: | ||
windegtool_check_type = zip_package | ||
cmd_extract_zip = 'powershell.exe Expand-Archive -Path "%s" -DestinationPath %s -Force' | ||
cmd_check_folder_size = powershell -c "$folderPath='%s'; $folderSize=(Get-ChildItem -Path $folderPath -Recurse | Measure-Object -Property Length -Sum).Sum; Write-Output $folderSize" | ||
- check_run_tools_multi_times: | ||
windegtool_check_type = run_tools_multi_times | ||
- check_user_friendliness: | ||
windegtool_check_type = user_friendliness | ||
cmd_kill_powershell_process = taskkill /IM powershell.exe /F | ||
cmd_kill_powershell_process1 = powershell.exe -Command "Stop-Process -Name msinfo32 -Force" | ||
invalid_params = "-invalidparam,IncludeSensitiveData,0000,hell,-H,-IncludeSensitiveData -h" | ||
expect_output_prompt = "Usage: .\CollectSystemInfo.ps1 [-IncludeSensitiveData] [-Help]" | ||
script_interrupt_signal_file = 'Collecting_Status.txt' | ||
cmd_dir_del = powershell.exe -Command "Remove-Item -Path '%s' -Recurse -Force -ErrorAction SilentlyContinue" | ||
cmd_query_path = powershell.exe "$lastDir = dir | Select-String 'System*' | Select-Object -Last 1; write-output $lastDir" | ||
- check_disk_registry_collection: | ||
windegtool_check_type = disk_registry_collection | ||
virtio_disk_filepath = "%s\virtio_disk.txt" | ||
new_reg_item = "HKLM:\SYSTEM\CurrentControlSet\Services\viostor\Parameters" | ||
exist_reg_item = "HKLM:\SYSTEM\CurrentControlSet\Services\Disk" | ||
cmd_reg_query = powershell.exe -Command "(Get-ItemProperty -Path %s).%s" | ||
cmd_reg_add_item = powershell.exe "if (-not (Test-Path -Path '%s')) {New-Item -Path %s | Out-Null}" | ||
cmd_reg_add_item_key = powershell.exe "if (-not (Test-Path -Path '%s')) {New-Item -Path %s -Name %s -ItemType Key | Out-Null}" | ||
cmd_reg_set_value = powershell.exe -Command "Set-ItemProperty -Path '%s' -Name '%s' -Value %d" | ||
cmd_reg_del = powershell.exe -Command "Remove-Item -Path '%s' -Recurse -Force -ErrorAction SilentlyContinue" | ||
reg_subkey1 = IoTimeoutValue | ||
reg_subkey2 = TimeoutValue | ||
key_value1 = 100 | ||
key_value2 = 150 | ||
- check_includeSensitiveData_collection: | ||
windegtool_check_type = includeSensitiveData_collection | ||
include_sensitive_data = True | ||
timeout = 360 | ||
reboot_method = system_reset | ||
memory_dmp_file = "%SystemRoot%\Memory.dmp" | ||
mini_dmp_folder = "%SystemRoot%\Minidump" | ||
crash_method = nmi | ||
cmd_check_files = powershell.exe ls %s | ||
- check_trigger_driver_msinfo_collection: | ||
windegtool_check_type = trigger_driver_msinfo_collection | ||
image_snapshot = yes | ||
transfer_timeout = 720 | ||
msinfo_file_path = "%s\msinfo32.txt" | ||
drv_list_file_path = "%s\drv_list.csv" | ||
setupapi_dev_file_path = "%s\setupapi.dev.log" | ||
target_driver = pvpanic | ||
cmd_query_oem_inf = powershell.exe -Command "pnputil.exe /enum-drivers | Select-String -Pattern '%s.inf' -Context 1,1 | ForEach-Object { if ($_ -match 'Published Name:\s+(oem\d+\.inf)') { $matches[1] } }" | ||
cmd_install_driver = pnputil.exe /add-driver %s /install | ||
cmd_uninstall_driver = pnputil.exe /delete-driver %s /uninstall /force | ||
cmd_scan_device = pnputil.exe /scan-devices | ||
cmd_backup_driver = Export-WindowsDriver -Online -Destination "C:\DriverBackup" | ||
cmd_check_driver_ver = powershell.exe -Command "Get-WmiObject Win32_PnPSignedDriver | Where-Object DeviceName -eq '%s'" | ||
new_system_name = "NewsystemName" | ||
cmd_change_systemname = powershell.exe -Command "Rename-Computer -NewName %s" | ||
cmd_query_from_file = powershell.exe -Command "Get-Content %s | Select-String -Pattern '%s'" | ||
cmd_check_systemname = echo %computername% | ||
cmd_query_ver_vm = powershell.exe -Command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption" | ||
cmd_search_2k16_inf_file_global = powershell.exe -Command "Get-PSDrive -PSProvider FileSystem | ForEach-Object { Get-ChildItem -Path $_.Root -Recurse -Filter '%s' -ErrorAction SilentlyContinue } | ForEach-Object { Join-Path -Path $_.Directory.FullName -ChildPath $_.Name } | Where-Object { $_ -match '2k16' }" | ||
- check_networkadapter_collection: | ||
windegtool_check_type = networkadapter_collection | ||
check_adapter_name = powershell.exe -Command "Get-NetAdapter | Select-Object -ExpandProperty Name" | ||
check_adapter_jp_info = powershell.exe -Command "Get-NetAdapterAdvancedProperty -Name '%s' | Where-Object { $_.DisplayName -eq 'Jumbo Packet' } | Select-Object -ExpandProperty DisplayValue" | ||
cmd_set_adapter_jp_info = powershell.exe -Command "Set-NetAdapterAdvancedProperty -Name '%s' -DisplayName 'Jumbo Packet' -DisplayValue %d" | ||
cmd_disable_adapter = powershell.exe -Command "Disable-NetAdapter -Name '%s' -Confirm:$false" | ||
cmd_enable_adapter = powershell.exe -Command "Enable-NetAdapter -Name '%s' -Confirm:$false" | ||
networkfile_path = "%s\NetworkInterfaces.txt" | ||
ipconfigfile_path = "%s\IPConfiguration.txt" | ||
static_dns = 8.8.8.8 | ||
cmd_get_dns = powershell.exe -Command (Get-DnsClientServerAddress -AddressFamily IPv4).ServerAddresses | ||
cmd_set_dns = netsh interface ipv4 set dns name="%s" static %s | ||
cmd_set_dns_dhcp = netsh interface ipv4 set dns name="%s" dhcp | ||
- check_documentation: | ||
windegtool_check_type = documentation | ||
standard_docs = "README.md", "LICENSE", "CollectSystemInfo.ps1" | ||
target_doc = "README.md" | ||
query_cmd_from_file = powershell.exe -Command "Get-Content %s | Select-String '```powershell' -Context 0,1" | ||
cmd_cp_file = powershell.exe -Command "cp %s %s" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,782 @@ | ||
import logging | ||
import time | ||
import os | ||
import re | ||
import base64 | ||
import random | ||
import string | ||
import json | ||
import threading | ||
|
||
import aexpect | ||
|
||
from distutils.util import strtobool | ||
from avocado.utils import genio | ||
from avocado.utils import path as avo_path | ||
from avocado.utils import process | ||
from avocado.core import exceptions | ||
from aexpect.exceptions import ShellTimeoutError | ||
|
||
from virttest import error_context | ||
from virttest import guest_agent | ||
from virttest import utils_misc | ||
from virttest import utils_disk | ||
from virttest import env_process | ||
from virttest import utils_net | ||
from virttest import data_dir | ||
from virttest import storage | ||
from virttest import qemu_migration | ||
from virttest.utils_version import VersionInterval | ||
|
||
from virttest.utils_windows import virtio_win | ||
from provider.win_driver_installer_test import (uninstall_gagent, | ||
run_installer_with_interaction) | ||
|
||
LOG_JOB = logging.getLogger("avocado.test") | ||
|
||
|
||
class BaseVirtTest(object): | ||
|
||
def __init__(self, test, params, env): | ||
self.test = test | ||
self.params = params | ||
self.env = env | ||
|
||
def initialize(self, test, params, env): | ||
if test: | ||
self.test = test | ||
if params: | ||
self.params = params | ||
if env: | ||
self.env = env | ||
start_vm = self.params["start_vm"] | ||
self.start_vm = start_vm | ||
if self.start_vm == "yes": | ||
vm = self.env.get_vm(params["main_vm"]) | ||
vm.verify_alive() | ||
self.vm = vm | ||
|
||
def setup(self, test, params, env): | ||
if test: | ||
self.test = test | ||
if params: | ||
self.params = params | ||
if env: | ||
self.env = env | ||
|
||
def run_once(self, test, params, env): | ||
if test: | ||
self.test = test | ||
if params: | ||
self.params = params | ||
if env: | ||
self.env = env | ||
|
||
def before_run_once(self, test, params, env): | ||
pass | ||
|
||
def after_run_once(self, test, params, env): | ||
pass | ||
|
||
def cleanup(self, test, params, env): | ||
pass | ||
|
||
def execute(self, test, params, env): | ||
self.initialize(test, params, env) | ||
self.setup(test, params, env) | ||
try: | ||
self.before_run_once(test, params, env) | ||
self.run_once(test, params, env) | ||
self.after_run_once(test, params, env) | ||
finally: | ||
self.cleanup(test, params, env) | ||
|
||
|
||
class WinDebugToolTest(BaseVirtTest): | ||
def __init__(self, test, params, env): | ||
super().__init__(test, params, env) | ||
self._open_session_list = [] | ||
self.vm = None | ||
self.script_dir = None | ||
self.script_name = params.get("script_name", "") | ||
self.script_path = params.get("script_path", "") | ||
self.tmp_dir = params.get("test_tmp_dir", "") | ||
|
||
def _get_session(self, params, vm): | ||
if not vm: | ||
vm = self.vm | ||
vm.verify_alive() | ||
timeout = int(params.get("login_timeout", 360)) | ||
session = vm.wait_for_login(timeout=timeout) | ||
return session | ||
|
||
def _cleanup_open_session(self): | ||
try: | ||
for s in self._open_session_list: | ||
if s: | ||
s.close() | ||
except Exception: | ||
pass | ||
|
||
def run_once(self, test, params, env): | ||
BaseVirtTest.run_once(self, test, params, env) | ||
if self.start_vm == "yes": | ||
pass | ||
|
||
def cleanup(self, test, params, env): | ||
self._cleanup_open_session() | ||
|
||
@error_context.context_aware | ||
def setup(self, test, params, env): | ||
BaseVirtTest.setup(self, test, params, env) | ||
if self.start_vm == "yes": | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
|
||
error_context.context("Check whether debug tool exists.", LOG_JOB.info) | ||
cmd_get_debug_tool_script = ( | ||
params["cmd_search_file_global"] % self.script_name | ||
) | ||
script_path = str( | ||
session.cmd_output(cmd_get_debug_tool_script, timeout=360) | ||
).strip() | ||
print("script_path: %s\n" % script_path) | ||
if script_path: | ||
self.script_path = script_path | ||
self.script_dir = self.script_path.replace(self.script_name, "").rstrip( | ||
"\\" | ||
) | ||
else: | ||
test.error( | ||
"The tool script file CollectSystemInfo.ps1 was not found. Please check." | ||
) | ||
|
||
error_context.context("Create tmp work dir since testing " | ||
"would create lots of dir and files.", LOG_JOB.info) | ||
session.cmd_output(params["cmd_create_dir"] % self.tmp_dir) | ||
|
||
def _check_generated_files(self, session, path, sensitive_data=False): | ||
output = str(session.cmd_output(f"dir /b {path}")).strip() | ||
|
||
target_files = ( | ||
self.params["target_dump_files"] | ||
if sensitive_data | ||
else self.params["target_files"] | ||
).split(",") | ||
|
||
for target_file in target_files: | ||
if target_file not in output: | ||
self.test.error(f"{target_file} is not included, please check it.") | ||
|
||
def _get_path(self, output, session, sensitive_data=False): | ||
log_folder_path = re.search(r"Log folder path: (.+)", output).group(1) | ||
self._check_generated_files(session, log_folder_path) | ||
log_zip_path = f"{log_folder_path}.zip" | ||
|
||
if sensitive_data: | ||
dump_folder_match = re.search(r"Dump folder path: (.+)", output) | ||
if dump_folder_match: | ||
dump_folder_path = dump_folder_match.group(1) | ||
self._check_generated_files( | ||
session, dump_folder_path, sensitive_data=True | ||
) | ||
dump_zip_path = f"{dump_folder_path}.zip" | ||
return log_folder_path, log_zip_path, dump_folder_path, dump_zip_path | ||
|
||
return log_folder_path, log_zip_path | ||
|
||
|
||
class WinDebugToolTestBasicCheck(WinDebugToolTest): | ||
def __init__(self, test, params, env): | ||
super().__init__(test, params, env) | ||
|
||
@error_context.context_aware | ||
def run_tool_scripts(self, session, return_zip_path=False): | ||
error_context.context( | ||
"Run Debug tool script to Query original info or value.", LOG_JOB.info | ||
) | ||
# Running the PowerShell script on the VM | ||
include_sensitive_data = bool(strtobool(self.params["include_sensitive_data"])) | ||
print(include_sensitive_data) | ||
sensitive_data_flag = "-IncludeSensitiveData" if include_sensitive_data else "" | ||
|
||
# Execute the command on the VM | ||
cmd_run_deg_tool = f"powershell.exe -ExecutionPolicy Bypass -File {self.script_path} {sensitive_data_flag}" | ||
s, o = session.cmd_status_output(cmd_run_deg_tool, timeout=360) | ||
|
||
paths = self._get_path(o, session, sensitive_data=include_sensitive_data) | ||
if include_sensitive_data: | ||
log_folder_path, log_zip_path, dump_folder_path, dump_zip_path = paths | ||
if not all(paths): | ||
test.fail("Debug tool run failed, please check it.") | ||
return paths if return_zip_path else (log_folder_path, dump_folder_path) | ||
else: | ||
log_folder_path, log_zip_path = paths | ||
if not all(paths): | ||
test.fail("Debug tool run failed, please check it.") | ||
return paths if return_zip_path else log_folder_path | ||
|
||
@error_context.context_aware | ||
def windegtool_check_script_execution(self, test, params, env): | ||
if not self.vm: | ||
self.vm = env.get_vm(params["main_vm"]) | ||
self.vm.verify_alive() | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
log_folder_path, log_zip_path = self.run_tool_scripts( | ||
session, return_zip_path=True | ||
) | ||
if not (log_zip_path and log_folder_path): | ||
test.fail("debug tool run failed, please check it.") | ||
|
||
@error_context.context_aware | ||
def windegtool_check_zip_package(self, test, params, env): | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
log_folder_path, log_zip_path = self.run_tool_scripts( | ||
session, return_zip_path=True | ||
) | ||
if not (log_zip_path and log_folder_path): | ||
test.fail("debug tool run failed, please check it.") | ||
|
||
error_context.context( | ||
"Extract ZIP and check the data files.", LOG_JOB.info | ||
) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
extract_folder = log_zip_path + "_extract" | ||
s, o = session.cmd_status_output( | ||
params["cmd_extract_zip"] % (log_zip_path, extract_folder) | ||
) | ||
if s: | ||
test.error("Extract ZIP failed, please take a look and check.") | ||
|
||
error_context.context("Compare the folders", LOG_JOB.info) | ||
extract_folder_size = session.cmd_output( | ||
params["cmd_check_folder_size"] % extract_folder | ||
) | ||
log_folder_size = session.cmd_output( | ||
params["cmd_check_folder_size"] % log_folder_path | ||
) | ||
if log_folder_size != extract_folder_size: | ||
test.fail( | ||
"ZIP package have problem, since the size of it " | ||
"is not same with the original log folder." | ||
) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_run_tools_multi_times(self, test, params, env): | ||
if not self.vm: | ||
self.vm = env.get_vm(params["main_vm"]) | ||
self.vm.verify_alive() | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
error_context.context( | ||
"Run scripts 100 times and check " | ||
"there is no problem", LOG_JOB.info | ||
) | ||
for i in range(1, 5): | ||
log_folder_path, log_zip_path = self.run_tool_scripts( | ||
session, return_zip_path=True | ||
) | ||
if not (log_zip_path and log_folder_path): | ||
test.fail("debug tool run failed, please check it.") | ||
cmd_remove_zip = params["cmd_remove_dir"] % log_zip_path | ||
cmd_remove_folder = params["cmd_remove_dir"] % log_folder_path | ||
cmd_clean_dir = ( | ||
"%s && %s" % (cmd_remove_folder, cmd_remove_zip) | ||
) | ||
session.cmd(cmd_clean_dir) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_user_friendliness(self, test, params, env): | ||
|
||
def _run_script(session): | ||
cmd_run_deg_tool = f"powershell.exe -ExecutionPolicy Bypass -File {self.script_path}" | ||
try: | ||
session.cmd_output(cmd_run_deg_tool, timeout=5) | ||
except ShellTimeoutError: | ||
pass | ||
|
||
def _kill_powershell_process(session1): | ||
session1.cmd(params["cmd_kill_powershell_process"]) | ||
session1.cmd(params["cmd_kill_powershell_process1"]) | ||
|
||
if not self.vm: | ||
self.vm = env.get_vm(params["main_vm"]) | ||
self.vm.verify_alive() | ||
|
||
session = self._get_session(params, self.vm) | ||
session1 = self._get_session(params, self.vm) | ||
self._open_session_list.extend([session, session1]) | ||
|
||
error_context.context( | ||
"Run script with various of invalid parameters.", LOG_JOB.info | ||
) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
session.cmd("rd /S /Q %s" % self.tmp_dir) | ||
session.cmd_output( | ||
params["cmd_create_dir"] % self.tmp_dir | ||
) | ||
invalid_params = list(params["invalid_params"].split(",")) | ||
expect_output_prompt = params["expect_output_prompt"] | ||
for invalid_param in invalid_params: | ||
cmd_run_deg_tool = f"powershell.exe -ExecutionPolicy Bypass -File {self.script_path} {invalid_param}" | ||
o = session.cmd_output(cmd_run_deg_tool, timeout=360) | ||
if expect_output_prompt not in o: | ||
test.fail( | ||
"There should be friendly reminder output %s, telling " | ||
"users how to run the script with reasonable parameters" | ||
"please check it." % expect_output_prompt | ||
) | ||
|
||
error_context.context( | ||
"Interrupt script when it's running to check " | ||
"the signal file.", LOG_JOB.info | ||
) | ||
script_thread = threading.Thread( | ||
target=_run_script(session) | ||
) | ||
kill_thread = threading.Thread( | ||
target=_kill_powershell_process(session1) | ||
) | ||
script_thread.start() | ||
time.sleep(5) | ||
kill_thread.start() | ||
script_thread.join() | ||
kill_thread.join() | ||
|
||
script_interrupt_signal_file = params["script_interrupt_signal_file"] | ||
log_path = session.cmd_output(params["cmd_query_path"]).split()[0] | ||
session.cmd("cd %s" % log_path) | ||
output = session.cmd_output("dir") | ||
if script_interrupt_signal_file not in output: | ||
test.fail( | ||
f"There should be one {script_interrupt_signal_file} once the script" | ||
f" is interrupted, but there isn't. Please check it." | ||
) | ||
|
||
error_context.context( | ||
"Clean invalid files and re-run script again to check " | ||
"whether it could be run well.", LOG_JOB.info | ||
) | ||
session.cmd("cd ../") | ||
session.cmd(params["cmd_dir_del"] % log_path) | ||
self.run_tool_scripts(session) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_disk_registry_collection(self, test, params, env): | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
error_context.context( | ||
"Run script first to collect 'virtio_disk.txt'.", LOG_JOB.info | ||
) | ||
log_folder_path = self.run_tool_scripts(session) | ||
virtio_disk_filepath = params["virtio_disk_filepath"] % log_folder_path | ||
exist_reg_item = params["exist_reg_item"] | ||
reg_subkey1, reg_subkey2 = params["reg_subkey1"], params["reg_subkey2"] | ||
iotimeoutvalue_file = int(session.cmd_output( | ||
params["cmd_findstr_in_file"] % ( | ||
virtio_disk_filepath, (exist_reg_item + "\\" + reg_subkey1)) | ||
).split(":")[-1].strip()) | ||
timeoutvalue_file = int(session.cmd_output( | ||
params["cmd_findstr_in_file"] % ( | ||
virtio_disk_filepath, (exist_reg_item + "\\" + reg_subkey2)) | ||
).split(":")[-1].strip()) | ||
iotimeoutvalue_cmd = int(session.cmd_output(params["cmd_reg_query"] % | ||
(exist_reg_item, reg_subkey1))) | ||
timeoutvalue_cmd = int(session.cmd_output(params["cmd_reg_query"] % | ||
(exist_reg_item, reg_subkey2))) | ||
if ( | ||
iotimeoutvalue_cmd != iotimeoutvalue_file | ||
or timeoutvalue_cmd != timeoutvalue_file | ||
): | ||
test.error( | ||
"The value of %s and %s is not same between %s and cmd," | ||
"please have a check" % ( | ||
reg_subkey1, reg_subkey2, virtio_disk_filepath | ||
) | ||
) | ||
|
||
error_context.context( | ||
"Edit exist value and create new sub-key for " | ||
"vioscsi/viostor for non-exist value", LOG_JOB.info | ||
) | ||
new_reg_item = params["new_reg_item"] | ||
cmd_reg_add_item = params["cmd_reg_add_item"] % (new_reg_item, new_reg_item) | ||
cmd_reg_add_item_key = params["cmd_reg_add_item_key"] | ||
cmd_reg_set_value = params["cmd_reg_set_value"] | ||
try: | ||
key_value1, key_value2 = int( | ||
params["key_value1"]), int(params["key_value2"]) | ||
|
||
s, o = session.cmd_status_output(cmd_reg_add_item) | ||
if not s: | ||
session.cmd_output( | ||
cmd_reg_add_item_key % (new_reg_item, new_reg_item, reg_subkey1) | ||
) | ||
session.cmd_output( | ||
cmd_reg_add_item_key % (new_reg_item, new_reg_item, reg_subkey2) | ||
) | ||
else: | ||
test.error( | ||
"Add register item for vioscsi/viostor failed, please help check." | ||
) | ||
|
||
session.cmd_output(cmd_reg_set_value % (exist_reg_item, reg_subkey1, key_value1)) | ||
session.cmd_output(cmd_reg_set_value % (new_reg_item, reg_subkey1, key_value1)) | ||
session.cmd_output(cmd_reg_set_value % (new_reg_item, reg_subkey2, key_value2)) | ||
|
||
error_context.context("Re-run guest debug tool script", LOG_JOB.info) | ||
new_log_folder_path = self.run_tool_scripts(session) | ||
new_virtio_disk_filepath = params["virtio_disk_filepath"] % new_log_folder_path | ||
exist_iotimeoutvalue_file = int(session.cmd_output( | ||
params["cmd_findstr_in_file"] % ( | ||
new_virtio_disk_filepath, (exist_reg_item + "\\" + reg_subkey1)) | ||
).split(":")[-1].strip()) | ||
new_iotimeoutvalue_file = int(session.cmd_output(params["cmd_findstr_in_file"] % | ||
(new_virtio_disk_filepath, | ||
(new_reg_item + "\\" + reg_subkey1))).split(":")[-1].strip()) | ||
new_timeoutvalue_file = int(session.cmd_output(params["cmd_findstr_in_file"] % | ||
(new_virtio_disk_filepath, | ||
(new_reg_item + "\\" + reg_subkey2))).split(":")[-1].strip()) | ||
|
||
exist_iotimeoutvalue_cmd = int(session.cmd_output(params["cmd_reg_query"] % (exist_reg_item, reg_subkey1))) | ||
new_iotimeoutvalue_cmd = int(session.cmd_output(params["cmd_reg_query"] % (new_reg_item, reg_subkey1))) | ||
new_timeoutvalue_cmd = int(session.cmd_output(params["cmd_reg_query"] % (new_reg_item, reg_subkey2))) | ||
print(exist_iotimeoutvalue_file, new_iotimeoutvalue_file, new_timeoutvalue_file, exist_iotimeoutvalue_cmd, | ||
new_iotimeoutvalue_cmd, new_timeoutvalue_cmd) | ||
if (exist_iotimeoutvalue_cmd != exist_iotimeoutvalue_file or | ||
new_iotimeoutvalue_cmd != new_iotimeoutvalue_file or | ||
new_timeoutvalue_cmd != new_timeoutvalue_file): | ||
test.error( | ||
"The value of %s and %s is not same between %s and cmd, please have a check" % ( | ||
reg_subkey1, reg_subkey2, new_log_folder_path | ||
) | ||
) | ||
finally: | ||
session.cmd_output(params["cmd_reg_del"] % new_reg_item) | ||
session.cmd_output( | ||
cmd_reg_set_value % (exist_reg_item, reg_subkey1, iotimeoutvalue_cmd) | ||
) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_includeSensitiveData_collection(self, test, params, env): | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
|
||
error_context.context("Trigger BSOD situation.", LOG_JOB.info) | ||
crash_method = params["crash_method"] | ||
if crash_method == "nmi": | ||
timeout = int(params.get("timeout", 360)) | ||
self.vm.monitor.nmi() | ||
time.sleep(timeout) | ||
self.vm.reboot( | ||
session, method=params["reboot_method"], timeout=timeout | ||
) | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
error_context.context("Check the dmp files are existed.", LOG_JOB.info) | ||
cmd_check_dmp_files = params["cmd_check_files"] % params["memory_dmp_file"] | ||
cmd_check_minidmp_files = params["cmd_check_files"] % params["mini_dmp_folder"] | ||
output = session.cmd_output( | ||
"%s && %s" % (cmd_check_dmp_files, cmd_check_minidmp_files) | ||
) | ||
if "dmp" not in output: | ||
test.error("Dump file should be existed, please have a check") | ||
else: | ||
self.run_tool_scripts(session) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_trigger_driver_msinfo_collection(self, test, params, env): | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
|
||
error_context.context( | ||
"Run script firstly to check system name and driver info.", LOG_JOB.info | ||
) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
log_path = self.run_tool_scripts(session) | ||
msinfo_file_path = params["msinfo_file_path"] % log_path | ||
drv_list_file_path = params["drv_list_file_path"] % log_path | ||
target_driver = params["target_driver"] | ||
|
||
old_systemname = str(session.cmd_output(params["cmd_query_from_file"] % | ||
(msinfo_file_path, "System Name:")).split(":")[1]).strip() | ||
systemname_guest = str(session.cmd_output(params["cmd_check_systemname"])).strip() | ||
if old_systemname != systemname_guest: | ||
test.error( | ||
"The system name are different between cmd and file that" | ||
" collect by tool, Please have a check" | ||
) | ||
drvinfo_output = session.cmd_output( | ||
params["cmd_query_from_file"] % (drv_list_file_path, target_driver) | ||
) | ||
if target_driver not in drvinfo_output: | ||
test.error( | ||
"%s doesn't installed, there is no info about it, " | ||
"Please have a check and change another target driver to test" | ||
) | ||
|
||
error_context.context( | ||
"Change the system name and uninstall certain driver.", LOG_JOB.info | ||
) | ||
new_system_name = params["new_system_name"] | ||
session.cmd(params["cmd_change_systemname"] % new_system_name) | ||
win_ver = str(session.cmd_output( | ||
params["cmd_query_ver_vm"], timeout=60) | ||
).strip() | ||
if "2016" not in win_ver: | ||
driver_oem_file = session.cmd_output( | ||
params["cmd_query_oem_inf"] % target_driver | ||
).strip() | ||
cmd_uninstall_driver = params["cmd_uninstall_driver"] % driver_oem_file | ||
s, o = session.cmd_status_output(cmd_uninstall_driver) | ||
else: | ||
cmd_search_2k16_inf = ( | ||
params["cmd_search_2k16_inf_file_global"] % (target_driver + ".inf") | ||
) | ||
w2k16_inf = str(session.cmd_output( | ||
cmd_search_2k16_inf, timeout=60) | ||
).strip() | ||
cmd_install_driver = params["cmd_install_driver"] % w2k16_inf | ||
s, o = session.cmd_status_output(cmd_install_driver) | ||
if s or "Fail" in o: | ||
test.error( | ||
"Fail to execute %s driver, please take a look." % target_driver | ||
) | ||
|
||
error_context.context( | ||
"Re-Run script after rebooting to check whether system" | ||
" name and driver info changed.",LOG_JOB.info | ||
) | ||
session.cmd_output(params["reboot_command"]) | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
|
||
session.cmd("cd %s" % self.tmp_dir) | ||
new_log_path = self.run_tool_scripts(session) | ||
new_msinfo_file_path = params["msinfo_file_path"] % new_log_path | ||
new_drv_list_file_path = params["drv_list_file_path"] % new_log_path | ||
new_setupapi_dev_file_path = params["setupapi_dev_file_path"] % new_log_path | ||
new_systemname = session.cmd_output( | ||
params["cmd_query_from_file"] % (new_msinfo_file_path, "System Name:") | ||
).split(":")[1].strip() | ||
if new_system_name.upper() not in str(new_systemname): | ||
test.fail( | ||
"New systemname wasn't captured by tool, Please have a check" | ||
) | ||
new_drvinfo_output = session.cmd_output( | ||
params["cmd_query_from_file"] % (new_drv_list_file_path, target_driver) | ||
) | ||
if target_driver in new_drvinfo_output: | ||
test.fail( | ||
"Driver should be uninstalled, but tool wasn't captured this situation, Please have a check" | ||
) | ||
if "2016" not in win_ver: | ||
regex_command = cmd_uninstall_driver.replace(" ", r"\s+").replace(".", r"\.") | ||
setupapi_output = session.cmd_output( | ||
params["cmd_query_from_file"] % (new_setupapi_dev_file_path, regex_command) | ||
) | ||
if "/delete-driver" not in setupapi_output: | ||
test.fail( | ||
"Driver execution operation was not captured, Please have a check." | ||
) | ||
else: | ||
setupapi_output = session.cmd_output( | ||
params["cmd_query_from_file"] % (new_setupapi_dev_file_path, "pnputil.exe") | ||
) | ||
if "/add-driver" not in setupapi_output: | ||
test.fail( | ||
"Driver execution operation was not captured, Please have a check." | ||
) | ||
|
||
@error_context.context_aware | ||
def windegtool_check_networkadapter_collection(self, test, params, env): | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
error_context.context( | ||
"Run tool script firstly, and conducting " | ||
"raw data comparison tests", LOG_JOB.info | ||
) | ||
adapter_name = session.cmd_output(params["check_adapter_name"]).strip() | ||
original_log_path = self.run_tool_scripts(session) | ||
|
||
original_networkfile_path = params["networkfile_path"] % original_log_path | ||
raw_jp_value_from_file = session.cmd_output(params["cmd_findstr_in_file"] % | ||
(original_networkfile_path, "Jumbo Packet")) | ||
original_jp_value_from_file = int(raw_jp_value_from_file.split()[5]) | ||
original_jp_value_from_cmd = int(session.cmd_output( | ||
params["check_adapter_jp_info"] % adapter_name) | ||
) | ||
if original_jp_value_from_cmd != original_jp_value_from_file: | ||
test.error( | ||
"Network info collection seems have problem, the value of" | ||
"Jumbo Packet is not same between file and cmd." | ||
) | ||
|
||
ipconfigfile_path = params["ipconfigfile_path"] % original_log_path | ||
original_ipconfig_output = session.cmd_output(params["cmd_findstr_in_file"] % | ||
(ipconfigfile_path, adapter_name)) | ||
dns_info = session.cmd_output(params["cmd_get_dns"]).split() | ||
for dns_info_item in dns_info: | ||
print("Yes DNS existed") if dns_info_item in original_ipconfig_output else print("No, DNS doesn't existed") | ||
|
||
error_context.context( | ||
"Change the dhcp and check whether the file changed", LOG_JOB.info | ||
) | ||
static_dns = params["static_dns"] | ||
session.cmd_output(params["cmd_set_dns"] % (adapter_name, static_dns), timeout=360) | ||
|
||
log_folder_path_new = self.run_tool_scripts(session) | ||
ipconfigfile_path = params["ipconfigfile_path"] % log_folder_path_new | ||
new_ipconfig_output = session.cmd_output( | ||
params["cmd_findstr_in_file"] % (ipconfigfile_path, static_dns) | ||
) | ||
if static_dns not in new_ipconfig_output: | ||
test.fail( | ||
"DNS should be changed but it's not, please check it." | ||
) | ||
else: | ||
error_context.context( | ||
"Checkpoint is pass, Re-enable adapter for next checkpoint.", LOG_JOB.info | ||
) | ||
session.cmd(params["cmd_set_dns_dhcp"] % adapter_name) | ||
|
||
error_context.context( | ||
"Changed the 'Jumbo Packet' value and compare.", LOG_JOB.info | ||
) | ||
try: | ||
session.cmd_output( | ||
params["cmd_set_adapter_jp_info"] % (adapter_name, 9014), timeout=360 | ||
) | ||
except ShellTimeoutError: | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
|
||
log_folder_path_new = self.run_tool_scripts(session) | ||
networkfile_path = params["networkfile_path"] % log_folder_path_new | ||
raw_jp_value = session.cmd_output( | ||
params["cmd_findstr_in_file"] % (networkfile_path, "Jumbo Packet") | ||
) | ||
new_jp_value = int(raw_jp_value.split()[5]) | ||
print("new_jp_value: %s" % new_jp_value) | ||
if original_jp_value_from_file == new_jp_value: | ||
test.fail( | ||
"Jumbo Packet should not be same with the original one, please check it." | ||
) | ||
if new_jp_value != 9014: | ||
test.error( | ||
"Jumbo Packet should be the new value, but it's not somehow, Please check it." | ||
) | ||
|
||
error_context.context("Recover the env.", LOG_JOB.info) | ||
try: | ||
session.cmd( | ||
params["cmd_set_adapter_jp_info"] % ( | ||
adapter_name, original_jp_value_from_file | ||
) | ||
) | ||
except ShellTimeoutError: | ||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
change_back_jp_value = int(session.cmd_output(params["check_adapter_jp_info"] % adapter_name)) | ||
if change_back_jp_value != original_jp_value_from_file: | ||
test.error("Please have a check, the value wasn't changed back to original.") | ||
|
||
@error_context.context_aware | ||
def windegtool_check_documentation(self, test, params, env): | ||
def _clean_output(output): | ||
lines = output.splitlines() | ||
cleaned_lines = [] | ||
|
||
for line in lines: | ||
line = line.strip() | ||
if not line or "powershell" in line: | ||
continue | ||
cleaned_lines.append(line) | ||
return "\n".join(cleaned_lines) | ||
|
||
session = self._get_session(params, self.vm) | ||
self._open_session_list.append(session) | ||
|
||
error_context.context( | ||
"Check all relevant official documents to " | ||
"ensure they are complete", LOG_JOB.info | ||
) | ||
output = str( | ||
session.cmd_output("dir %s\\" % self.script_dir) | ||
).strip() | ||
standard_docs = (params["standard_docs"]).split(",") | ||
for standard_doc in standard_docs: | ||
if standard_doc not in output: | ||
test.error(f"There is no file {standard_doc}, please contact with vendor.") | ||
|
||
error_context.context( | ||
"Address usable commands and execute them to ensure " | ||
"they are executable and accurate", LOG_JOB.info | ||
) | ||
target_doc_path = "%s\\%s" % (self.script_dir, params["target_doc"]) | ||
target_output = str( | ||
session.cmd_output(params["query_cmd_from_file"] % target_doc_path) | ||
).strip() | ||
executable_cmds = _clean_output(target_output).splitlines() | ||
executable_cmd_final = 'powershell.exe -Command "' | ||
for executable_cmd in executable_cmds: | ||
executable_cmd_final += executable_cmd + "; " | ||
executable_cmd_final = executable_cmd_final.rstrip("; ") + '"' | ||
session.cmd(params["cmd_cp_file"] % (self.script_path, self.tmp_dir)) | ||
session.cmd("cd %s" % self.tmp_dir) | ||
s, o = session.cmd_status_output(executable_cmd_final, timeout=360) | ||
|
||
include_sensitive_data = True if "-IncludeSensitiveData" in executable_cmd_final else False | ||
paths = self._get_path( | ||
o, session, sensitive_data=include_sensitive_data | ||
) | ||
if not all(paths): | ||
test.fail("Debug tool run failed, please check it.") | ||
|
||
def run_once(self, test, params, env): | ||
WinDebugToolTest.run_once(self, test, params, env) | ||
|
||
windegtool_check_type = self.params["windegtool_check_type"] | ||
chk_type = "windegtool_check_%s" % windegtool_check_type | ||
if hasattr(self, chk_type): | ||
func = getattr(self, chk_type) | ||
func(test, params, env) | ||
else: | ||
test.error("Could not find matching test, check your config file") | ||
|
||
def run(test, params, env): | ||
""" | ||
Test CollectSystemInfo.ps1 tool, this case will: | ||
1) Start VM with virtio-win rpm package. | ||
2) Execute CollectSystemInfo.ps1 with&without param | ||
"-IncludeSensitiveData". | ||
3) Run some basic test for CollectSystemInfo.ps1. | ||
:param test: kvm test object | ||
:param params: Dictionary with the test parameters | ||
:param env: Dictionary with test environmen. | ||
""" | ||
|
||
collectinfotool_test = WinDebugToolTestBasicCheck(test, params, env) | ||
collectinfotool_test.execute(test, params, env) |