Skip to content

Commit ee0f37d

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 ee0f37d

8 files changed

Lines changed: 197 additions & 247 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/network/test_vif_management.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

33
from lib.commands import SSHCommandFailed
4+
from lib.common import Defer
45
from lib.vif import VIF
56
from lib.vm import VM
67

@@ -20,7 +21,7 @@ def count_interfaces(vm: VM) -> int:
2021

2122
@pytest.mark.small_vm
2223
class TestVIFManagement:
23-
def test_vif_management(self, running_unix_vm: VM) -> None:
24+
def test_vif_management(self, running_unix_vm: VM, defer: Defer) -> None:
2425
vm = running_unix_vm
2526
host = vm.host
2627
network_uuid = host.management_network()
@@ -33,33 +34,29 @@ def test_vif_management(self, running_unix_vm: VM) -> None:
3334

3435
# create a new VIF in the management network
3536
vif_new = vm.create_vif(n_vif, network_uuid=network_uuid)
37+
defer(lambda: vif_new.destroy())
3638

37-
try:
38-
# check one more VIF
39-
assert len(vm.vifs()) == n_vif + 1
40-
assert count_interfaces(vm) == n_interfaces
41-
42-
# plug the VIF
43-
vif_new.plug()
44-
assert count_interfaces(vm) == n_interfaces + 1
45-
46-
# try destroying the plugged VIF (should fail)
47-
try:
48-
vif_new.destroy()
49-
pytest.fail("VIF destroy should fail if the VIF is plugged")
50-
except SSHCommandFailed as exc:
51-
if "You attempted an operation that was not allowed." in exc.stdout:
52-
pass
53-
else:
54-
raise exc
39+
# check one more VIF
40+
assert len(vm.vifs()) == n_vif + 1
41+
assert count_interfaces(vm) == n_interfaces
5542

56-
# unplug the VIF
57-
vif_new.unplug()
58-
assert count_interfaces(vm) == n_interfaces
43+
# plug the VIF
44+
vif_new.plug()
45+
assert count_interfaces(vm) == n_interfaces + 1
5946

60-
finally:
61-
# destroy the just created VIF
47+
# try destroying the plugged VIF (should fail)
48+
try:
6249
vif_new.destroy()
50+
pytest.fail("VIF destroy should fail if the VIF is plugged")
51+
except SSHCommandFailed as exc:
52+
if "You attempted an operation that was not allowed." in exc.stdout:
53+
pass
54+
else:
55+
raise exc
56+
57+
# unplug the VIF
58+
vif_new.unplug()
59+
assert count_interfaces(vm) == n_interfaces
6360

6461
# check one less VIF
6562
assert len(vm.vifs()) == n_vif

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+
])

0 commit comments

Comments
 (0)