|
8 | 8 | import tempfile
|
9 | 9 |
|
10 | 10 | from packaging import version
|
11 |
| -from typing import Dict, Generator |
| 11 | +from typing import Dict, Generator, Iterable |
12 | 12 |
|
13 | 13 | import lib.config as global_config
|
14 | 14 |
|
15 | 15 | from lib import pxe
|
16 |
| -from lib.common import DiskDevName |
| 16 | +from lib.common import DiskDevName, HostAddress |
17 | 17 | from lib.common import callable_marker, shortened_nodeid, prefix_object_name
|
18 | 18 | from lib.common import wait_for, vm_image, is_uuid
|
19 | 19 | from lib.common import setup_formatted_and_mounted_disk, teardown_formatted_and_mounted_disk
|
@@ -75,6 +75,14 @@ def pytest_addoption(parser):
|
75 | 75 | default=20,
|
76 | 76 | help="Max lines to output in a ssh log (0 if no limit)"
|
77 | 77 | )
|
| 78 | + parser.addoption( |
| 79 | + "--disks", |
| 80 | + action="append", |
| 81 | + default=[], |
| 82 | + help="HOST:DISKS to authorize for use by tests. " |
| 83 | + "DISKS is a possibly-empty comma-separated list. " |
| 84 | + "No mention of a given host authorizes use of all its disks." |
| 85 | + ) |
78 | 86 | parser.addoption(
|
79 | 87 | "--sr-disk",
|
80 | 88 | action="append",
|
@@ -219,6 +227,14 @@ def cleanup_hosts():
|
219 | 227 |
|
220 | 228 | cleanup_hosts()
|
221 | 229 |
|
| 230 | +@pytest.fixture(scope='session') |
| 231 | +def pools_hosts_by_name_or_ip(hosts: list[Host]) -> Generator[dict[HostAddress, Host]]: |
| 232 | + """All hosts of all pools, each indexed by their hostname_or_ip.""" |
| 233 | + yield {host.hostname_or_ip: host |
| 234 | + for pool_master in hosts |
| 235 | + for host in pool_master.pool.hosts |
| 236 | + } |
| 237 | + |
222 | 238 | @pytest.fixture(scope='session')
|
223 | 239 | def registered_xo_cli():
|
224 | 240 | # The fixture is not responsible for establishing the connection.
|
@@ -331,10 +347,32 @@ def local_sr_on_hostB1(hostB1):
|
331 | 347 | yield sr
|
332 | 348 |
|
333 | 349 | @pytest.fixture(scope='session')
|
334 |
| -def disks(hosts: list[Host]) -> Generator[dict[Host, list[DiskDevName]], None, None]: |
335 |
| - ret = {host: host.disks() |
336 |
| - for pool_master in hosts |
337 |
| - for host in pool_master.pool.hosts |
| 350 | +def disks(pytestconfig, pools_hosts_by_name_or_ip: dict[Host, Host] |
| 351 | + ) -> Generator[dict[Host, list[DiskDevName]]]: |
| 352 | + def _parse_disk_option(option_text: str) -> tuple[HostAddress, list[DiskDevName]]: |
| 353 | + parsed = option_text.split(sep=":", maxsplit=1) |
| 354 | + assert len(parsed) == 2, f"--disks option {option_text!r} is not <host>:<disk>[,<disk>]*" |
| 355 | + host_address, disks_string = parsed |
| 356 | + devices = disks_string.split(',') if disks_string else [] |
| 357 | + return host_address, devices |
| 358 | + |
| 359 | + cli_disks = dict(_parse_disk_option(option_text) |
| 360 | + for option_text in pytestconfig.getoption("disks")) |
| 361 | + |
| 362 | + def _host_disks(host: Host, hosts_cli_disks: list[DiskDevName] | None) -> Iterable[DiskDevName]: |
| 363 | + host_disks = host.disks() |
| 364 | + # no disk specified = allow all |
| 365 | + if hosts_cli_disks is None: |
| 366 | + yield from host_disks |
| 367 | + return |
| 368 | + # check all disks in --disks=host:... exist |
| 369 | + for cli_disk in hosts_cli_disks: |
| 370 | + assert cli_disk in host_disks, \ |
| 371 | + f"no {cli_disk!r} disk on host {host.hostname_or_ip}, has {','.join(host_disks)}" |
| 372 | + yield cli_disk |
| 373 | + |
| 374 | + ret = {host: list(_host_disks(host, cli_disks.get(host.hostname_or_ip))) |
| 375 | + for host in pools_hosts_by_name_or_ip.values() |
338 | 376 | }
|
339 | 377 | logging.debug("disks collected: %s", {host.hostname_or_ip: value for host, value in ret.items()})
|
340 | 378 | yield ret
|
|
0 commit comments