|
1 | 1 | import itertools
|
2 | 2 | import git
|
3 | 3 | import logging
|
| 4 | +import os |
4 | 5 | import pytest
|
5 | 6 | import tempfile
|
6 | 7 |
|
|
9 | 10 |
|
10 | 11 | import lib.config as global_config
|
11 | 12 |
|
| 13 | +from lib import pxe |
12 | 14 | from lib.common import callable_marker, shortened_nodeid, prefix_object_name
|
13 | 15 | from lib.common import wait_for, vm_image, is_uuid
|
14 | 16 | from lib.common import setup_formatted_and_mounted_disk, teardown_formatted_and_mounted_disk
|
|
33 | 35 | # pytest hooks
|
34 | 36 |
|
35 | 37 | def pytest_addoption(parser):
|
| 38 | + parser.addoption( |
| 39 | + "--nest", |
| 40 | + action="store", |
| 41 | + default=None, |
| 42 | + help="XCP-ng or XS master of pool to use for nesting hosts under test", |
| 43 | + ) |
36 | 44 | parser.addoption(
|
37 | 45 | "--hosts",
|
38 | 46 | action="append",
|
@@ -142,20 +150,71 @@ def pytest_runtest_makereport(item, call):
|
142 | 150 |
|
143 | 151 | @pytest.fixture(scope='session')
|
144 | 152 | def hosts(pytestconfig):
|
145 |
| - def setup_host(hostname_or_ip): |
| 153 | + nested_list = [] |
| 154 | + |
| 155 | + def setup_host(hostname_or_ip, *, config=None): |
| 156 | + host_vm = None |
| 157 | + if hostname_or_ip.startswith("cache://"): |
| 158 | + if config is None: |
| 159 | + raise RuntimeError("setup_host: a cache:// host requires --nest") |
| 160 | + nest_hostname = config.getoption("nest") |
| 161 | + if not nest_hostname: |
| 162 | + pytest.fail("--hosts=cache://... requires --nest parameter") |
| 163 | + nest = Pool(nest_hostname).master |
| 164 | + |
| 165 | + protocol, rest = hostname_or_ip.split(":", 1) |
| 166 | + host_vm = nest.import_vm(f"clone:{rest}", nest.main_sr_uuid(), |
| 167 | + use_cache=True) |
| 168 | + nested_list.append(host_vm) |
| 169 | + |
| 170 | + vif = host_vm.vifs()[0] |
| 171 | + mac_address = vif.param_get('MAC') |
| 172 | + logging.info("Nested host has MAC %s", mac_address) |
| 173 | + |
| 174 | + host_vm.start() |
| 175 | + wait_for(host_vm.is_running, "Wait for nested host VM running") |
| 176 | + |
| 177 | + # catch host-vm IP address |
| 178 | + wait_for(lambda: pxe.arp_addresses_for(mac_address), |
| 179 | + "Wait for DHCP server to see nested host in ARP tables", |
| 180 | + timeout_secs=10 * 60) |
| 181 | + ips = pxe.arp_addresses_for(mac_address) |
| 182 | + logging.info("Nested host has IPs %s", ips) |
| 183 | + assert len(ips) == 1 |
| 184 | + host_vm.ip = ips[0] |
| 185 | + |
| 186 | + wait_for(lambda: not os.system(f"nc -zw5 {host_vm.ip} 22"), |
| 187 | + "Wait for ssh up on nested host", retry_delay_secs=5) |
| 188 | + |
| 189 | + hostname_or_ip = host_vm.ip |
| 190 | + |
146 | 191 | pool = Pool(hostname_or_ip)
|
147 | 192 | h = pool.master
|
148 | 193 | return h
|
149 | 194 |
|
| 195 | + def cleanup_hosts(): |
| 196 | + for vm in nested_list: |
| 197 | + logging.info("Destroying nested host VM %s", vm.uuid) |
| 198 | + vm.destroy(verify=True) |
| 199 | + |
150 | 200 | # a list of master hosts, each from a different pool
|
151 | 201 | hosts_args = pytestconfig.getoption("hosts")
|
152 | 202 | hosts_split = [hostlist.split(',') for hostlist in hosts_args]
|
153 | 203 | hostname_list = list(itertools.chain(*hosts_split))
|
154 |
| - host_list = [setup_host(hostname_or_ip) for hostname_or_ip in hostname_list] |
| 204 | + |
| 205 | + try: |
| 206 | + host_list = [setup_host(hostname_or_ip, config=pytestconfig) |
| 207 | + for hostname_or_ip in hostname_list] |
| 208 | + except Exception: |
| 209 | + cleanup_hosts() |
| 210 | + raise |
| 211 | + |
155 | 212 | if not host_list:
|
156 | 213 | pytest.fail("This test requires at least one --hosts parameter")
|
157 | 214 | yield host_list
|
158 | 215 |
|
| 216 | + cleanup_hosts() |
| 217 | + |
159 | 218 | @pytest.fixture(scope='session')
|
160 | 219 | def registered_xo_cli():
|
161 | 220 | # The fixture is not responsible for establishing the connection.
|
|
0 commit comments