-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5795 from cliping/swtpm
migration: Update vtpm device migration case
- Loading branch information
Showing
6 changed files
with
351 additions
and
3 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
66 changes: 66 additions & 0 deletions
66
libvirt/tests/cfg/migration/migration_with_vtpm/migration_with_vtpm_dev.cfg
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,66 @@ | ||
- migration_with_vtpm.migration_with_vtpm_dev: | ||
type = migration_with_vtpm_dev | ||
migration_setup = 'yes' | ||
storage_type = 'nfs' | ||
setup_local_nfs = 'yes' | ||
disk_type = "file" | ||
disk_source_protocol = "netfs" | ||
mnt_path_name = ${nfs_mount_dir} | ||
# Console output can only be monitored via virsh console output | ||
only_pty = True | ||
take_regular_screendumps = no | ||
# Extra options to pass after <domain> <desturi> | ||
virsh_migrate_extra = "" | ||
# SSH connection time out | ||
ssh_timeout = 60 | ||
start_vm = "no" | ||
# Local URI | ||
virsh_migrate_connect_uri = "qemu:///system" | ||
server_ip = "${migrate_dest_host}" | ||
server_user = "root" | ||
server_pwd = "${migrate_dest_pwd}" | ||
client_ip = "${migrate_source_host}" | ||
client_user = "root" | ||
client_pwd = "${migrate_source_pwd}" | ||
transport_type = "ssh" | ||
migrate_desturi_type = "ssh" | ||
virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system" | ||
tpm_cmd = "tpm2_getrandom --hex 16" | ||
auth_sec_dict = {"sec_ephemeral": "no", "sec_private": "yes", "sec_desc": "sample vTPM secret", "sec_usage": "vtpm", "sec_name": "VTPM_example"} | ||
src_secret_value = "sec value test" | ||
src_secret_value_path = "/var/tmp/src_secretinfile" | ||
dst_secret_value = ${src_secret_value} | ||
dst_secret_value_path = "/var/tmp/dst_secretinfile" | ||
swtpm_path = "/var/lib/libvirt/swtpm/" | ||
swtpm_log = "/var/log/swtpm/libvirt/qemu/${migrate_main_vm}-swtpm.log" | ||
status_error = "yes" | ||
err_msg = "guest CPU doesn't match specification: missing features" | ||
status_error_again = "no" | ||
migrate_again = "yes" | ||
tpm_model = "tpm-crb" | ||
aarch64: | ||
tpm_model = "tpm-tis" | ||
tpm_dict = {'tpm_model': '${tpm_model}', 'backend': {'backend_type': 'emulator', 'backend_version': '2.0', 'encryption_secret': '0051c505-1ad0-4d77-9b3e-360c8f5e3b86'}} | ||
variants: | ||
- p2p: | ||
virsh_migrate_options = '--live --p2p --verbose' | ||
- non_p2p: | ||
virsh_migrate_options = '--live --verbose' | ||
variants: | ||
- with_precopy: | ||
- with_postcopy: | ||
postcopy_options = '--postcopy --postcopy-bandwidth 10 --bandwidth 10' | ||
action_during_mig_again = '[{"func": "virsh.migrate_postcopy", "func_param": "'%s' % params.get('migrate_main_vm')", "need_sleep_time": "5"}]' | ||
variants test_case: | ||
- default: | ||
- tunnelled: | ||
only with_precopy | ||
only p2p | ||
virsh_migrate_extra = "--tunnelled" | ||
- diff_secret_on_src_and_dst: | ||
only with_precopy | ||
status_error = "yes" | ||
migrate_again = "no" | ||
src_secret_value = "sec value test" | ||
dst_secret_value = "sec value diff" | ||
err_msg = "qemu-kvm: tpm-emulator: Setting the stateblob \(type 1\) failed with a TPM error 0x21 decryption error" |
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
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
240 changes: 240 additions & 0 deletions
240
libvirt/tests/src/migration/migration_with_vtpm/migration_with_vtpm_dev.py
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,240 @@ | ||
import os | ||
|
||
from avocado.utils import process | ||
|
||
from virttest import remote | ||
from virttest import utils_package | ||
from virttest import virsh | ||
|
||
from virttest.libvirt_xml import vm_xml | ||
from virttest.utils_libvirt import libvirt_secret | ||
from virttest.utils_libvirt import libvirt_vmxml | ||
from virttest.utils_test import libvirt | ||
|
||
from provider.migration import base_steps | ||
|
||
src_sec_uuid = None | ||
dst_sec_uuid = None | ||
|
||
|
||
def check_vtpm_func(params, vm, test, remote=False): | ||
""" | ||
Check vtpm function | ||
:param params: dict, test parameters | ||
:param vm: VM object | ||
:param test: test object | ||
:param remote: True to check context on remote | ||
""" | ||
tpm_cmd = params.get("tpm_cmd") | ||
dest_uri = params.get("virsh_migrate_desturi") | ||
src_uri = params.get("virsh_migrate_connect_uri") | ||
test.log.debug("Check vtpm func: %s (remote).", remote) | ||
if remote: | ||
if vm.serial_console is not None: | ||
vm.cleanup_serial_console() | ||
vm.connect_uri = dest_uri | ||
if vm.serial_console is None: | ||
vm.create_serial_console() | ||
vm_session = vm.wait_for_serial_login(timeout=240) | ||
if not utils_package.package_install("tpm2-tools", vm_session): | ||
test.error("Failed to install tpm2-tools in vm") | ||
cmd_result = vm_session.cmd_status(tpm_cmd) | ||
vm_session.close() | ||
if remote: | ||
if vm.serial_console is not None: | ||
vm.cleanup_serial_console() | ||
vm.connect_uri = src_uri | ||
if cmd_result: | ||
test.fail("Fail to run '%s': %s." % (tpm_cmd, cmd_result)) | ||
|
||
|
||
def set_secret(params): | ||
""" | ||
Set secret | ||
:param params: dict, test parameters | ||
""" | ||
auth_sec_dict = eval(params.get("auth_sec_dict")) | ||
src_secret_value = params.get("src_secret_value") | ||
src_secret_value_path = params.get("src_secret_value_path") | ||
dst_secret_value = params.get("dst_secret_value") | ||
dst_secret_value_path = params.get("dst_secret_value_path") | ||
remote_pwd = params.get("migrate_dest_pwd") | ||
remote_ip = params.get("migrate_dest_host") | ||
remote_user = params.get("remote_user", "root") | ||
|
||
def _create_secret(session=None, remote_args=None, secret_value_path=None): | ||
""" | ||
create secret | ||
:param session: a session object of remote host | ||
:param remote_args: remote host parameters | ||
:param secret_value_path: the path of secret value | ||
""" | ||
libvirt_secret.clean_up_secrets(session) | ||
global dst_sec_uuid | ||
global src_sec_uuid | ||
if remote_args: | ||
dst_sec_uuid = libvirt.create_secret(auth_sec_dict, remote_args=remote_args) | ||
else: | ||
src_sec_uuid = libvirt.create_secret(auth_sec_dict) | ||
auth_sec_dict.update({"sec_uuid": src_sec_uuid}) | ||
if os.path.exists(secret_value_path): | ||
os.remove(secret_value_path) | ||
if session: | ||
cmd = "echo '%s' > %s" % (dst_secret_value, secret_value_path) | ||
process.run(cmd, shell=True) | ||
remote.scp_to_remote(remote_ip, '22', remote_user, remote_pwd, | ||
secret_value_path, secret_value_path, | ||
limit="", log_filename=None, timeout=60, | ||
interface=None) | ||
cmd = f"virsh secret-set-value {dst_sec_uuid} --file {secret_value_path} --plain" | ||
remote.run_remote_cmd(cmd, params) | ||
else: | ||
cmd = "echo '%s' > %s" % (src_secret_value, secret_value_path) | ||
process.run(cmd, shell=True) | ||
cmd = f"virsh secret-set-value {src_sec_uuid} --file {secret_value_path} --plain" | ||
process.run(cmd, shell=True) | ||
|
||
_create_secret(secret_value_path=src_secret_value_path) | ||
params.update({"auth_sec_dict": auth_sec_dict}) | ||
virsh_dargs = {'remote_ip': remote_ip, 'remote_user': remote_user, | ||
'remote_pwd': remote_pwd, 'unprivileged_user': None, | ||
'ssh_remote_auth': True} | ||
remote_virsh_session = None | ||
remote_virsh_session = virsh.VirshPersistent(**virsh_dargs) | ||
_create_secret(session=remote_virsh_session, remote_args=virsh_dargs, | ||
secret_value_path=dst_secret_value_path) | ||
|
||
|
||
def setup_vtpm(params, test, vm, migration_obj): | ||
""" | ||
Setup vTPM device in guest xml | ||
:param params: dict, test parameters | ||
:param vm: VM object | ||
:param test: test object | ||
:param migration_obj: migration object | ||
""" | ||
vm_name = params.get("migrate_main_vm") | ||
tpm_dict = eval(params.get('tpm_dict', '{}')) | ||
auth_sec_dict = params.get("auth_sec_dict") | ||
|
||
test.log.info("Setup vTPM device in guest xml.") | ||
if vm.is_alive(): | ||
vm.destroy(gracefully=False) | ||
vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) | ||
# Remove all existing tpm devices | ||
vmxml.remove_all_device_by_type('tpm') | ||
|
||
tpm_dict['backend']['encryption_secret'] = auth_sec_dict['sec_uuid'] | ||
libvirt_vmxml.modify_vm_device(vmxml, 'tpm', tpm_dict) | ||
|
||
vm.start() | ||
vm.wait_for_login().close() | ||
|
||
|
||
def check_ownership(swtpm_log, expected_ownership, test): | ||
""" | ||
Check ownership | ||
:param swtpm_log: swtpm log path | ||
:param expected_ownership: Expected ownership | ||
:param test: test object | ||
""" | ||
cmd = "ls -lZ %s" % swtpm_log | ||
ret = process.run(cmd, shell=True).stdout_text.strip() | ||
if expected_ownership not in ret: | ||
test.fail("Swtpm log ownership not correct: %s" % ret) | ||
|
||
|
||
def run(test, params, env): | ||
""" | ||
Test migration with vtpm device. | ||
:param test: test object | ||
:param params: Dictionary with the test parameters | ||
:param env: Dictionary with test environment. | ||
""" | ||
|
||
def setup_test(): | ||
""" | ||
Setup steps | ||
""" | ||
test.log.info("Setup steps.") | ||
set_secret(params) | ||
migration_obj.setup_connection() | ||
setup_vtpm(params, test, vm, migration_obj) | ||
|
||
def verify_test(): | ||
""" | ||
Verify steps | ||
""" | ||
swtpm_log = params.get("swtpm_log") | ||
|
||
test.log.info("Verify steps.") | ||
check_ownership(swtpm_log, "svirt_image_t", test) | ||
virsh.shutdown(vm_name, debug=True) | ||
if not vm.wait_for_shutdown(): | ||
test.error('VM failed to shutdown in 60s') | ||
check_ownership(swtpm_log, "virt_log_t", test) | ||
|
||
def cleanup_test(): | ||
""" | ||
Cleanup steps | ||
""" | ||
desturi = params.get("virsh_migrate_desturi") | ||
swtpm_path = params.get("swtpm_path") | ||
dst_secret_value_path = params.get("dst_secret_value_path") | ||
src_secret_value_path = params.get("src_secret_value_path") | ||
|
||
test.log.info("Cleanup steps.") | ||
global src_sec_uuid | ||
if src_sec_uuid: | ||
virsh.secret_undefine(src_sec_uuid, debug=True, ignore_status=True) | ||
global dst_sec_uuid | ||
if dst_sec_uuid: | ||
virsh.secret_undefine(dst_sec_uuid, debug=True, ignore_status=True, uri=desturi) | ||
|
||
migration_obj.cleanup_connection() | ||
cmd = f"rm -rf {swtpm_path}/*" | ||
remote.run_remote_cmd(cmd, params) | ||
cmd = f"rm -rf {dst_secret_value_path}" | ||
remote.run_remote_cmd(cmd, params) | ||
process.run(cmd, shell=True, ignore_status=True) | ||
cmd = f"rm -rf {src_secret_value_path}" | ||
process.run(cmd, shell=True, ignore_status=True) | ||
|
||
vm_name = params.get("migrate_main_vm") | ||
test_case = params.get("test_case", "") | ||
migrate_again = "yes" == params.get("migrate_again", "no") | ||
desturi = params.get("virsh_migrate_desturi") | ||
|
||
vm = env.get_vm(vm_name) | ||
migration_obj = base_steps.MigrationBase(test, vm, params) | ||
|
||
if base_steps.check_cpu_for_mig(desturi): | ||
if test_case != "diff_secret_on_src_and_dst": | ||
test.cancel("Need to use machines with different cpu to test this case.") | ||
else: | ||
if test_case == "diff_secret_on_src_and_dst": | ||
base_steps.sync_cpu_for_mig(params) | ||
|
||
try: | ||
setup_test() | ||
migration_obj.run_migration() | ||
if test_case != "negative": | ||
verify_test() | ||
base_steps.sync_cpu_for_mig(params) | ||
else: | ||
migration_obj.verify_default() | ||
if migrate_again: | ||
migration_obj.run_migration_again() | ||
migration_obj.verify_default() | ||
check_vtpm_func(params, vm, test, remote=True) | ||
finally: | ||
cleanup_test() |
Oops, something went wrong.