Skip to content

Commit bd2ec43

Browse files
authored
Merge pull request #215 from xcp-ng/largeblock
largeblock: add tests for largeblock driver
2 parents 906daab + 7435c99 commit bd2ec43

File tree

9 files changed

+234
-8
lines changed

9 files changed

+234
-8
lines changed

conftest.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ def pytest_addoption(parser):
8484
help="Name of an available disk (sdb) or partition device (sdb2) to be formatted and used in storage tests. "
8585
"Set it to 'auto' to let the fixtures auto-detect available disks."
8686
)
87+
parser.addoption(
88+
"--sr-disk-4k",
89+
action="append",
90+
default=[],
91+
help="Name of an available disk (sdb) or partition device (sdb2) with "
92+
"4KiB blocksize to be formatted and used in storage tests. "
93+
"Set it to 'auto' to let the fixtures auto-detect available disks."
94+
)
8795

8896
def pytest_configure(config):
8997
global_config.ignore_ssh_banner = config.getoption('--ignore-ssh-banner')
@@ -227,6 +235,21 @@ def sr_disk(request, host):
227235
f"disk or block device {disk} is either not present or already used on master host"
228236
yield disk
229237

238+
@pytest.fixture(scope='session')
239+
def sr_disk_4k(request, host):
240+
disk = request.param
241+
if disk == "auto":
242+
logging.info(">> Check for the presence of a free 4KiB block device on the master host")
243+
disks = host.available_disks(4096)
244+
assert len(disks) > 0, "a free 4KiB block device is required on the master host"
245+
disk = disks[0]
246+
logging.info(f">> Found free 4KiB block device(s) on hostA1: {' '.join(disks)}. Using {disk}.")
247+
else:
248+
logging.info(f">> Check that 4KiB block device {disk} is available on the master host")
249+
assert disk in host.available_disks(4096), \
250+
f"4KiB block device {disk} must be available for use on master host"
251+
yield disk
252+
230253
@pytest.fixture(scope='session')
231254
def sr_disk_for_all_hosts(request, host):
232255
disk = request.param
@@ -435,6 +458,9 @@ def pytest_generate_tests(metafunc):
435458
if "sr_disk" in metafunc.fixturenames:
436459
disk = metafunc.config.getoption("sr_disk")
437460
metafunc.parametrize("sr_disk", disk, indirect=True, scope="session")
461+
if "sr_disk_4k" in metafunc.fixturenames:
462+
disk = metafunc.config.getoption("sr_disk_4k")
463+
metafunc.parametrize("sr_disk_4k", disk, indirect=True, scope="session")
438464
if "sr_disk_for_all_hosts" in metafunc.fixturenames:
439465
disk = metafunc.config.getoption("sr_disk")
440466
metafunc.parametrize("sr_disk_for_all_hosts", disk, indirect=True, scope="session")
@@ -449,7 +475,8 @@ def pytest_collection_modifyitems(items, config):
449475
'windows_vm',
450476
'hostA2',
451477
'hostB1',
452-
'sr_disk'
478+
'sr_disk',
479+
'sr_disk_4k'
453480
]
454481

455482
for item in items:

jobs.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"--sr-disk": "auto",
7272
},
7373
"paths": ["tests/storage"],
74-
"markers": "(small_vm or no_vm) and not reboot and not quicktest",
74+
"markers": "(small_vm or no_vm) and not reboot and not quicktest and not sr_disk_4k",
7575
"name_filter": "not migration and not linstor",
7676
},
7777
"storage-migrations": {
@@ -89,7 +89,7 @@
8989
"--sr-disk": "auto",
9090
},
9191
"paths": ["tests/storage"],
92-
"markers": "",
92+
"markers": "not sr_disk_4k",
9393
"name_filter": "migration and not linstor",
9494
},
9595
"storage-reboots": {
@@ -106,7 +106,7 @@
106106
"--sr-disk": "auto",
107107
},
108108
"paths": ["tests/storage"],
109-
"markers": "reboot and not flaky",
109+
"markers": "reboot and not flaky and not sr_disk_4k",
110110
"name_filter": "not linstor",
111111
},
112112
"storage-quicktest": {
@@ -121,7 +121,7 @@
121121
"--sr-disk": "auto",
122122
},
123123
"paths": ["tests/storage"],
124-
"markers": "quicktest",
124+
"markers": "quicktest and not sr_disk_4k",
125125
"name_filter": "not linstor and not zfsvol",
126126
},
127127
"linstor-main": {
@@ -185,6 +185,67 @@
185185
"paths": ["tests/storage/linstor"],
186186
"markers": "quicktest",
187187
},
188+
"largeblock-main": {
189+
"description": "tests the largeblock storage driver. avoids quicktest, migrations and reboots",
190+
"requirements": [
191+
"A pool with at least 1 host.",
192+
"An additional free 4KiB disk on the first host.",
193+
"A small VM that can be imported on the SRs.",
194+
],
195+
"nb_pools": 1,
196+
"params": {
197+
"--vm": "single/small_vm",
198+
"--sr-disk-4k": "auto",
199+
},
200+
"paths": ["tests/storage"],
201+
"markers": "(small_vm or no_vm) and sr_disk_4k and not reboot and not quicktest",
202+
"name_filter": "not migration",
203+
},
204+
"largeblock-migrations": {
205+
"description": "a group of tests that need to run on hosts with 4KiB disks and migrates the VDI around",
206+
"requirements": [
207+
"A pool with at least 2 hosts, each with a local SR.",
208+
"An additional free 4KiB disk on the first host.",
209+
"A second pool with a SR to receive migrated VMs.",
210+
"A small VM that can be imported on the SRs.",
211+
],
212+
"nb_pools": 2,
213+
"params": {
214+
"--vm": "single/small_vm",
215+
"--sr-disk-4k": "auto",
216+
},
217+
"paths": ["tests/storage"],
218+
"markers": "sr_disk_4k",
219+
"name_filter": "migration",
220+
},
221+
"largeblock-reboots": {
222+
"description": "largeblock storage driver tests that involve rebooting hosts",
223+
"requirements": [
224+
"A pool with at least 1 host.",
225+
"An additional free 4KiB disk on the first host.",
226+
"A small VM that can be imported on the SRs.",
227+
],
228+
"nb_pools": 1,
229+
"params": {
230+
"--vm": "single/small_vm",
231+
"--sr-disk-4k": "auto",
232+
},
233+
"paths": ["tests/storage"],
234+
"markers": "sr_disk_4k and reboot",
235+
},
236+
"largeblock-quicktest": {
237+
"description": "runs `quicktest` on the largeblock storage driver",
238+
"requirements": [
239+
"A pool with at least 1 host",
240+
"An additional free 4KiB disk on the first host.",
241+
],
242+
"nb_pools": 1,
243+
"params": {
244+
"--sr-disk-4k": "auto",
245+
},
246+
"paths": ["tests/storage"],
247+
"markers": "sr_disk_4k and quicktest",
248+
},
188249
"sb-main": {
189250
"description": "tests uefistored/varstored and SecureBoot using a small unix VM (or no VM when none needed)",
190251
"requirements": [
@@ -342,7 +403,7 @@
342403
"nb_pools": 1,
343404
"params": {},
344405
"paths": ["tests/pci_passthrough"],
345-
}
406+
},
346407
}
347408

348409
# List used by the 'check' action: tests listed here will not raise a check error

lib/host.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,14 +401,22 @@ def disks(self):
401401
def disk_is_available(self, disk):
402402
return len(self.ssh(['lsblk', '-n', '-o', 'MOUNTPOINT', '/dev/' + disk]).strip()) == 0
403403

404-
def available_disks(self):
404+
def available_disks(self, blocksize=512):
405405
"""
406406
Return a list of available disks for formatting, creating SRs or such.
407407
408408
Returns a list of disk names (eg.: ['sdb', 'sdc']) that don't have any mountpoint in
409409
the output of lsblk (including their children such as partitions or md RAID devices)
410410
"""
411-
return [disk for disk in self.disks() if self.disk_is_available(disk)]
411+
avail_disks = []
412+
blk_output = self.ssh(['lsblk', '-nd', '-I', '8,259', '--output', 'NAME,LOG-SEC']).splitlines()
413+
for line in blk_output:
414+
line = line.split()
415+
disk = line[0]
416+
sec_size = line[1]
417+
if sec_size == str(blocksize):
418+
avail_disks.append(disk)
419+
return [disk for disk in avail_disks if self.disk_is_available(disk)]
412420

413421
def file_exists(self, filepath, regular_file=True):
414422
option = '-f' if regular_file else '-e'

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ markers =
1111
hostA2: a second member in the first pool.
1212
hostB1: a second pool.
1313
sr_disk: the test needs a free disk or writable block device that it can erase.
14+
sr_disk_4k: the test needs a free 4KiB block device that it can erase.
1415

1516
# * VM-related markers, automatically set based on fixtures
1617
no_vm: tests that do not require a VM to run.

tests/storage/largeblock/__init__.py

Whitespace-only changes.

tests/storage/largeblock/conftest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import logging
2+
import pytest
3+
4+
@pytest.fixture(scope='package')
5+
def largeblock_sr(host, sr_disk_4k):
6+
""" A LARGEBLOCK SR on first host. """
7+
sr = host.sr_create('largeblock', "LARGEBLOCK-local-SR-test", {'device': '/dev/' + sr_disk_4k})
8+
yield sr
9+
# teardown
10+
sr.destroy()
11+
12+
@pytest.fixture(scope='module')
13+
def vdi_on_largeblock_sr(largeblock_sr):
14+
vdi = largeblock_sr.create_vdi('LARGEBLOCK-local-VDI-test')
15+
yield vdi
16+
vdi.destroy()
17+
18+
@pytest.fixture(scope='module')
19+
def vm_on_largeblock_sr(host, largeblock_sr, vm_ref):
20+
vm = host.import_vm(vm_ref, sr_uuid=largeblock_sr.uuid)
21+
yield vm
22+
# teardown
23+
logging.info("<< Destroy VM")
24+
vm.destroy(verify=True)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import pytest
2+
from lib.common import wait_for, vm_image
3+
from tests.storage import try_to_create_sr_with_missing_device, vdi_is_open
4+
5+
# Requirements:
6+
# - one XCP-ng host with an additional unused 4KiB disk for the SR
7+
8+
class TestLARGEBLOCKSRCreateDestroy:
9+
"""
10+
Tests that do not use fixtures that setup the SR or import VMs,
11+
because they precisely need to test SR creation and destruction,
12+
and VM import.
13+
"""
14+
15+
def test_create_sr_with_missing_device(self, host):
16+
try_to_create_sr_with_missing_device('largeblock', 'LARGEBLOCK-local-SR-test', host)
17+
18+
def test_create_and_destroy_sr(self, host, sr_disk_4k):
19+
# Create and destroy tested in the same test to leave the host as unchanged as possible
20+
sr = host.sr_create('largeblock', "LARGEBLOCK-local-SR-test", {'device': '/dev/' + sr_disk_4k}, verify=True)
21+
# import a VM in order to detect vm import issues here rather than in the vm_on_xfs_fixture used in
22+
# the next tests, because errors in fixtures break teardown
23+
vm = host.import_vm(vm_image('mini-linux-x86_64-bios'), sr_uuid=sr.uuid)
24+
vm.destroy(verify=True)
25+
sr.destroy(verify=True)
26+
27+
@pytest.mark.usefixtures("largeblock_sr")
28+
class TestLARGEBLOCKSR:
29+
@pytest.mark.quicktest
30+
def test_quicktest(self, largeblock_sr):
31+
largeblock_sr.run_quicktest()
32+
33+
def test_vdi_is_not_open(self, vdi_on_largeblock_sr):
34+
assert not vdi_is_open(vdi_on_largeblock_sr)
35+
36+
@pytest.mark.small_vm # run with a small VM to test the features
37+
@pytest.mark.big_vm # and ideally with a big VM to test it scales
38+
def test_start_and_shutdown_VM(self, vm_on_largeblock_sr):
39+
vm = vm_on_largeblock_sr
40+
vm.start()
41+
vm.wait_for_os_booted()
42+
vm.shutdown(verify=True)
43+
44+
@pytest.mark.small_vm
45+
@pytest.mark.big_vm
46+
def test_snapshot(self, vm_on_largeblock_sr):
47+
vm = vm_on_largeblock_sr
48+
vm.start()
49+
vm.wait_for_os_booted()
50+
vm.test_snapshot_on_running_vm()
51+
vm.shutdown(verify=True)
52+
53+
# *** tests with reboots (longer tests).
54+
55+
@pytest.mark.reboot
56+
@pytest.mark.small_vm
57+
def test_reboot(self, host, largeblock_sr, vm_on_largeblock_sr):
58+
sr = largeblock_sr
59+
vm = vm_on_largeblock_sr
60+
host.reboot(verify=True)
61+
wait_for(sr.all_pbds_attached, "Wait for PBD attached")
62+
# start the VM as a way to check that the underlying SR is operational
63+
vm.start()
64+
vm.wait_for_os_booted()
65+
vm.shutdown(verify=True)
66+
67+
# *** End of tests with reboots
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
from tests.storage import cold_migration_then_come_back, live_storage_migration_then_come_back
3+
4+
# Requirements:
5+
# From --hosts parameter:
6+
# - host(A1): first XCP-ng host with an additional unused 4KiB disk for the SR.
7+
# - hostB1: Master of a second pool. Any local SR.
8+
# From --vm parameter
9+
# - A VM to import to the EXT SR
10+
11+
@pytest.mark.small_vm # run with a small VM to test the features
12+
@pytest.mark.big_vm # and ideally with a big VM to test it scales
13+
@pytest.mark.usefixtures("hostB1", "local_sr_on_hostB1")
14+
class Test:
15+
def test_cold_crosspool_migration(self, host, hostB1, vm_on_largeblock_sr, local_sr_on_hostB1):
16+
cold_migration_then_come_back(vm_on_largeblock_sr, host, hostB1, local_sr_on_hostB1)
17+
18+
def test_live_crosspool_migration(self, host, hostB1, vm_on_largeblock_sr, local_sr_on_hostB1):
19+
live_storage_migration_then_come_back(vm_on_largeblock_sr, host, hostB1, local_sr_on_hostB1)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
from tests.storage import cold_migration_then_come_back, live_storage_migration_then_come_back
3+
4+
# Requirements:
5+
# From --hosts parameter:
6+
# - host(A1): first XCP-ng host with an additional unused 4KiB disk for the largeblock SR.
7+
# - hostA2: Second member of the pool. Can have any local SR. No need to specify it on CLI.
8+
# From --vm parameter
9+
# - A VM to import to the EXT SR
10+
11+
@pytest.mark.small_vm # run with a small VM to test the features
12+
@pytest.mark.big_vm # and ideally with a big VM to test it scales
13+
@pytest.mark.usefixtures("hostA2", "local_sr_on_hostA2")
14+
class Test:
15+
def test_cold_intrapool_migration(self, host, hostA2, vm_on_largeblock_sr, local_sr_on_hostA2):
16+
cold_migration_then_come_back(vm_on_largeblock_sr, host, hostA2, local_sr_on_hostA2)
17+
18+
def test_live_intrapool_migration(self, host, hostA2, vm_on_largeblock_sr, local_sr_on_hostA2):
19+
live_storage_migration_then_come_back(vm_on_largeblock_sr, host, hostA2, local_sr_on_hostA2)

0 commit comments

Comments
 (0)