Skip to content

Commit

Permalink
win_guest_debugging_tool: Support new feature
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
6-dehan committed Dec 16, 2024
1 parent d516da1 commit 59abb7b
Show file tree
Hide file tree
Showing 2 changed files with 332 additions and 0 deletions.
36 changes: 36 additions & 0 deletions qemu/tests/cfg/win_guest_debugging_tool.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
- 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
variants:
- check_script_execution:
windegtool_check_type = script_execution
include_sensitive_data = False
- 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
- check_disk_registry_collection:
windegtool_check_type = disk_registry_collection
- check_includeSensitiveData_collection:
windegtool_check_type = includeSensitiveData_collection
include_sensitive_data = True
- check_trigger_driver_collection:
windegtool_check_type = trigger_driver_collection
- check_networkadapter_collection:
windegtool_check_type = networkadapter_collection
- check_documentation:
windegtool_check_type = documentation
296 changes: 296 additions & 0 deletions qemu/tests/win_guest_debugging_tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
import logging
import time
import os
import re
import base64
import random
import string
import json

import aexpect

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_name = "CollectSystemInfo.ps1" # Assuming script is named CollectSystemInfo.ps1

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("Create tmp work dir since testing "
"would create lots of "
"dir and files.", LOG_JOB.info)
self.tmp_dir = params['test_tmp_dir']
session.cmd(params['cmd_create_dir'] % self.tmp_dir)

error_context.context("Change to the temporary "
"work directory.", LOG_JOB.info)
# 在工作临时目录中执行脚本
session.cmd("cd %s" % self.tmp_dir)



def _check_tool_exist(self, test, params, session):
# will includ into above fuc run_once
error_context.context("Check whether debug tool exists.", LOG_JOB.info)
cmd_check_dir = params['cmd_check_dir' % debug_tool_path]
file_check_list = params['file_check_list']
s, o = session.cmd_status_output(cmd_check_dir)
if s == 0 and o:
for file in file_check_list:
if file in o:
test.error('File %s should exist under %s' % (file, debug_tool_path))
else:
test.error('The debug tool path doesn not exist. Please contact with vendor.')
return s == 1
self.script_path = script_path
return s == 0

def _cleanup_files(self, log_folder, dump_folder, log_zip, dump_zip):
# 清理文件, 目录, powershell 命令:
'Remove-Item -Recurse -Force "C:\ExtractedFiles"'
# This function can be customized to clean up or archive files after test
cmd_clean_logfoler(self.params[cmd_clean_files] % log_folder)
cmd_clean_dumpfolder(self.params[cmd_clean_files] % dump_folder)
cmd_clean_logzip(self.params[cmd_clean_files] % log_zip)
cmd_clean_dumpzip(self.params[cmd_clean_files] % dump_zip)
session.cmd(cmd_clean_logfolder)
if dump_folder:
session.cmd(cmd_clean_dumpfolder)
session.cmd(cmd_clean_logzip)
if dump_zip:
session.cmd(cmd_clean_dumpzip)

def _check_file_zip(self, test, params, env):
# Check the folder and zip package
pass



class WinDebugToolTestBasicCheck(WinDebugToolTest):

@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)
# Running the PowerShell script on the VM
include_sensitive_data = self.params.get("include_sensitive_data", False)
sensitive_data_flag = "-IncludeSensitiveData" if include_sensitive_data else ""

# Ensure the script runs with an unrestricted execution policy
cmd_unrestrict_policy = self.params['cmd_unrestrict_policy']
session.cmd(cmd_unrestrict_policy)

# Execute the command on the VM
self.script_path = "E:\\tools\\debug\\CollectSystemInfo.ps1"
cmd_run_deg_tool = f"powershell {self.script_path} {sensitive_data_flag}"
s, o = session.cmd_status_output(cmd_run_deg_tool, timeout=300)

log_folder_path_pattern = r"Log folder path: (.+)"
log_folder_match = re.search(log_folder_path_pattern, o)
if log_folder_match:
log_folder_path = log_folder_match.group(1)
print(f"Log folder path: {log_folder_path}")
if log_folder_path:
# 拼接 ZIP 文件路径
log_zip_path = log_folder_path + ".zip"
# 确保路径合法性
log_zip_path = os.path.normpath(log_zip_path)
print(f"Log zip path: {log_zip_path}")
return log_folder_path, log_zip_path
else:
test.fail("debug tool run failed, please check it.")

@error_context.context_aware
def windegtool_check_zip_package(self, test, params, env):
error_context.context("Extract ZIP and check the data files.", LOG_JOB.info)
# cmd解压缩命令
session.cmd("cd %s" % self.tmp_dir)
extract_folder = "zip_package"+"_extract"
s, o = session.cmd_status_output(params['cmd_extract_zip'] % (zip_package, extract_folder))
if s:
test.error("Extract ZIP failed, please take a look and check.")

error_context.context("Compare the folders", LOG_JOB.info)
# Check the size of unzip folder and original folder.
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.")

def windegtool_check_run_tools_multi_times(self, test, params, env):
error_context.context("Run scripts 100 times and check there is no problem", LOG_JOB.info)
# 1. cmd 运行脚本100次
# 2. 检查所有文件是否都在


def windegtool_check_user_friendliness(self, test, params, env):
# 1. 运行无效参数, 看脚本是否可以运行
#2. 运行脚本, 但是5秒钟后中断脚本运行, 查看:
# 2.1 是否有'Collecting_Status.txt'来记录脚本运行进程, 以告知用户
# 3. Clean the folder that was interrupted.
# 3.1 `Remove - Item - Path.\SystemInfo_2024 - xx_xx - xx\ -ErrorActionSilentlyContinue - Force - Recurse`
# 4. Re-running a script after an abnormal interruption
pass

def windegtool_check_disk_registry_collection(self, test, param, env):

pass

def windegtool_check_includeSensitiveData_collection(self, test, param, env):
pass

def windegtool_check_trigger_driver_collection(self, test, param, env):
pass

def windegtool_check_networkadapter_collection(self, test, param, env):
pass

def windegtool_check_documentation(self, test, param, env):
# 1. Check all relevant documents to ensure they are complete. (README.md,LICENSE,CollectSystemInfo.ps1)
# 2. Follow the script according to the documentation to ensure all steps and instructions are correct.
pass

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)

0 comments on commit 59abb7b

Please sign in to comment.