tests: Add test for CPU hotplug for Windows guest

Also, add a note on hotplug support to windows.md.

Closes #2438.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski 2021-03-29 22:10:05 +02:00 committed by Rob Bradford
parent 46f96f27a4
commit 1bb0e54e92
2 changed files with 97 additions and 0 deletions

View File

@ -184,6 +184,10 @@ Set-Service -Name sshd -StartupType Automatic
This allows for SSH login from a remote machine, for example through the `administrator` user: `ssh administrator@192.168.249.2`. For a more detailed OpenSSH guide, please follow the MSDN article from the [links](#links) section.
## Hotplug capability
CPU hotplug is supported. The VM operating system needs to support hotplug and be appropriately licensed. SKU limitations like constraints on the number of cores are to be taken into consideration.
## Debugging
The Windows guest debugging process relies heavily on QEMU and [socat](http://www.dest-unreach.org/socat/). The procedure requires two Windows VMs:

View File

@ -5565,6 +5565,30 @@ mod tests {
}
}
fn get_cpu_count_windows(auth: &PasswordAuth) -> u8 {
return ssh_command_ip_with_auth(
"powershell -Command \"(Get-CimInstance win32_computersystem).NumberOfLogicalProcessors\"",
&auth,
"192.168.249.2",
DEFAULT_SSH_RETRIES,
DEFAULT_SSH_TIMEOUT,
)
.unwrap()
.trim()
.parse::<u8>()
.unwrap_or(0);
}
fn get_vcpu_threads_count(pid: u32) -> u8 {
// ps -T -p 12345 | grep vcpu | wc -l
let out = Command::new("ps")
.args(&["-T", "-p", format!("{}", pid).as_str()])
.output()
.expect("ps command failed")
.stdout;
return String::from_utf8_lossy(&out).matches("vcpu").count() as u8;
}
#[test]
fn test_windows_guest() {
let mut windows = WindowsDiskConfig::new(WINDOWS_IMAGE_NAME.to_string());
@ -5712,6 +5736,75 @@ mod tests {
handle_child_output(r, &output);
}
#[test]
fn test_windows_guest_cpu_hotplug() {
let mut windows = WindowsDiskConfig::new(WINDOWS_IMAGE_NAME.to_string());
let guest = Guest::new(&mut windows);
let tmp_dir = TempDir::new_with_prefix("/tmp/ch").unwrap();
let mut workload_path = dirs::home_dir().unwrap();
workload_path.push("workloads");
let mut ovmf_path = workload_path.clone();
ovmf_path.push(OVMF_NAME);
let mut osdisk_path = workload_path;
osdisk_path.push(WINDOWS_IMAGE_NAME.to_string());
let api_socket = temp_api_path(&tmp_dir);
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket])
.args(&["--cpus", "boot=2,max=8,kvm_hyperv=on"])
.args(&["--memory", "size=4G"])
.args(&["--kernel", ovmf_path.to_str().unwrap()])
.default_disks()
.args(&["--serial", "tty"])
.args(&["--console", "off"])
.args(&["--net", "tap="])
.capture_output()
.spawn()
.unwrap();
// Wait to make sure Windows boots up
thread::sleep(std::time::Duration::new(60, 0));
let r = std::panic::catch_unwind(|| {
let auth = windows_auth();
let vcpu_num = 2;
// Check the initial number of CPUs the guest sees
assert_eq!(get_cpu_count_windows(&auth), vcpu_num);
// Check the initial number of vcpu threads in the CH process
assert_eq!(get_vcpu_threads_count(child.id()), vcpu_num);
let vcpu_num = 6;
// Hotplug some CPUs
resize_command(&api_socket, Some(vcpu_num), None, None);
// Wait to make sure CPUs are added
thread::sleep(std::time::Duration::new(10, 0));
// Check the guest sees the correct number
assert_eq!(get_cpu_count_windows(&auth), vcpu_num);
// Check the CH process has the correct number of vcpu threads
assert_eq!(get_vcpu_threads_count(child.id()), vcpu_num);
ssh_command_ip_with_auth(
"shutdown /s",
&auth,
"192.168.249.2",
DEFAULT_SSH_RETRIES,
DEFAULT_SSH_TIMEOUT,
)
.unwrap();
});
let _ = child.wait_timeout(std::time::Duration::from_secs(60));
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
}
#[cfg(target_arch = "x86_64")]