Skip to content

Commit 09c4d6e

Browse files
committed
Avoid destroying/unloading the resources before entering the debugger
Signed-off-by: Gaëtan Lehmann <gaetan.lehmann@vates.tech>
1 parent a44e21a commit 09c4d6e

7 files changed

Lines changed: 176 additions & 223 deletions

File tree

tests/install/conftest.py

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from data import ARP_SERVER, ISO_IMAGES, ISO_IMAGES_BASE, ISO_IMAGES_CACHE, TEST_SSH_PUBKEY, TOOLS
1212
from lib import installer, pxe
1313
from lib.commands import local_cmd
14-
from lib.common import callable_marker, url_download, wait_for
14+
from lib.common import Defer, callable_marker, url_download, wait_for
1515
from lib.installer import AnswerFile
1616

1717
from typing import TYPE_CHECKING, Any, Generator, Sequence
@@ -271,7 +271,8 @@ def remastered_iso(installer_iso: dict[str, str | bool], answerfile: AnswerFile
271271
yield remastered_iso
272272

273273
@pytest.fixture(scope='function')
274-
def vm_booted_with_installer(host: Host, create_vms: list[VM], remastered_iso: str) -> Generator[VM, None, None]:
274+
def vm_booted_with_installer(host: Host, create_vms: list[VM], remastered_iso: str, defer: Defer) \
275+
-> Generator[VM, None, None]:
275276
host_vm, = create_vms # one single VM
276277
iso = remastered_iso
277278

@@ -280,52 +281,39 @@ def vm_booted_with_installer(host: Host, create_vms: list[VM], remastered_iso: s
280281
assert mac_address is not None
281282
logging.info("Host VM has MAC %s", mac_address)
282283

283-
remote_iso = None
284-
try:
285-
remote_iso = host.pool.push_iso(iso)
286-
host_vm.insert_cd(os.path.basename(remote_iso))
287-
288-
try:
289-
host_vm.start()
290-
wait_for(host_vm.is_running, "Wait for host VM running")
291-
292-
# catch host-vm IP address
293-
wait_for(lambda: pxe.arp_addresses_for(mac_address),
294-
"Wait for DHCP server to see Host VM in ARP tables",
295-
timeout_secs=10 * 60)
296-
ips = pxe.arp_addresses_for(mac_address)
297-
logging.info("Host VM has IPs %s", ips)
298-
assert len(ips) == 1
299-
host_vm.ip = ips[0]
300-
ip = host_vm.ip
301-
assert ip is not None
302-
303-
# host may not be up if ARP cache was filled
304-
wait_for(lambda: local_cmd(["ping", "-c1", ip], check=False),
305-
"Wait for host up", timeout_secs=10 * 60, retry_delay_secs=10)
306-
wait_for(lambda: local_cmd(["nc", "-zw5", ip, "22"], check=False),
307-
"Wait for ssh up on host", timeout_secs=10 * 60, retry_delay_secs=5)
308-
309-
yield host_vm
310-
311-
logging.info("Shutting down Host VM")
312-
assert host_vm.ip is not None
313-
installer.poweroff(host_vm.ip)
314-
wait_for(host_vm.is_halted, "Wait for host VM halted")
315-
316-
except Exception as e:
317-
logging.critical("caught exception %s", e)
318-
host_vm.shutdown(force=True)
319-
raise
320-
except KeyboardInterrupt:
321-
logging.warning("keyboard interrupt")
322-
host_vm.shutdown(force=True)
323-
raise
324-
325-
host_vm.eject_cd()
326-
finally:
327-
if remote_iso:
328-
host.pool.remove_iso(remote_iso)
284+
remote_iso = host.pool.push_iso(iso)
285+
host_vm.insert_cd(os.path.basename(remote_iso))
286+
defer(lambda: host.pool.remove_iso(remote_iso))
287+
288+
host_vm.start()
289+
defer(lambda: host_vm.shutdown(force=True))
290+
wait_for(host_vm.is_running, "Wait for host VM running")
291+
292+
# catch host-vm IP address
293+
wait_for(lambda: pxe.arp_addresses_for(mac_address),
294+
"Wait for DHCP server to see Host VM in ARP tables",
295+
timeout_secs=10 * 60)
296+
ips = pxe.arp_addresses_for(mac_address)
297+
logging.info("Host VM has IPs %s", ips)
298+
assert len(ips) == 1
299+
host_vm.ip = ips[0]
300+
ip = host_vm.ip
301+
assert ip is not None
302+
303+
# host may not be up if ARP cache was filled
304+
wait_for(lambda: local_cmd(["ping", "-c1", ip], check=False),
305+
"Wait for host up", timeout_secs=10 * 60, retry_delay_secs=10)
306+
wait_for(lambda: local_cmd(["nc", "-zw5", ip, "22"], check=False),
307+
"Wait for ssh up on host", timeout_secs=10 * 60, retry_delay_secs=5)
308+
309+
yield host_vm
310+
311+
logging.info("Shutting down Host VM")
312+
assert host_vm.ip is not None
313+
installer.poweroff(host_vm.ip)
314+
wait_for(host_vm.is_halted, "Wait for host VM halted")
315+
316+
host_vm.eject_cd()
329317

330318
@pytest.fixture(scope='function')
331319
def xcpng_chained(request: pytest.FixtureRequest) -> None:

tests/migration/test_cross_pool_migration.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,19 @@
22

33
import logging
44

5-
from lib.common import wait_for, wait_for_not
5+
from lib.common import Defer, wait_for, wait_for_not
66
from lib.host import Host
77
from lib.vm import VM
88

99
@pytest.mark.multi_vms # run on a variety of VMs
1010
@pytest.mark.big_vm # and also on a really big VM ideally
11-
def test_cross_pool_migration(hostB1: Host, imported_vm: VM) -> None:
11+
def test_cross_pool_migration(hostB1: Host, imported_vm: VM, defer: Defer) -> None:
1212
vm = imported_vm.clone()
13-
try:
14-
vm.start()
15-
vm.wait_for_os_booted()
16-
vm.migrate(hostB1)
17-
wait_for_not(vm.exists_on_previous_pool, "Wait for VM not on old pool anymore")
18-
wait_for(vm.exists, "Wait for VM on new pool")
19-
vm.wait_for_os_booted()
20-
vm.shutdown(verify=True)
21-
finally:
22-
logging.info("Destroy VM %s" % vm.uuid)
23-
vm.destroy()
13+
defer(lambda: vm.destroy())
14+
vm.start()
15+
vm.wait_for_os_booted()
16+
vm.migrate(hostB1)
17+
wait_for_not(vm.exists_on_previous_pool, "Wait for VM not on old pool anymore")
18+
wait_for(vm.exists, "Wait for VM on new pool")
19+
vm.wait_for_os_booted()
20+
vm.shutdown(verify=True)

tests/misc/test_basic_without_ssh.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import logging
44

5-
from lib.common import wait_for
5+
from lib.common import Defer, wait_for
66
from lib.host import Host
77
from lib.sr import SR
88
from lib.vm import VM
@@ -59,25 +59,21 @@ def test_suspend(self, imported_vm: VM) -> None:
5959
vm.resume()
6060
vm.wait_for_os_booted()
6161

62-
def test_snapshot(self, imported_vm: VM) -> None:
62+
def test_snapshot(self, imported_vm: VM, defer: Defer) -> None:
6363
vm = imported_vm
6464
snapshot = vm.snapshot()
65-
try:
66-
snapshot.revert()
67-
vm.start()
68-
vm.wait_for_os_booted()
69-
finally:
70-
snapshot.destroy(verify=True)
65+
defer(lambda: snapshot.destroy(verify=True))
66+
snapshot.revert()
67+
vm.start()
68+
vm.wait_for_os_booted()
7169

72-
def test_checkpoint(self, imported_vm: VM) -> None:
70+
def test_checkpoint(self, imported_vm: VM, defer: Defer) -> None:
7371
vm = imported_vm
7472
snapshot = vm.checkpoint()
75-
try:
76-
snapshot.revert()
77-
vm.resume()
78-
vm.wait_for_os_booted()
79-
finally:
80-
snapshot.destroy(verify=True)
73+
defer(lambda: snapshot.destroy(verify=True))
74+
snapshot.revert()
75+
vm.resume()
76+
vm.wait_for_os_booted()
8177

8278
# Live migration tests
8379
# We want to test storage migration (memory+disks) and live migration without storage migration (memory only).

tests/misc/test_export.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import logging
44

5+
from lib.common import Defer
56
from lib.host import Host
67
from lib.vm import VM
78

@@ -13,8 +14,9 @@
1314
# From --vm parameter:
1415
# - A VM to import and export
1516

16-
def export_test(host: Host, vm: VM, filepath: str, compress: Literal['none', 'gzip', 'zstd'] = 'none') -> None:
17+
def export_test(host: Host, vm: VM, filepath: str, compress: Literal['none', 'gzip', 'zstd'], defer: Defer) -> None:
1718
vm.export(filepath, compress)
19+
defer(lambda: host.ssh(f'rm -f {filepath}', check=False))
1820
assert host.file_exists(filepath)
1921

2022
def check_file_type(expected: str) -> None:
@@ -29,29 +31,24 @@ def check_file_type(expected: str) -> None:
2931
else:
3032
assert False, 'Unsupported compress mode'
3133

32-
vm2 = None
33-
try:
34-
vm2 = host.import_vm(filepath)
35-
vm2.start()
36-
vm2.wait_for_os_booted()
37-
vm2.shutdown(verify=True)
38-
finally:
39-
logging.info("Delete %s" % filepath)
40-
host.ssh(f'rm -f {filepath}', check=False)
41-
if vm2 is not None:
42-
vm2.destroy()
34+
vm2 = host.import_vm(filepath)
35+
defer(lambda: vm2.destroy())
36+
vm2.start()
37+
vm2.wait_for_os_booted()
38+
vm2.shutdown(verify=True)
4339

4440
@pytest.mark.small_vm # run on a small VM to test the functions
4541
@pytest.mark.big_vm # and also on a really big VM ideally to make sure it scales
4642
class TestExport:
47-
def test_export_zstd(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM) -> None:
43+
def test_export_zstd(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM, defer: Defer) -> None:
4844
filepath = formatted_and_mounted_ext4_disk + '/test-export-zstd.xva'
49-
export_test(host, imported_vm, filepath, 'zstd')
45+
export_test(host, imported_vm, filepath, 'zstd', defer)
5046

51-
def test_export_gzip(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM) -> None:
47+
def test_export_gzip(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM, defer: Defer) -> None:
5248
filepath = formatted_and_mounted_ext4_disk + '/test-export-gzip.xva'
53-
export_test(host, imported_vm, filepath, 'gzip')
49+
export_test(host, imported_vm, filepath, 'gzip', defer)
5450

55-
def test_export_uncompressed(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM) -> None:
51+
def test_export_uncompressed(self, host: Host, formatted_and_mounted_ext4_disk: str, imported_vm: VM,
52+
defer: Defer) -> None:
5653
filepath = formatted_and_mounted_ext4_disk + '/test-export-uncompressed.xva'
57-
export_test(host, imported_vm, filepath, 'none')
54+
export_test(host, imported_vm, filepath, 'none', defer)

tests/packages/bugtool/test_bugtool.py

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import subprocess
44

5+
from lib.common import Defer
56
from lib.host import Host
67

78
# This smoke test runs xen-bugtool and verifies that the archive it generates
@@ -17,35 +18,27 @@ def verify_contains(host: Host, archive: str, files: list[str]) -> None:
1718

1819
class TestsBugtool:
1920
# Verify a minimal bugtool invocation that only queries certain capabilities
20-
def test_bugtool_entries(self, host: Host) -> None:
21-
filename = ''
22-
try:
23-
filename = host.ssh('xen-bugtool -y -s --entries=xenserver-logs,xenserver-databases,system-logs')
24-
verify_contains(host, filename,
25-
[
26-
"var/log/xensource.log",
27-
"var/log/SMlog",
28-
"xapi-db.xml",
29-
])
30-
finally:
31-
if filename:
32-
host.ssh(f'rm -f {filename}')
21+
def test_bugtool_entries(self, host: Host, defer: Defer) -> None:
22+
filename = host.ssh('xen-bugtool -y -s --entries=xenserver-logs,xenserver-databases,system-logs')
23+
defer(lambda: host.ssh(f'rm -f {filename}'))
24+
verify_contains(host, filename,
25+
[
26+
"var/log/xensource.log",
27+
"var/log/SMlog",
28+
"xapi-db.xml",
29+
])
3330

3431
# Verify that a full xen-bugtool invocation contains the most essential files
35-
def test_bugtool_all(self, host: Host) -> None:
36-
filename = ''
37-
try:
38-
filename = host.ssh('xen-bugtool -y -s')
39-
verify_contains(host, filename,
40-
[
41-
"var/log/xensource.log",
42-
"var/log/SMlog",
43-
"xapi-db.xml",
44-
"acpidump.out",
45-
"etc/fstab",
46-
"etc/xapi.conf",
47-
"etc/xensource/pool.conf",
48-
])
49-
finally:
50-
if filename:
51-
host.ssh(f'rm -f {filename}')
32+
def test_bugtool_all(self, host: Host, defer: Defer) -> None:
33+
filename = host.ssh('xen-bugtool -y -s')
34+
defer(lambda: host.ssh(f'rm -f {filename}'))
35+
verify_contains(host, filename,
36+
[
37+
"var/log/xensource.log",
38+
"var/log/SMlog",
39+
"xapi-db.xml",
40+
"acpidump.out",
41+
"etc/fstab",
42+
"etc/xapi.conf",
43+
"etc/xensource/pool.conf",
44+
])

tests/uefi_sb/test_varstored_cert_flow.py

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import logging
44

5-
from lib.common import wait_for
5+
from lib.common import Defer, wait_for
66
from lib.efi import EFIAuth
77
from lib.host import Host
88
from lib.snapshot import Snapshot
@@ -70,40 +70,31 @@ def auto_revert_vm(self, uefi_vm_and_snapshot: tuple[VM, Snapshot]) -> Generator
7070
# Revert the VM, which has the interesting effect of also shutting it down instantly
7171
revert_vm_state(vm, snapshot)
7272

73-
def test_snapshot_revert_restores_certs(self, uefi_vm: VM) -> None:
73+
def test_snapshot_revert_restores_certs(self, uefi_vm: VM, defer: Defer) -> None:
7474
vm = uefi_vm
7575
vm_auths = generate_keys(as_dict=True)
7676
vm.install_uefi_certs([vm_auths[key] for key in ['PK', 'KEK', 'db', 'dbx']])
7777
snapshot = vm.snapshot()
78-
try:
79-
# clear all certs
80-
vm.set_uefi_setup_mode()
81-
snapshot.revert()
82-
logging.info("Check that the VM certs were restored")
83-
for key in ['PK', 'KEK', 'db', 'dbx']:
84-
check_vm_cert_md5sum(vm, key, vm_auths[key].auth())
85-
finally:
86-
snapshot.destroy()
87-
88-
def test_vm_import_restores_certs(self, uefi_vm: VM, formatted_and_mounted_ext4_disk: str) -> None:
78+
defer(lambda: snapshot.destroy())
79+
# clear all certs
80+
vm.set_uefi_setup_mode()
81+
snapshot.revert()
82+
logging.info("Check that the VM certs were restored")
83+
for key in ['PK', 'KEK', 'db', 'dbx']:
84+
check_vm_cert_md5sum(vm, key, vm_auths[key].auth())
85+
86+
def test_vm_import_restores_certs(self, uefi_vm: VM, formatted_and_mounted_ext4_disk: str, defer: Defer) -> None:
8987
vm = uefi_vm
9088
vm_auths = generate_keys(as_dict=True)
9189
vm.install_uefi_certs([vm_auths[key] for key in ['PK', 'KEK', 'db', 'dbx']])
9290
filepath = formatted_and_mounted_ext4_disk + '/test-export-with-uefi-certs.xva'
9391
vm.export(filepath, 'zstd')
94-
vm2 = None
95-
try:
96-
vm2 = vm.host.import_vm(filepath)
97-
logging.info("Check that the VM certs were imported with the VM")
98-
for key in ['PK', 'KEK', 'db', 'dbx']:
99-
check_vm_cert_md5sum(vm2, key, vm_auths[key].auth())
100-
finally:
101-
try:
102-
if vm2 is not None:
103-
logging.info(f"Destroy VM {vm2.uuid}")
104-
vm2.destroy(verify=True)
105-
finally:
106-
vm.host.ssh('rm -f {filepath}', check=False)
92+
defer(lambda: vm.host.ssh('rm -f {filepath}', check=False))
93+
vm2 = vm.host.import_vm(filepath)
94+
defer(lambda: vm2.destroy())
95+
logging.info("Check that the VM certs were imported with the VM")
96+
for key in ['PK', 'KEK', 'db', 'dbx']:
97+
check_vm_cert_md5sum(vm2, key, vm_auths[key].auth())
10798

10899
@pytest.mark.small_vm
109100
@pytest.mark.usefixtures("host_at_least_8_3")

0 commit comments

Comments
 (0)