]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/tests/util/test_prepare.py
update sources to 12.2.8
[ceph.git] / ceph / src / ceph-volume / ceph_volume / tests / util / test_prepare.py
1 import pytest
2 from textwrap import dedent
3 import json
4 from ceph_volume.util import prepare
5 from ceph_volume.util.prepare import system
6 from ceph_volume import conf
7 from ceph_volume.tests.conftest import Factory
8
9
10 class TestOSDIDAvailable(object):
11
12 def test_false_if_id_is_none(self):
13 assert not prepare.osd_id_available(None)
14
15 def test_returncode_is_not_zero(self, monkeypatch):
16 monkeypatch.setattr('ceph_volume.process.call', lambda *a, **kw: ('', '', 1))
17 with pytest.raises(RuntimeError):
18 prepare.osd_id_available(1)
19
20 def test_id_does_exist_but_not_available(self, monkeypatch):
21 stdout = dict(nodes=[
22 dict(id=0, status="up"),
23 ])
24 stdout = ['', json.dumps(stdout)]
25 monkeypatch.setattr('ceph_volume.process.call', lambda *a, **kw: (stdout, '', 0))
26 result = prepare.osd_id_available(0)
27 assert not result
28
29 def test_id_does_not_exist(self, monkeypatch):
30 stdout = dict(nodes=[
31 dict(id=0),
32 ])
33 stdout = ['', json.dumps(stdout)]
34 monkeypatch.setattr('ceph_volume.process.call', lambda *a, **kw: (stdout, '', 0))
35 result = prepare.osd_id_available(1)
36 assert not result
37
38 def test_invalid_osd_id(self, monkeypatch):
39 stdout = dict(nodes=[
40 dict(id=0),
41 ])
42 stdout = ['', json.dumps(stdout)]
43 monkeypatch.setattr('ceph_volume.process.call', lambda *a, **kw: (stdout, '', 0))
44 result = prepare.osd_id_available("foo")
45 assert not result
46
47 def test_returns_true_when_id_is_destroyed(self, monkeypatch):
48 stdout = dict(nodes=[
49 dict(id=0, status="destroyed"),
50 ])
51 stdout = ['', json.dumps(stdout)]
52 monkeypatch.setattr('ceph_volume.process.call', lambda *a, **kw: (stdout, '', 0))
53 result = prepare.osd_id_available(0)
54 assert result
55
56
57 class TestFormatDevice(object):
58
59 def test_include_force(self, fake_run, monkeypatch):
60 monkeypatch.setattr(conf, 'ceph', Factory(get_list=lambda *a, **kw: []))
61 prepare.format_device('/dev/sxx')
62 flags = fake_run.calls[0]['args'][0]
63 assert '-f' in flags
64
65 def test_device_is_always_appended(self, fake_run, conf_ceph):
66 conf_ceph(get_list=lambda *a, **kw: [])
67 prepare.format_device('/dev/sxx')
68 flags = fake_run.calls[0]['args'][0]
69 assert flags[-1] == '/dev/sxx'
70
71 def test_extra_flags_are_added(self, fake_run, conf_ceph):
72 conf_ceph(get_list=lambda *a, **kw: ['--why-yes'])
73 prepare.format_device('/dev/sxx')
74 flags = fake_run.calls[0]['args'][0]
75 assert '--why-yes' in flags
76
77 def test_default_options(self, conf_ceph_stub, fake_run):
78 conf_ceph_stub(dedent("""[global]
79 fsid = 1234lkjh1234"""))
80 conf.cluster = 'ceph'
81 prepare.format_device('/dev/sda1')
82 expected = [
83 'mkfs', '-t', 'xfs',
84 '-f', '-i', 'size=2048', # default flags
85 '/dev/sda1']
86 assert expected == fake_run.calls[0]['args'][0]
87
88 def test_multiple_options_are_used(self, conf_ceph_stub, fake_run):
89 conf_ceph_stub(dedent("""[global]
90 fsid = 1234lkjh1234
91 [osd]
92 osd mkfs options xfs = -f -i size=1024"""))
93 conf.cluster = 'ceph'
94 prepare.format_device('/dev/sda1')
95 expected = [
96 'mkfs', '-t', 'xfs',
97 '-f', '-i', 'size=1024',
98 '/dev/sda1']
99 assert expected == fake_run.calls[0]['args'][0]
100
101 def test_multiple_options_will_get_the_force_flag(self, conf_ceph_stub, fake_run):
102 conf_ceph_stub(dedent("""[global]
103 fsid = 1234lkjh1234
104 [osd]
105 osd mkfs options xfs = -i size=1024"""))
106 conf.cluster = 'ceph'
107 prepare.format_device('/dev/sda1')
108 expected = [
109 'mkfs', '-t', 'xfs',
110 '-f', '-i', 'size=1024',
111 '/dev/sda1']
112 assert expected == fake_run.calls[0]['args'][0]
113
114 def test_underscore_options_are_used(self, conf_ceph_stub, fake_run):
115 conf_ceph_stub(dedent("""[global]
116 fsid = 1234lkjh1234
117 [osd]
118 osd_mkfs_options_xfs = -i size=128"""))
119 conf.cluster = 'ceph'
120 prepare.format_device('/dev/sda1')
121 expected = [
122 'mkfs', '-t', 'xfs',
123 '-f', '-i', 'size=128',
124 '/dev/sda1']
125 assert expected == fake_run.calls[0]['args'][0]
126
127
128 mkfs_filestore_flags = [
129 'ceph-osd',
130 '--cluster',
131 '--osd-objectstore', 'filestore',
132 '--mkfs',
133 '-i',
134 '--monmap',
135 '--keyfile', '-', # goes through stdin
136 '--osd-data',
137 '--osd-journal',
138 '--osd-uuid',
139 '--setuser', 'ceph',
140 '--setgroup', 'ceph'
141 ]
142
143
144 class TestOsdMkfsFilestore(object):
145
146 @pytest.mark.parametrize('flag', mkfs_filestore_flags)
147 def test_keyring_is_used(self, fake_call, monkeypatch, flag):
148 monkeypatch.setattr(prepare, '__release__', 'mimic')
149 monkeypatch.setattr(system, 'chown', lambda path: True)
150 prepare.osd_mkfs_filestore(1, 'asdf', keyring='secret')
151 assert flag in fake_call.calls[0]['args'][0]
152
153 def test_keyring_is_used_luminous(self, fake_call, monkeypatch):
154 monkeypatch.setattr(prepare, '__release__', 'luminous')
155 monkeypatch.setattr(system, 'chown', lambda path: True)
156 prepare.osd_mkfs_filestore(1, 'asdf', keyring='secret')
157 assert '--keyfile' not in fake_call.calls[0]['args'][0]
158
159
160 class TestOsdMkfsBluestore(object):
161
162 def test_keyring_is_added(self, fake_call, monkeypatch):
163 monkeypatch.setattr(system, 'chown', lambda path: True)
164 prepare.osd_mkfs_bluestore(1, 'asdf', keyring='secret')
165 assert '--keyfile' in fake_call.calls[0]['args'][0]
166
167 def test_keyring_is_not_added(self, fake_call, monkeypatch):
168 monkeypatch.setattr(system, 'chown', lambda path: True)
169 prepare.osd_mkfs_bluestore(1, 'asdf')
170 assert '--keyfile' not in fake_call.calls[0]['args'][0]
171
172 def test_keyring_is_not_added_luminous(self, fake_call, monkeypatch):
173 monkeypatch.setattr(system, 'chown', lambda path: True)
174 prepare.osd_mkfs_bluestore(1, 'asdf')
175 monkeypatch.setattr(prepare, '__release__', 'luminous')
176 assert '--keyfile' not in fake_call.calls[0]['args'][0]
177
178 def test_wal_is_added(self, fake_call, monkeypatch):
179 monkeypatch.setattr(system, 'chown', lambda path: True)
180 prepare.osd_mkfs_bluestore(1, 'asdf', wal='/dev/smm1')
181 assert '--bluestore-block-wal-path' in fake_call.calls[0]['args'][0]
182 assert '/dev/smm1' in fake_call.calls[0]['args'][0]
183
184 def test_db_is_added(self, fake_call, monkeypatch):
185 monkeypatch.setattr(system, 'chown', lambda path: True)
186 prepare.osd_mkfs_bluestore(1, 'asdf', db='/dev/smm2')
187 assert '--bluestore-block-db-path' in fake_call.calls[0]['args'][0]
188 assert '/dev/smm2' in fake_call.calls[0]['args'][0]
189
190
191 class TestMountOSD(object):
192
193 def test_default_options(self, conf_ceph_stub, fake_run):
194 conf_ceph_stub(dedent("""[global]
195 fsid = 1234lkjh1234"""))
196 conf.cluster = 'ceph'
197 prepare.mount_osd('/dev/sda1', 1)
198 expected = [
199 'mount', '-t', 'xfs', '-o',
200 'rw,noatime,inode64', # default flags
201 '/dev/sda1', '/var/lib/ceph/osd/ceph-1']
202 assert expected == fake_run.calls[0]['args'][0]
203
204 def test_mount_options_are_used(self, conf_ceph_stub, fake_run):
205 conf_ceph_stub(dedent("""[global]
206 fsid = 1234lkjh1234
207 [osd]
208 osd mount options xfs = rw"""))
209 conf.cluster = 'ceph'
210 prepare.mount_osd('/dev/sda1', 1)
211 expected = [
212 'mount', '-t', 'xfs', '-o',
213 'rw',
214 '/dev/sda1', '/var/lib/ceph/osd/ceph-1']
215 assert expected == fake_run.calls[0]['args'][0]
216
217 def test_multiple_whitespace_options_are_used(self, conf_ceph_stub, fake_run):
218 conf_ceph_stub(dedent("""[global]
219 fsid = 1234lkjh1234
220 [osd]
221 osd mount options xfs = rw auto exec"""))
222 conf.cluster = 'ceph'
223 prepare.mount_osd('/dev/sda1', 1)
224 expected = [
225 'mount', '-t', 'xfs', '-o',
226 'rw,auto,exec',
227 '/dev/sda1', '/var/lib/ceph/osd/ceph-1']
228 assert expected == fake_run.calls[0]['args'][0]
229
230 def test_multiple_comma_whitespace_options_are_used(self, conf_ceph_stub, fake_run):
231 conf_ceph_stub(dedent("""[global]
232 fsid = 1234lkjh1234
233 [osd]
234 osd mount options xfs = rw, auto, exec"""))
235 conf.cluster = 'ceph'
236 prepare.mount_osd('/dev/sda1', 1)
237 expected = [
238 'mount', '-t', 'xfs', '-o',
239 'rw,auto,exec',
240 '/dev/sda1', '/var/lib/ceph/osd/ceph-1']
241 assert expected == fake_run.calls[0]['args'][0]
242
243 def test_underscore_mount_options_are_used(self, conf_ceph_stub, fake_run):
244 conf_ceph_stub(dedent("""[global]
245 fsid = 1234lkjh1234
246 [osd]
247 osd mount options xfs = rw"""))
248 conf.cluster = 'ceph'
249 prepare.mount_osd('/dev/sda1', 1)
250 expected = [
251 'mount', '-t', 'xfs', '-o',
252 'rw',
253 '/dev/sda1', '/var/lib/ceph/osd/ceph-1']
254 assert expected == fake_run.calls[0]['args'][0]
255
256
257 ceph_conf_mount_values = [
258 ['rw,', 'auto,' 'exec'],
259 ['rw', 'auto', 'exec'],
260 [' rw ', ' auto ', ' exec '],
261 ['rw,', 'auto,', 'exec,'],
262 [',rw ', ',auto ', ',exec,'],
263 [',rw,', ',auto,', ',exec,'],
264 ]
265
266 string_mount_values = [
267 'rw, auto exec ',
268 'rw auto exec',
269 ',rw, auto, exec,',
270 ' rw auto exec ',
271 ' rw,auto,exec ',
272 'rw,auto,exec',
273 ',rw,auto,exec,',
274 'rw,auto,exec ',
275 'rw, auto, exec ',
276 ]
277
278
279 class TestNormalizeFlags(object):
280 # a bit overkill since most of this is already tested in prepare.mount_osd
281 # tests
282
283 @pytest.mark.parametrize("flags", ceph_conf_mount_values)
284 def test_normalize_lists(self, flags):
285 result = sorted(prepare._normalize_mount_flags(flags).split(','))
286 assert ','.join(result) == 'auto,exec,rw'
287
288 @pytest.mark.parametrize("flags", string_mount_values)
289 def test_normalize_strings(self, flags):
290 result = sorted(prepare._normalize_mount_flags(flags).split(','))
291 assert ','.join(result) == 'auto,exec,rw'
292
293 @pytest.mark.parametrize("flags", ceph_conf_mount_values)
294 def test_normalize_extra_flags(self, flags):
295 result = prepare._normalize_mount_flags(flags, extras=['discard'])
296 assert sorted(result.split(',')) == ['auto', 'discard', 'exec', 'rw']
297
298 @pytest.mark.parametrize("flags", ceph_conf_mount_values)
299 def test_normalize_duplicate_extra_flags(self, flags):
300 result = prepare._normalize_mount_flags(flags, extras=['rw', 'discard'])
301 assert sorted(result.split(',')) == ['auto', 'discard', 'exec', 'rw']
302
303 @pytest.mark.parametrize("flags", string_mount_values)
304 def test_normalize_strings_flags(self, flags):
305 result = sorted(prepare._normalize_mount_flags(flags, extras=['discard']).split(','))
306 assert ','.join(result) == 'auto,discard,exec,rw'
307
308 @pytest.mark.parametrize("flags", string_mount_values)
309 def test_normalize_strings_duplicate_flags(self, flags):
310 result = sorted(prepare._normalize_mount_flags(flags, extras=['discard','rw']).split(','))
311 assert ','.join(result) == 'auto,discard,exec,rw'
312
313
314 class TestMkfsBluestore(object):
315
316 def test_non_zero_exit_status(self, stub_call, monkeypatch):
317 conf.cluster = 'ceph'
318 monkeypatch.setattr('ceph_volume.util.prepare.system.chown', lambda x: True)
319 stub_call(([], [], 1))
320 with pytest.raises(RuntimeError) as error:
321 prepare.osd_mkfs_bluestore('1', 'asdf-1234', keyring='keyring')
322 assert "Command failed with exit code 1" in str(error)
323
324 def test_non_zero_exit_formats_command_correctly(self, stub_call, monkeypatch):
325 conf.cluster = 'ceph'
326 monkeypatch.setattr('ceph_volume.util.prepare.system.chown', lambda x: True)
327 stub_call(([], [], 1))
328 with pytest.raises(RuntimeError) as error:
329 prepare.osd_mkfs_bluestore('1', 'asdf-1234', keyring='keyring')
330 expected = ' '.join([
331 'ceph-osd',
332 '--cluster',
333 'ceph',
334 '--osd-objectstore', 'bluestore', '--mkfs',
335 '-i', '1', '--monmap', '/var/lib/ceph/osd/ceph-1/activate.monmap',
336 '--keyfile', '-', '--osd-data', '/var/lib/ceph/osd/ceph-1/',
337 '--osd-uuid', 'asdf-1234',
338 '--setuser', 'ceph', '--setgroup', 'ceph'])
339 assert expected in str(error)
340
341
342 class TestGetJournalSize(object):
343
344 def test_undefined_size_fallbacks_formatted(self, conf_ceph_stub):
345 conf_ceph_stub(dedent("""
346 [global]
347 fsid = a25d19a6-7d57-4eda-b006-78e35d2c4d9f
348 """))
349 result = prepare.get_journal_size()
350 assert result == '5G'
351
352 def test_undefined_size_fallbacks_unformatted(self, conf_ceph_stub):
353 conf_ceph_stub(dedent("""
354 [global]
355 fsid = a25d19a6-7d57-4eda-b006-78e35d2c4d9f
356 """))
357 result = prepare.get_journal_size(lv_format=False)
358 assert result.gb.as_int() == 5
359
360 def test_defined_size_unformatted(self, conf_ceph_stub):
361 conf_ceph_stub(dedent("""
362 [global]
363 fsid = a25d19a6-7d57-4eda-b006-78e35d2c4d9f
364
365 [osd]
366 osd journal size = 10240
367 """))
368 result = prepare.get_journal_size(lv_format=False)
369 assert result.gb.as_int() == 10
370
371 def test_defined_size_formatted(self, conf_ceph_stub):
372 conf_ceph_stub(dedent("""
373 [global]
374 fsid = a25d19a6-7d57-4eda-b006-78e35d2c4d9f
375
376 [osd]
377 osd journal size = 10240
378 """))
379 result = prepare.get_journal_size()
380 assert result == '10G'
381
382 def test_refuse_tiny_journals(self, conf_ceph_stub):
383 conf_ceph_stub(dedent("""
384 [global]
385 fsid = a25d19a6-7d57-4eda-b006-78e35d2c4d9f
386
387 [osd]
388 osd journal size = 1024
389 """))
390 with pytest.raises(RuntimeError) as error:
391 prepare.get_journal_size()
392 assert 'journal sizes must be larger' in str(error)
393 assert 'detected: 1024.00 MB' in str(error)