]>
Commit | Line | Data |
---|---|---|
3efd9988 | 1 | import os |
d2e6a577 | 2 | import pytest |
f91f0fd5 TL |
3 | from mock.mock import patch, PropertyMock, create_autospec |
4 | from ceph_volume.api import lvm | |
11fdf7f2 | 5 | from ceph_volume.util import disk |
f91f0fd5 | 6 | from ceph_volume.util import device |
494da23a | 7 | from ceph_volume.util.constants import ceph_disk_guids |
b32b8144 | 8 | from ceph_volume import conf, configuration |
3efd9988 | 9 | |
d2e6a577 FG |
10 | |
11 | class Capture(object): | |
12 | ||
13 | def __init__(self, *a, **kw): | |
14 | self.a = a | |
15 | self.kw = kw | |
16 | self.calls = [] | |
28e407b8 AA |
17 | self.return_values = kw.get('return_values', False) |
18 | self.always_returns = kw.get('always_returns', False) | |
d2e6a577 FG |
19 | |
20 | def __call__(self, *a, **kw): | |
21 | self.calls.append({'args': a, 'kwargs': kw}) | |
28e407b8 AA |
22 | if self.always_returns: |
23 | return self.always_returns | |
24 | if self.return_values: | |
25 | return self.return_values.pop() | |
d2e6a577 FG |
26 | |
27 | ||
3efd9988 FG |
28 | class Factory(object): |
29 | ||
30 | def __init__(self, **kw): | |
31 | for k, v in kw.items(): | |
32 | setattr(self, k, v) | |
33 | ||
34 | ||
35 | @pytest.fixture | |
36 | def factory(): | |
37 | return Factory | |
38 | ||
39 | ||
d2e6a577 FG |
40 | @pytest.fixture |
41 | def capture(): | |
42 | return Capture() | |
181888fb | 43 | |
f91f0fd5 TL |
44 | @pytest.fixture |
45 | def mock_lv_device_generator(): | |
46 | def mock_lv(): | |
47 | size = 21474836480 | |
48 | dev = create_autospec(device.Device) | |
49 | dev.lv_name = 'lv' | |
50 | dev.vg_name = 'vg' | |
51 | dev.path = '{}/{}'.format(dev.vg_name, dev.lv_name) | |
52 | dev.used_by_ceph = False | |
53 | dev.vg_size = [size] | |
54 | dev.vg_free = dev.vg_size | |
522d829b TL |
55 | dev.available_lvm = True |
56 | dev.is_device = False | |
f91f0fd5 TL |
57 | dev.lvs = [lvm.Volume(vg_name=dev.vg_name, lv_name=dev.lv_name, lv_size=size, lv_tags='')] |
58 | return dev | |
59 | return mock_lv | |
60 | ||
2a845540 | 61 | def mock_device(): |
f91f0fd5 TL |
62 | dev = create_autospec(device.Device) |
63 | dev.path = '/dev/foo' | |
a4b75251 TL |
64 | dev.vg_name = 'vg_foo' |
65 | dev.lv_name = 'lv_foo' | |
2a845540 | 66 | dev.symlink = None |
a4b75251 | 67 | dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] |
f91f0fd5 TL |
68 | dev.available_lvm = True |
69 | dev.vg_size = [21474836480] | |
70 | dev.vg_free = dev.vg_size | |
2a845540 TL |
71 | dev.lvs = [] |
72 | return dev | |
73 | ||
1e59de90 | 74 | @pytest.fixture(params=range(1,4)) |
2a845540 TL |
75 | def mock_devices_available(request): |
76 | ret = [] | |
1e59de90 TL |
77 | for n in range(request.param): |
78 | dev = mock_device() | |
79 | # after v15.2.8, a single VG is created for each PV | |
80 | dev.vg_name = f'vg_foo_{n}' | |
81 | dev.vgs = [lvm.VolumeGroup(vg_name=dev.vg_name, lv_name=dev.lv_name)] | |
82 | ret.append(dev) | |
2a845540 | 83 | return ret |
f91f0fd5 TL |
84 | |
85 | @pytest.fixture | |
86 | def mock_device_generator(): | |
f91f0fd5 TL |
87 | return mock_device |
88 | ||
89 | ||
90 | @pytest.fixture(params=range(1,11)) | |
91 | def osds_per_device(request): | |
92 | return request.param | |
93 | ||
181888fb | 94 | |
b32b8144 FG |
95 | @pytest.fixture |
96 | def fake_run(monkeypatch): | |
97 | fake_run = Capture() | |
98 | monkeypatch.setattr('ceph_volume.process.run', fake_run) | |
99 | return fake_run | |
100 | ||
101 | ||
102 | @pytest.fixture | |
103 | def fake_call(monkeypatch): | |
28e407b8 | 104 | fake_call = Capture(always_returns=([], [], 0)) |
b32b8144 FG |
105 | monkeypatch.setattr('ceph_volume.process.call', fake_call) |
106 | return fake_call | |
107 | ||
108 | ||
91327a77 AA |
109 | @pytest.fixture |
110 | def fakedevice(factory): | |
111 | def apply(**kw): | |
112 | params = dict( | |
113 | path='/dev/sda', | |
114 | abspath='/dev/sda', | |
115 | lv_api=None, | |
116 | pvs_api=[], | |
117 | disk_api={}, | |
118 | sys_api={}, | |
119 | exists=True, | |
120 | is_lvm_member=True, | |
121 | ) | |
122 | params.update(dict(kw)) | |
11fdf7f2 | 123 | params['lvm_size'] = disk.Size(b=params['sys_api'].get("size", 0)) |
91327a77 AA |
124 | return factory(**params) |
125 | return apply | |
126 | ||
127 | ||
b32b8144 FG |
128 | @pytest.fixture |
129 | def stub_call(monkeypatch): | |
130 | """ | |
131 | Monkeypatches process.call, so that a caller can add behavior to the response | |
132 | """ | |
28e407b8 AA |
133 | def apply(return_values): |
134 | if isinstance(return_values, tuple): | |
135 | return_values = [return_values] | |
136 | stubbed_call = Capture(return_values=return_values) | |
137 | monkeypatch.setattr('ceph_volume.process.call', stubbed_call) | |
138 | return stubbed_call | |
b32b8144 FG |
139 | |
140 | return apply | |
141 | ||
142 | ||
91327a77 AA |
143 | @pytest.fixture(autouse=True) |
144 | def reset_cluster_name(request, monkeypatch): | |
145 | """ | |
146 | The globally available ``ceph_volume.conf.cluster`` might get mangled in | |
147 | tests, make sure that after evert test, it gets reset, preventing pollution | |
148 | going into other tests later. | |
149 | """ | |
150 | def fin(): | |
151 | conf.cluster = None | |
152 | try: | |
153 | os.environ.pop('CEPH_CONF') | |
154 | except KeyError: | |
155 | pass | |
156 | request.addfinalizer(fin) | |
157 | ||
158 | ||
b32b8144 FG |
159 | @pytest.fixture |
160 | def conf_ceph(monkeypatch): | |
161 | """ | |
162 | Monkeypatches ceph_volume.conf.ceph, which is meant to parse/read | |
163 | a ceph.conf. The patching is naive, it allows one to set return values for | |
164 | specific method calls. | |
165 | """ | |
166 | def apply(**kw): | |
167 | stub = Factory(**kw) | |
168 | monkeypatch.setattr(conf, 'ceph', stub) | |
169 | return stub | |
170 | return apply | |
171 | ||
172 | ||
173 | @pytest.fixture | |
174 | def conf_ceph_stub(monkeypatch, tmpfile): | |
175 | """ | |
176 | Monkeypatches ceph_volume.conf.ceph with contents from a string that are | |
177 | written to a temporary file and then is fed through the same ceph.conf | |
178 | loading mechanisms for testing. Unlike ``conf_ceph`` which is just a fake, | |
179 | we are actually loading values as seen on a ceph.conf file | |
180 | ||
181 | This is useful when more complex ceph.conf's are needed. In the case of | |
182 | just trying to validate a key/value behavior ``conf_ceph`` is better | |
183 | suited. | |
184 | """ | |
185 | def apply(contents): | |
186 | conf_path = tmpfile(contents=contents) | |
187 | parser = configuration.load(conf_path) | |
188 | monkeypatch.setattr(conf, 'ceph', parser) | |
189 | return parser | |
190 | return apply | |
191 | ||
192 | ||
181888fb FG |
193 | @pytest.fixture |
194 | def is_root(monkeypatch): | |
195 | """ | |
196 | Patch ``os.getuid()`` so that ceph-volume's decorators that ensure a user | |
197 | is root (or is sudoing to superuser) can continue as-is | |
198 | """ | |
199 | monkeypatch.setattr('os.getuid', lambda: 0) | |
3efd9988 FG |
200 | |
201 | ||
202 | @pytest.fixture | |
203 | def tmpfile(tmpdir): | |
204 | """ | |
205 | Create a temporary file, optionally filling it with contents, returns an | |
206 | absolute path to the file when called | |
207 | """ | |
1adf2230 AA |
208 | def generate_file(name='file', contents='', directory=None): |
209 | directory = directory or str(tmpdir) | |
210 | path = os.path.join(directory, name) | |
3efd9988 FG |
211 | with open(path, 'w') as fp: |
212 | fp.write(contents) | |
213 | return path | |
214 | return generate_file | |
1adf2230 AA |
215 | |
216 | ||
494da23a TL |
217 | @pytest.fixture |
218 | def disable_kernel_queries(monkeypatch): | |
219 | ''' | |
220 | This speeds up calls to Device and Disk | |
221 | ''' | |
1e59de90 | 222 | monkeypatch.setattr("ceph_volume.util.device.disk.get_devices", lambda device='': {}) |
494da23a TL |
223 | monkeypatch.setattr("ceph_volume.util.disk.udevadm_property", lambda *a, **kw: {}) |
224 | ||
225 | ||
494da23a TL |
226 | @pytest.fixture(params=[ |
227 | '', 'ceph data', 'ceph journal', 'ceph block', | |
228 | 'ceph block.wal', 'ceph block.db', 'ceph lockbox']) | |
229 | def ceph_partlabel(request): | |
230 | return request.param | |
231 | ||
232 | ||
233 | @pytest.fixture(params=list(ceph_disk_guids.keys())) | |
234 | def ceph_parttype(request): | |
235 | return request.param | |
236 | ||
237 | ||
238 | @pytest.fixture | |
239 | def lsblk_ceph_disk_member(monkeypatch, request, ceph_partlabel, ceph_parttype): | |
240 | monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", | |
f91f0fd5 | 241 | lambda path: {'TYPE': 'disk', |
2a845540 TL |
242 | 'NAME': 'sda', |
243 | 'PARTLABEL': ceph_partlabel, | |
494da23a | 244 | 'PARTTYPE': ceph_parttype}) |
2a845540 TL |
245 | monkeypatch.setattr("ceph_volume.util.device.disk.lsblk_all", |
246 | lambda: [{'TYPE': 'disk', | |
247 | 'NAME': 'sda', | |
248 | 'PARTLABEL': ceph_partlabel, | |
249 | 'PARTTYPE': ceph_parttype}]) | |
494da23a TL |
250 | |
251 | @pytest.fixture | |
252 | def blkid_ceph_disk_member(monkeypatch, request, ceph_partlabel, ceph_parttype): | |
253 | monkeypatch.setattr("ceph_volume.util.device.disk.blkid", | |
f91f0fd5 TL |
254 | lambda path: {'TYPE': 'disk', |
255 | 'PARTLABEL': ceph_partlabel, | |
494da23a TL |
256 | 'PARTTYPE': ceph_parttype}) |
257 | ||
258 | ||
259 | @pytest.fixture(params=[ | |
260 | ('gluster partition', 'gluster partition'), | |
261 | # falls back to blkid | |
262 | ('', 'gluster partition'), | |
263 | ('gluster partition', ''), | |
264 | ]) | |
265 | def device_info_not_ceph_disk_member(monkeypatch, request): | |
266 | monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", | |
f91f0fd5 | 267 | lambda path: {'TYPE': 'disk', |
2a845540 | 268 | 'NAME': 'sda', |
f91f0fd5 | 269 | 'PARTLABEL': request.param[0]}) |
2a845540 TL |
270 | monkeypatch.setattr("ceph_volume.util.device.disk.lsblk_all", |
271 | lambda: [{'TYPE': 'disk', | |
272 | 'NAME': 'sda', | |
273 | 'PARTLABEL': request.param[0]}]) | |
494da23a | 274 | monkeypatch.setattr("ceph_volume.util.device.disk.blkid", |
f91f0fd5 TL |
275 | lambda path: {'TYPE': 'disk', |
276 | 'PARTLABEL': request.param[1]}) | |
494da23a | 277 | |
92f5a8d4 | 278 | @pytest.fixture |
2a845540 TL |
279 | def patched_get_block_devs_sysfs(): |
280 | with patch('ceph_volume.util.disk.get_block_devs_sysfs') as p: | |
92f5a8d4 TL |
281 | yield p |
282 | ||
283 | @pytest.fixture | |
284 | def patch_bluestore_label(): | |
285 | with patch('ceph_volume.util.device.Device.has_bluestore_label', | |
286 | new_callable=PropertyMock) as p: | |
287 | p.return_value = False | |
288 | yield p | |
494da23a | 289 | |
1adf2230 | 290 | @pytest.fixture |
92f5a8d4 TL |
291 | def device_info(monkeypatch, patch_bluestore_label): |
292 | def apply(devices=None, lsblk=None, lv=None, blkid=None, udevadm=None, | |
293 | has_bluestore_label=False): | |
2a845540 TL |
294 | if devices: |
295 | for dev in devices.keys(): | |
296 | devices[dev]['device_nodes'] = os.path.basename(dev) | |
297 | else: | |
298 | devices = {} | |
1adf2230 | 299 | lsblk = lsblk if lsblk else {} |
91327a77 | 300 | blkid = blkid if blkid else {} |
f64942e4 | 301 | udevadm = udevadm if udevadm else {} |
1adf2230 AA |
302 | lv = Factory(**lv) if lv else None |
303 | monkeypatch.setattr("ceph_volume.sys_info.devices", {}) | |
1e59de90 | 304 | monkeypatch.setattr("ceph_volume.util.device.disk.get_devices", lambda device='': devices) |
91327a77 | 305 | if not devices: |
a4b75251 | 306 | monkeypatch.setattr("ceph_volume.util.device.lvm.get_single_lv", lambda filters: lv) |
91327a77 | 307 | else: |
92f5a8d4 TL |
308 | monkeypatch.setattr("ceph_volume.util.device.lvm.get_device_lvs", |
309 | lambda path: [lv]) | |
1adf2230 | 310 | monkeypatch.setattr("ceph_volume.util.device.disk.lsblk", lambda path: lsblk) |
91327a77 | 311 | monkeypatch.setattr("ceph_volume.util.device.disk.blkid", lambda path: blkid) |
f64942e4 | 312 | monkeypatch.setattr("ceph_volume.util.disk.udevadm_property", lambda *a, **kw: udevadm) |
1adf2230 | 313 | return apply |
20effc67 TL |
314 | |
315 | @pytest.fixture(params=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.999, 1.0]) | |
316 | def data_allocate_fraction(request): | |
317 | return request.param | |
2a845540 TL |
318 | |
319 | @pytest.fixture | |
320 | def fake_filesystem(fs): | |
321 | ||
322 | fs.create_dir('/sys/block/sda/slaves') | |
323 | fs.create_dir('/sys/block/sda/queue') | |
324 | fs.create_dir('/sys/block/rbd0') | |
325 | yield fs |