-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathconftest.py
More file actions
226 lines (189 loc) · 7.34 KB
/
Copy pathconftest.py
File metadata and controls
226 lines (189 loc) · 7.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
from __future__ import annotations
import pytest
import functools
import json
import logging
import os
from contextlib import contextmanager
from dataclasses import dataclass
import lib.commands as commands
from lib import config
from lib.common import safe_split
try:
from data import LINSTOR_REDUNDANCY # type: ignore
except ImportError:
LINSTOR_REDUNDANCY = 2
# explicit import for package-scope fixtures
from pkgfixtures import (
_xfs_config_on_hostA2,
_xfs_config_on_hostB1,
hostA2_with_xfsprogs,
hostB1_with_xfsprogs,
pool_with_saved_yum_state,
xfs_sr_on_hostA2,
xfs_sr_on_hostB1,
)
from typing import TYPE_CHECKING, Generator
if TYPE_CHECKING:
from lib.host import Host
from lib.pool import Pool
from lib.sr import SR
from lib.vdi import VDI
from lib.vm import VM
GROUP_NAME = 'linstor_group'
STORAGE_POOL_NAME = f'{GROUP_NAME}/thin_device'
LINSTOR_RELEASE_PACKAGE = 'xcp-ng-release-linstor'
LINSTOR_PACKAGE = 'xcp-ng-linstor'
@dataclass
class LinstorConfig:
uninstall_linstor: bool = True
@pytest.fixture(scope='package')
def _linstor_config() -> LinstorConfig:
return LinstorConfig()
@pytest.fixture(scope='package')
def lvm_disks(
pool_with_unused_512B_disk: Pool,
unused_512B_disks: dict[Host, list[Host.BlockDeviceInfo]],
provisioning_type: str,
) -> Generator[None, None, None]:
"""
Common LVM PVs on which a LV is created on each host of the pool.
On each host in the pool, create PV on each of those disks whose
DEVICE NAME exists ACROSS THE WHOLE POOL. Then make a VG out of
all those, then a LV taking up the whole VG space.
Return the list of device node paths for that list of devices
used in all hosts.
"""
hosts = pool_with_unused_512B_disk.hosts
@functools.cache
def host_devices(host: Host) -> list[str]:
return [disk.path for disk in unused_512B_disks[host][0:1]]
for host in hosts:
devices = host_devices(host)
for device in devices:
try:
host.ssh(f'pvcreate -ff -y {device}')
except commands.SSHCommandFailed as e:
if e.stdout.endswith('Mounted filesystem?'):
host.ssh(f'vgremove -f {GROUP_NAME} -y')
host.ssh(f'pvcreate -ff -y {device}')
elif e.stdout.endswith('excluded by a filter.'):
host.ssh(f'wipefs -a {device}')
host.ssh(f'pvcreate -ff -y {device}')
else:
raise e
host.ssh(f'vgcreate {GROUP_NAME} ' + ' '.join(devices))
if provisioning_type == 'thin':
host.ssh(f'lvcreate -l 100%FREE -T {STORAGE_POOL_NAME}')
# FIXME ought to provide storage_pool_name and get rid of that other fixture
yield None
for host in hosts:
host.ssh(f'vgremove -f {GROUP_NAME}')
for device in host_devices(host):
host.ssh(f'pvremove {device}')
@pytest.fixture(scope="package")
def storage_pool_name(provisioning_type: str) -> str:
return GROUP_NAME if provisioning_type == "thick" else STORAGE_POOL_NAME
@pytest.fixture(params=["thin"], scope="session")
def provisioning_type(request: pytest.FixtureRequest) -> str:
return request.param
@pytest.fixture(scope='package')
def pool_with_linstor(
hostA2: Host,
lvm_disks: None,
pool_with_saved_yum_state: Pool,
_linstor_config: LinstorConfig
) -> Generator[Pool, None, None]:
import concurrent.futures
pool = pool_with_saved_yum_state
def check_linstor_installed(host: Host) -> None:
if host.is_package_installed(LINSTOR_PACKAGE):
raise Exception(
f'{LINSTOR_PACKAGE} is already installed on host {host}. This should not be the case.'
)
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(check_linstor_installed, pool.hosts)
def install_linstor(host: Host) -> None:
logging.info(f"Installing {LINSTOR_PACKAGE} on host {host}...")
host.yum_install([LINSTOR_RELEASE_PACKAGE])
host.yum_install([LINSTOR_PACKAGE], enablerepo="xcp-ng-linstor-testing")
# Needed because the linstor driver is not in the xapi sm-plugins list
# before installing the LINSTOR packages.
host.ssh('systemctl restart multipathd')
host.restart_toolstack(verify=True)
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(install_linstor, pool.hosts)
yield pool
def _disable_yum_rollback(host: Host) -> None:
host.saved_rollback_id = None
if not _linstor_config.uninstall_linstor:
pool.exec_on_hosts_on_error_continue(_disable_yum_rollback)
return
# Need to remove this package as we have separate run of `test_create_sr_without_linstor`
# for `thin` and `thick` `provisioning_type`.
def remove_linstor(host: Host) -> None:
logging.info(f"Cleaning up python-linstor from host {host}...")
host.yum_remove(["python-linstor"])
host.restart_toolstack(verify=True)
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(remove_linstor, pool.hosts)
@pytest.fixture(scope='package')
def linstor_redundancy(pool_with_linstor: Pool) -> int:
return min(len(pool_with_linstor.hosts), LINSTOR_REDUNDANCY)
@pytest.fixture(scope='package')
def linstor_sr(
pool_with_linstor: Pool,
linstor_redundancy: int,
provisioning_type: str,
storage_pool_name: str,
lvm_disks: None,
_linstor_config: LinstorConfig
) -> Generator[SR, None, None]:
sr = pool_with_linstor.master.sr_create('linstor', 'LINSTOR-SR-test', {
'group-name': storage_pool_name,
'redundancy': str(linstor_redundancy),
'provisioning': provisioning_type
}, shared=True)
yield sr
try:
sr.destroy()
except Exception as e:
_linstor_config.uninstall_linstor = False
raise pytest.fail("Could not destroy linstor SR, leaving packages in place for manual cleanup") from e
@pytest.fixture(scope='module')
def vdi_on_linstor_sr(linstor_sr: SR) -> Generator[VDI, None, None]:
vdi = linstor_sr.create_vdi('LINSTOR-VDI-test', virtual_size=config.volume_size)
yield vdi
vdi.destroy()
@contextmanager
def _vm_on_linstor_sr(host: Host, linstor_sr: SR, vm_ref: str) -> Generator[VM]:
"""
Context manager to provide the fixture lifecycle on a VM on a Linstor SR
with different scopes without repeating the code.
"""
vm = host.import_vm(vm_ref, sr_uuid=linstor_sr.uuid)
try:
yield vm
finally:
logging.info("<< Destroy VM")
vm.destroy(verify=True)
@pytest.fixture(scope='module')
def vm_on_linstor_sr(host: Host, linstor_sr: SR, vm_ref: str) -> Generator[VM, None, None]:
with _vm_on_linstor_sr(host, linstor_sr, vm_ref) as vm:
yield vm
@pytest.fixture(scope='function')
def vm_on_linstor_sr_function(host: Host, linstor_sr: SR, vm_ref: str) -> Generator[VM]:
with _vm_on_linstor_sr(host, linstor_sr, vm_ref) as vm:
yield vm
@pytest.fixture(scope='function')
def linstor_no_monitor(linstor_sr: SR):
"""
Disable linstor monitor on the linstor SR for
the current test to avoid unwanted scans.
"""
hosts = linstor_sr.main_host().pool.hosts
for host in hosts:
host.ssh("systemctl stop linstor-monitor.service")
yield
for host in hosts:
host.ssh("systemctl start linstor-monitor.service")