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