]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-disk/tests/test_main.py
ef6d7d4456e67af0911ab64d7a73bc26fb12d606
[ceph.git] / ceph / src / ceph-disk / tests / test_main.py
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2015, 2016 Red Hat <contact@redhat.com>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Library Public License as published by
7 # the Free Software Foundation; either version 2, or (at your option)
8 # any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Library Public License for more details.
14 #
15 from mock import patch, DEFAULT
16 import os
17 import platform
18 import io
19 import shutil
20 import subprocess
21 import tempfile
22 import unittest
23 from ceph_disk import main
24
25 try:
26 import builtins
27 except:
28 import __builtin__ as builtins
29
30
31 def fail_to_mount(dev, fstype, options):
32 raise main.MountError(dev + " mount fail")
33
34
35 class TestCephDisk(object):
36
37 def setup_class(self):
38 main.setup_logging(verbose=True, log_stdout=False)
39
40 def test_main_list_json(self, capsys):
41 if platform.system() == "FreeBSD":
42 return
43
44 data = tempfile.mkdtemp()
45 main.setup_statedir(data)
46 args = main.parse_args(['list', '--format', 'json'])
47 with patch.multiple(
48 main,
49 list_devices=lambda: {}):
50 main.main_list(args)
51 out, err = capsys.readouterr()
52 assert '{}\n' == out
53 shutil.rmtree(data)
54
55 def test_main_list_plain(self, capsys):
56 if platform.system() == "FreeBSD":
57 return
58
59 data = tempfile.mkdtemp()
60 main.setup_statedir(data)
61 args = main.parse_args(['list'])
62 with patch.multiple(
63 main,
64 list_devices=lambda: {}):
65 main.main_list(args)
66 out, err = capsys.readouterr()
67 assert '' == out
68 shutil.rmtree(data)
69
70 def test_list_format_more_osd_info_plain(self):
71 dev = {
72 'ceph_fsid': 'UUID',
73 'cluster': 'ceph',
74 'whoami': '1234',
75 'journal_dev': '/dev/Xda2',
76 }
77 out = main.list_format_more_osd_info_plain(dev)
78 assert dev['cluster'] in " ".join(out)
79 assert dev['journal_dev'] in " ".join(out)
80 assert dev['whoami'] in " ".join(out)
81
82 dev = {
83 'ceph_fsid': 'UUID',
84 'whoami': '1234',
85 'journal_dev': '/dev/Xda2',
86 }
87 out = main.list_format_more_osd_info_plain(dev)
88 assert 'unknown cluster' in " ".join(out)
89
90 def test_list_format_plain(self):
91 payload = [{
92 'path': '/dev/Xda',
93 'ptype': 'unknown',
94 'type': 'other',
95 'mount': '/somewhere',
96 }]
97 out = main.list_format_plain(payload)
98 assert payload[0]['path'] in out
99 assert payload[0]['type'] in out
100 assert payload[0]['mount'] in out
101
102 payload = [{
103 'path': '/dev/Xda1',
104 'ptype': 'unknown',
105 'type': 'swap',
106 }]
107 out = main.list_format_plain(payload)
108 assert payload[0]['path'] in out
109 assert payload[0]['type'] in out
110
111 payload = [{
112 'path': '/dev/Xda',
113 'partitions': [
114 {
115 'dmcrypt': {},
116 'ptype': 'whatever',
117 'is_partition': True,
118 'fs_type': 'ext4',
119 'path': '/dev/Xda1',
120 'mounted': '/somewhere',
121 'type': 'other',
122 }
123 ],
124 }]
125 out = main.list_format_plain(payload)
126 assert payload[0]['path'] in out
127 assert payload[0]['partitions'][0]['path'] in out
128
129 def test_list_format_dev_plain(dev):
130 #
131 # data
132 #
133 dev = {
134 'path': '/dev/Xda1',
135 'ptype': main.PTYPE['regular']['osd']['ready'],
136 'state': 'prepared',
137 'whoami': '1234',
138 }
139 out = main.list_format_dev_plain(dev)
140 assert 'data' in out
141 assert dev['whoami'] in out
142 assert dev['state'] in out
143 #
144 # journal
145 #
146 dev = {
147 'path': '/dev/Xda2',
148 'ptype': main.PTYPE['regular']['journal']['ready'],
149 'journal_for': '/dev/Xda1',
150 }
151 out = main.list_format_dev_plain(dev)
152 assert 'journal' in out
153 assert dev['journal_for'] in out
154
155 #
156 # dmcrypt data
157 #
158 ptype2type = {
159 main.PTYPE['plain']['osd']['ready']: 'plain',
160 main.PTYPE['luks']['osd']['ready']: 'luks',
161 }
162 for (ptype, type) in ptype2type.items():
163 for holders in ((), ("dm_0",), ("dm_0", "dm_1")):
164 dev = {
165 'dmcrypt': {
166 'holders': holders,
167 'type': type,
168 },
169 'path': '/dev/Xda1',
170 'ptype': ptype,
171 'state': 'prepared',
172 'whoami': '1234',
173 }
174 out = main.list_format_dev_plain(dev)
175 assert 'data' in out
176 assert 'dmcrypt' in out
177 assert type in out
178 if len(holders) == 1:
179 assert dev['whoami'] in out
180 for holder in holders:
181 assert holder in out
182
183 #
184 # dmcrypt journal
185 #
186 ptype2type = {
187 main.PTYPE['plain']['journal']['ready']: 'plain',
188 main.PTYPE['luks']['journal']['ready']: 'luks',
189 }
190 for (ptype, type) in ptype2type.items():
191 for holders in ((), ("dm_0",)):
192 dev = {
193 'path': '/dev/Xda2',
194 'ptype': ptype,
195 'journal_for': '/dev/Xda1',
196 'dmcrypt': {
197 'holders': holders,
198 'type': type,
199 },
200 }
201 out = main.list_format_dev_plain(dev)
202 assert 'journal' in out
203 assert 'dmcrypt' in out
204 assert type in out
205 assert dev['journal_for'] in out
206 if len(holders) == 1:
207 assert holders[0] in out
208
209 def test_list_dev_osd(self):
210 dev = "Xda"
211 mount_path = '/mount/path'
212 fs_type = 'ext4'
213 cluster = 'ceph'
214 uuid_map = {}
215
216 def more_osd_info(path, uuid_map, desc):
217 desc['cluster'] = cluster
218 #
219 # mounted therefore active
220 #
221 with patch.multiple(
222 main,
223 is_mounted=lambda dev: mount_path,
224 get_dev_fs=lambda dev: fs_type,
225 more_osd_info=more_osd_info
226 ):
227 desc = {}
228 main.list_dev_osd(dev, uuid_map, desc)
229 assert {'cluster': 'ceph',
230 'fs_type': 'ext4',
231 'mount': '/mount/path',
232 'state': 'active'} == desc
233 #
234 # not mounted and cannot mount: unprepared
235 #
236 mount_path = None
237 with patch.multiple(
238 main,
239 is_mounted=lambda dev: mount_path,
240 get_dev_fs=lambda dev: fs_type,
241 mount=fail_to_mount,
242 more_osd_info=more_osd_info
243 ):
244 desc = {}
245 main.list_dev_osd(dev, uuid_map, desc)
246 assert {'fs_type': 'ext4',
247 'mount': mount_path,
248 'state': 'unprepared'} == desc
249 #
250 # not mounted and magic found: prepared
251 #
252
253 def get_oneliner(path, what):
254 if what == 'magic':
255 return main.CEPH_OSD_ONDISK_MAGIC
256 else:
257 raise Exception('unknown ' + what)
258 with patch.multiple(
259 main,
260 is_mounted=lambda dev: mount_path,
261 get_dev_fs=lambda dev: fs_type,
262 mount=DEFAULT,
263 unmount=DEFAULT,
264 get_oneliner=get_oneliner,
265 more_osd_info=more_osd_info
266 ):
267 desc = {}
268 main.list_dev_osd(dev, uuid_map, desc)
269 assert {'cluster': 'ceph',
270 'fs_type': 'ext4',
271 'mount': mount_path,
272 'magic': main.CEPH_OSD_ONDISK_MAGIC,
273 'state': 'prepared'} == desc
274
275 def test_list_all_partitions(self):
276 if platform.system() == "FreeBSD":
277 return
278
279 disk = "Xda"
280 partition = "Xda1"
281
282 with patch(
283 'ceph_disk.main.os',
284 listdir=lambda path: [disk],
285 ), patch.multiple(
286 main,
287 list_partitions=lambda dev: [partition],
288 ):
289 assert {disk: [partition]} == main.list_all_partitions()
290
291 def test_list_data(self):
292 #
293 # a data partition that fails to mount is silently
294 # ignored
295 #
296 if platform.system() == "FreeBSD":
297 return
298
299 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
300 disk = "Xda"
301 partition = "Xda1"
302 fs_type = "ext4"
303
304 def get_partition_type(dev):
305 return main.PTYPE['regular']['osd']['ready']
306 with patch.multiple(
307 main,
308 list_all_partitions=lambda: {disk: [partition]},
309 get_partition_uuid=lambda dev: partition_uuid,
310 get_partition_type=get_partition_type,
311 get_dev_fs=lambda dev: fs_type,
312 mount=fail_to_mount,
313 unmount=DEFAULT,
314 is_partition=lambda dev: True,
315 ):
316 expect = [{'path': '/dev/' + disk,
317 'partitions': [{
318 'dmcrypt': {},
319 'fs_type': fs_type,
320 'is_partition': True,
321 'mount': None,
322 'path': '/dev/' + partition,
323 'ptype': main.PTYPE['regular']['osd']['ready'],
324 'state': 'unprepared',
325 'type': 'data',
326 'uuid': partition_uuid,
327 }]}]
328 assert expect == main.list_devices()
329
330 def test_list_dmcrypt_data(self):
331 if platform.system() == "FreeBSD":
332 return
333
334 partition_type2type = {
335 main.PTYPE['plain']['osd']['ready']: 'plain',
336 main.PTYPE['luks']['osd']['ready']: 'LUKS',
337 }
338 for (partition_type, type) in partition_type2type.items():
339 #
340 # dmcrypt data partition with one holder
341 #
342 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
343 disk = "Xda"
344 partition = "Xda1"
345 holders = ["dm-dummy"]
346 with patch.multiple(
347 main,
348 is_held=lambda dev: holders,
349 list_all_partitions=lambda: {disk: [partition]},
350 get_partition_uuid=lambda dev: partition_uuid,
351 get_partition_type=lambda dev: partition_type,
352 is_partition=lambda dev: True,
353 ):
354 expect = [{'path': '/dev/' + disk,
355 'partitions': [{
356 'dmcrypt': {
357 'holders': holders,
358 'type': type,
359 },
360 'fs_type': None,
361 'is_partition': True,
362 'mount': None,
363 'path': '/dev/' + partition,
364 'ptype': partition_type,
365 'state': 'unprepared',
366 'type': 'data',
367 'uuid': partition_uuid,
368 }]}]
369 assert expect == main.list_devices()
370 #
371 # dmcrypt data partition with two holders
372 #
373 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
374 disk = "Xda"
375 partition = "Xda1"
376 holders = ["dm-dummy", "dm-dummy1"]
377 with patch.multiple(
378 main,
379 is_held=lambda dev: holders,
380 list_all_partitions=lambda: {disk: [partition]},
381 get_partition_uuid=lambda dev: partition_uuid,
382 get_partition_type=lambda dev: partition_type,
383 is_partition=lambda dev: True,
384 ):
385 expect = [{'path': '/dev/' + disk,
386 'partitions': [{
387 'dmcrypt': {
388 'holders': holders,
389 'type': type,
390 },
391 'is_partition': True,
392 'path': '/dev/' + partition,
393 'ptype': partition_type,
394 'type': 'data',
395 'uuid': partition_uuid,
396 }]}]
397 assert expect == main.list_devices()
398
399 def test_list_multipath(self):
400 #
401 # multipath data partition
402 #
403 if platform.system() == "FreeBSD":
404 return
405
406 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
407 disk = "Xda"
408 partition = "Xda1"
409
410 def get_partition_type(dev):
411 return main.PTYPE['mpath']['osd']['ready']
412 with patch.multiple(
413 main,
414 list_all_partitions=lambda: {disk: [partition]},
415 get_partition_uuid=lambda dev: partition_uuid,
416 get_partition_type=get_partition_type,
417 is_partition=lambda dev: True,
418 ):
419 expect = [{'path': '/dev/' + disk,
420 'partitions': [{
421 'dmcrypt': {},
422 'fs_type': None,
423 'is_partition': True,
424 'mount': None,
425 'multipath': True,
426 'path': '/dev/' + partition,
427 'ptype': main.PTYPE['mpath']['osd']['ready'],
428 'state': 'unprepared',
429 'type': 'data',
430 'uuid': partition_uuid,
431 }]}]
432 assert expect == main.list_devices()
433 #
434 # multipath journal partition
435 #
436 journal_partition_uuid = "2cc40457-259e-4542-b029-785c7cc37871"
437
438 def get_partition_type(dev):
439 return main.PTYPE['mpath']['journal']['ready']
440 with patch.multiple(
441 main,
442 list_all_partitions=lambda: {disk: [partition]},
443 get_partition_uuid=lambda dev: journal_partition_uuid,
444 get_partition_type=get_partition_type,
445 is_partition=lambda dev: True,
446 ):
447 expect = [{'path': '/dev/' + disk,
448 'partitions': [{
449 'dmcrypt': {},
450 'is_partition': True,
451 'multipath': True,
452 'path': '/dev/' + partition,
453 'ptype': main.PTYPE['mpath']['journal']['ready'],
454 'type': 'journal',
455 'uuid': journal_partition_uuid,
456 }]}]
457 assert expect == main.list_devices()
458
459 def test_list_default(self):
460 self.list(main.PTYPE['plain']['osd']['ready'],
461 main.PTYPE['plain']['journal']['ready'])
462 self.list(main.PTYPE['luks']['osd']['ready'],
463 main.PTYPE['luks']['journal']['ready'])
464 self.list(main.PTYPE['regular']['osd']['ready'],
465 main.PTYPE['regular']['journal']['ready'])
466
467 def test_list_bluestore(self):
468 if platform.system() == "FreeBSD":
469 return
470
471 self.list(main.PTYPE['plain']['osd']['ready'],
472 main.PTYPE['plain']['block']['ready'])
473 self.list(main.PTYPE['luks']['osd']['ready'],
474 main.PTYPE['luks']['block']['ready'])
475 self.list(main.PTYPE['regular']['osd']['ready'],
476 main.PTYPE['regular']['block']['ready'])
477
478 def list(self, data_ptype, space_ptype):
479 #
480 # a single disk has a data partition and a journal
481 # partition and the osd is active
482 #
483 name = main.Ptype.space_ptype_to_name(space_ptype)
484 data_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
485 disk = "Xda"
486 data = "Xda1"
487 data_holder = "dm-dummy"
488 space = "Xda2"
489 space_holder = "dm-dummy"
490 mount_path = '/mount/path'
491 fs_type = 'ext4'
492 space_uuid = "7ad5e65a-0ca5-40e4-a896-62a74ca61c55"
493 ceph_fsid = "60a2ef70-d99b-4b9b-a83c-8a86e5e60091"
494 osd_id = '1234'
495
496 def get_oneliner(path, what):
497 if '_uuid' in what:
498 if what == name + '_uuid':
499 return space_uuid
500 else:
501 return None
502 elif what == 'ceph_fsid':
503 return ceph_fsid
504 elif what == 'whoami':
505 return osd_id
506 else:
507 raise Exception('unknown ' + what)
508
509 def get_partition_uuid(dev):
510 if dev == '/dev/' + data:
511 return data_uuid
512 elif dev == '/dev/' + space:
513 return space_uuid
514 else:
515 raise Exception('unknown ' + dev)
516
517 def get_partition_type(dev):
518 if (dev == '/dev/' + data or
519 dev == '/dev/' + data_holder):
520 return data_ptype
521 elif (dev == '/dev/' + space or
522 dev == '/dev/' + space_holder):
523 return space_ptype
524 else:
525 raise Exception('unknown ' + dev)
526 cluster = 'ceph'
527 if data_ptype == main.PTYPE['regular']['osd']['ready']:
528 data_dmcrypt = {}
529 elif data_ptype == main.PTYPE['plain']['osd']['ready']:
530 data_dmcrypt = {
531 'type': 'plain',
532 'holders': [data_holder],
533 }
534 elif data_ptype == main.PTYPE['luks']['osd']['ready']:
535 data_dmcrypt = {
536 'type': 'LUKS',
537 'holders': [data_holder],
538 }
539 else:
540 raise Exception('unknown ' + data_ptype)
541
542 if space_ptype == main.PTYPE['regular'][name]['ready']:
543 space_dmcrypt = {}
544 elif space_ptype == main.PTYPE['plain'][name]['ready']:
545 space_dmcrypt = {
546 'type': 'plain',
547 'holders': [space_holder],
548 }
549 elif space_ptype == main.PTYPE['luks'][name]['ready']:
550 space_dmcrypt = {
551 'type': 'LUKS',
552 'holders': [space_holder],
553 }
554 else:
555 raise Exception('unknown ' + space_ptype)
556
557 if data_dmcrypt:
558 def is_held(dev):
559 if dev == '/dev/' + data:
560 return [data_holder]
561 elif dev == '/dev/' + space:
562 return [space_holder]
563 else:
564 raise Exception('unknown ' + dev)
565 else:
566 def is_held(dev):
567 return []
568
569 with patch.multiple(
570 main,
571 list_all_partitions=lambda: {disk: [data, space]},
572 get_dev_fs=lambda dev: fs_type,
573 is_mounted=lambda dev: mount_path,
574 get_partition_uuid=get_partition_uuid,
575 get_partition_type=get_partition_type,
576 find_cluster_by_uuid=lambda ceph_fsid: cluster,
577 is_partition=lambda dev: True,
578 mount=DEFAULT,
579 unmount=DEFAULT,
580 get_oneliner=get_oneliner,
581 is_held=is_held,
582 ):
583 expect = [{'path': '/dev/' + disk,
584 'partitions': [{
585 'ceph_fsid': ceph_fsid,
586 'cluster': cluster,
587 'dmcrypt': data_dmcrypt,
588 'fs_type': fs_type,
589 'is_partition': True,
590 name + '_dev': '/dev/' + space,
591 name + '_uuid': space_uuid,
592 'mount': mount_path,
593 'path': '/dev/' + data,
594 'ptype': data_ptype,
595 'state': 'active',
596 'type': 'data',
597 'whoami': osd_id,
598 'uuid': data_uuid,
599 }, {
600 'dmcrypt': space_dmcrypt,
601 'is_partition': True,
602 name + '_for': '/dev/' + data,
603 'path': '/dev/' + space,
604 'ptype': space_ptype,
605 'type': name,
606 'uuid': space_uuid,
607 }]}]
608 assert expect == main.list_devices()
609
610 def test_list_other(self):
611 #
612 # not swap, unknown fs type, not mounted, with uuid
613 #
614 if platform.system() == "FreeBSD":
615 return
616
617 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
618 partition_type = "e51adfb9-e9fd-4718-9fc1-7a0cb03ea3f4"
619 disk = "Xda"
620 partition = "Xda1"
621 with patch.multiple(
622 main,
623 list_all_partitions=lambda: {disk: [partition]},
624 get_partition_uuid=lambda dev: partition_uuid,
625 get_partition_type=lambda dev: partition_type,
626 is_partition=lambda dev: True,
627 ):
628 expect = [{'path': '/dev/' + disk,
629 'partitions': [{'dmcrypt': {},
630 'is_partition': True,
631 'path': '/dev/' + partition,
632 'ptype': partition_type,
633 'type': 'other',
634 'uuid': partition_uuid}]}]
635 assert expect == main.list_devices()
636 #
637 # not swap, mounted, ext4 fs type, with uuid
638 #
639 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
640 partition_type = "e51adfb9-e9fd-4718-9fc1-7a0cb03ea3f4"
641 disk = "Xda"
642 partition = "Xda1"
643 mount_path = '/mount/path'
644 fs_type = 'ext4'
645 with patch.multiple(
646 main,
647 list_all_partitions=lambda: {disk: [partition]},
648 get_dev_fs=lambda dev: fs_type,
649 is_mounted=lambda dev: mount_path,
650 get_partition_uuid=lambda dev: partition_uuid,
651 get_partition_type=lambda dev: partition_type,
652 is_partition=lambda dev: True,
653 ):
654 expect = [{'path': '/dev/' + disk,
655 'partitions': [{
656 'dmcrypt': {},
657 'is_partition': True,
658 'mount': mount_path,
659 'fs_type': fs_type,
660 'path': '/dev/' + partition,
661 'ptype': partition_type,
662 'type': 'other',
663 'uuid': partition_uuid,
664 }]}]
665 assert expect == main.list_devices()
666
667 #
668 # swap, with uuid
669 #
670 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
671 partition_type = "e51adfb9-e9fd-4718-9fc1-7a0cb03ea3f4"
672 disk = "Xda"
673 partition = "Xda1"
674 with patch.multiple(
675 main,
676 list_all_partitions=lambda: {disk: [partition]},
677 is_swap=lambda dev: True,
678 get_partition_uuid=lambda dev: partition_uuid,
679 get_partition_type=lambda dev: partition_type,
680 is_partition=lambda dev: True,
681 ):
682 expect = [{'path': '/dev/' + disk,
683 'partitions': [{'dmcrypt': {},
684 'is_partition': True,
685 'path': '/dev/' + partition,
686 'ptype': partition_type,
687 'type': 'swap',
688 'uuid': partition_uuid}]}]
689 assert expect == main.list_devices()
690
691 #
692 # whole disk
693 #
694 partition_uuid = "56244cf5-83ef-4984-888a-2d8b8e0e04b2"
695 disk = "Xda"
696 partition = "Xda1"
697 with patch.multiple(
698 main,
699 list_all_partitions=lambda: {disk: []},
700 is_partition=lambda dev: False,
701 ):
702 expect = [{'path': '/dev/' + disk,
703 'dmcrypt': {},
704 'is_partition': False,
705 'ptype': 'unknown',
706 'type': 'other'}]
707 assert expect == main.list_devices()
708
709
710 class TestCephDiskDeactivateAndDestroy(unittest.TestCase):
711
712 def setup_class(self):
713 main.setup_logging(verbose=True, log_stdout=False)
714
715 @patch('{0}.open'.format(builtins.__name__))
716 def test_main_deactivate(self, mock_open):
717 data = tempfile.mkdtemp()
718 main.setup_statedir(data)
719 DMCRYPT_LUKS_OSD_UUID = '4fbd7e29-9d25-41b8-afd0-35865ceff05d'
720 part_uuid = '0ce28a16-6d5d-11e5-aec3-fa163e5c167b'
721 disk = 'sdX'
722 #
723 # Can not find match device by osd-id
724 #
725 args = main.parse_args(['deactivate',
726 '--cluster', 'ceph',
727 '--deactivate-by-id', '5566'])
728 fake_device = [{'path': '/dev/' + disk,
729 'partitions': [{
730 'path': '/dev/sdX1',
731 'whoami': '-1',
732 }]}]
733 with patch.multiple(
734 main,
735 list_devices=lambda: fake_device,
736 ):
737 self.assertRaises(Exception, main.main_deactivate, args)
738
739 #
740 # find match device by osd-id, status: OSD_STATUS_IN_DOWN
741 # with --mark-out option
742 #
743 args = main.parse_args(['deactivate',
744 '--cluster', 'ceph',
745 '--deactivate-by-id', '5566',
746 '--mark-out'])
747 fake_device = [{'path': '/dev/' + disk,
748 'partitions': [{
749 'ptype': DMCRYPT_LUKS_OSD_UUID,
750 'path': '/dev/sdX1',
751 'whoami': '5566',
752 'mount': '/var/lib/ceph/osd/ceph-5566/',
753 'uuid': part_uuid,
754 }]}]
755 with patch.multiple(
756 main,
757 list_devices=lambda: fake_device,
758 _check_osd_status=lambda cluster, osd_id: 2,
759 _mark_osd_out=lambda cluster, osd_id: True
760 ):
761 main.main_deactivate(args)
762
763 #
764 # find match device by device partition, status: OSD_STATUS_IN_DOWN
765 #
766 args = main.parse_args(['deactivate',
767 '--cluster', 'ceph',
768 '/dev/sdX1'])
769 fake_device = [{'path': '/dev/' + disk,
770 'partitions': [{
771 'ptype': DMCRYPT_LUKS_OSD_UUID,
772 'path': '/dev/sdX1',
773 'whoami': '5566',
774 'mount': '/var/lib/ceph/osd/ceph-5566/',
775 'uuid': part_uuid,
776 }]}]
777 with patch.multiple(
778 main,
779 list_devices=lambda: fake_device,
780 _check_osd_status=lambda cluster, osd_id: 0,
781 ):
782 main.main_deactivate(args)
783
784 #
785 # find match device by device partition, status: OSD_STATUS_IN_UP
786 # with --mark-out option
787 #
788 args = main.parse_args(['deactivate',
789 '--cluster', 'ceph',
790 '/dev/sdX1',
791 '--mark-out'])
792 fake_device = [{'path': '/dev/' + disk,
793 'partitions': [{
794 'ptype': DMCRYPT_LUKS_OSD_UUID,
795 'path': '/dev/sdX1',
796 'whoami': '5566',
797 'mount': '/var/lib/ceph/osd/ceph-5566/',
798 'uuid': part_uuid,
799 }]}]
800
801 # mock the file open.
802 file_opened = io.StringIO()
803 file_opened.write(u'deactive')
804 mock_open.return_value = file_opened
805
806 with patch.multiple(
807 main,
808 mock_open,
809 list_devices=lambda: fake_device,
810 _check_osd_status=lambda cluster, osd_id: 3,
811 _mark_osd_out=lambda cluster, osd_id: True,
812 stop_daemon=lambda cluster, osd_id: True,
813 _remove_osd_directory_files=lambda path, cluster: True,
814 path_set_context=lambda path: True,
815 unmount=lambda path: True,
816 dmcrypt_unmap=lambda part_uuid: True,
817 ):
818 main.main_deactivate(args)
819
820 #
821 # find match device by osd-id, status: OSD_STATUS_OUT_UP
822 #
823 args = main.parse_args(['deactivate',
824 '--cluster', 'ceph',
825 '--deactivate-by-id', '5566'])
826 fake_device = [{'path': '/dev/' + disk,
827 'partitions': [{
828 'ptype': DMCRYPT_LUKS_OSD_UUID,
829 'path': '/dev/sdX1',
830 'whoami': '5566',
831 'mount': '/var/lib/ceph/osd/ceph-5566/',
832 'uuid': part_uuid,
833 }]}]
834
835 # mock the file open.
836 file_opened = io.StringIO()
837 file_opened.write(u'deactive')
838 mock_open.return_value = file_opened
839
840 with patch.multiple(
841 main,
842 mock_open,
843 list_devices=lambda: fake_device,
844 _check_osd_status=lambda cluster, osd_id: 1,
845 _mark_osd_out=lambda cluster, osd_id: True,
846 stop_daemon=lambda cluster, osd_id: True,
847 _remove_osd_directory_files=lambda path, cluster: True,
848 path_set_context=lambda path: True,
849 unmount=lambda path: True,
850 dmcrypt_unmap=lambda part_uuid: True,
851 ):
852 main.main_deactivate(args)
853 shutil.rmtree(data)
854
855 def test_mark_out_out(self):
856 def mark_osd_out_fail(osd_id):
857 raise main.Error('Could not find osd.%s, is a vaild/exist osd id?'
858 % osd_id)
859
860 with patch.multiple(
861 main,
862 command=mark_osd_out_fail,
863 ):
864 self.assertRaises(Exception, main._mark_osd_out, 'ceph', '5566')
865
866 def test_check_osd_status(self):
867 #
868 # command failure
869 #
870 with patch.multiple(
871 main,
872 command=raise_command_error,
873 ):
874 self.assertRaises(Exception, main._check_osd_status,
875 'ceph', '5566')
876
877 #
878 # osd not found
879 #
880
881 fake_data = ('{"osds":[{"osd":0,"up":1,"in":1},'
882 '{"osd":1,"up":1,"in":1}]}')
883
884 def return_fake_value(cmd):
885 return fake_data, '', 0
886
887 with patch.multiple(
888 main,
889 command=return_fake_value,
890 ):
891 self.assertRaises(Exception, main._check_osd_status,
892 'ceph', '5566')
893
894 #
895 # successfully
896 #
897
898 fake_data = ('{"osds":[{"osd":0,"up":1,"in":1},'
899 '{"osd":5566,"up":1,"in":1}]}')
900
901 def return_fake_value(cmd):
902 return fake_data, '', 0
903
904 with patch.multiple(
905 main,
906 command=return_fake_value,
907 ):
908 main._check_osd_status('ceph', '5566')
909
910 def test_stop_daemon(self):
911 STATEDIR = '/var/lib/ceph'
912 cluster = 'ceph'
913 osd_id = '5566'
914
915 def stop_daemon_fail(cmd):
916 raise Exception('ceph osd stop failed')
917
918 #
919 # fail on init type
920 #
921 with patch('os.path.exists', return_value=False):
922 self.assertRaises(Exception, main.stop_daemon, 'ceph', '5566')
923
924 #
925 # upstart failure
926 #
927 fake_path = (STATEDIR + '/osd/{cluster}-{osd_id}/upstart').format(
928 cluster=cluster, osd_id=osd_id)
929
930 def path_exist(check_path):
931 if check_path == fake_path:
932 return True
933 else:
934 False
935
936 patcher = patch('os.path.exists')
937 check_path = patcher.start()
938 check_path.side_effect = path_exist
939 with patch.multiple(
940 main,
941 check_path,
942 command_check_call=stop_daemon_fail,
943 ):
944 self.assertRaises(Exception, main.stop_daemon, 'ceph', '5566')
945
946 #
947 # sysvinit failure
948 #
949 fake_path = (STATEDIR + '/osd/{cluster}-{osd_id}/sysvinit').format(
950 cluster=cluster, osd_id=osd_id)
951
952 def path_exist(check_path):
953 if check_path == fake_path:
954 return True
955 else:
956 return False
957
958 patcher = patch('os.path.exists')
959 check_path = patcher.start()
960 check_path.side_effect = path_exist
961 with patch.multiple(
962 main,
963 check_path,
964 which=lambda name: True,
965 command_check_call=stop_daemon_fail,
966 ):
967 self.assertRaises(Exception, main.stop_daemon, 'ceph', '5566')
968
969 #
970 # systemd failure
971 #
972 fake_path = (STATEDIR + '/osd/{cluster}-{osd_id}/systemd').format(
973 cluster=cluster, osd_id=osd_id)
974
975 def path_exist(check_path):
976 if check_path == fake_path:
977 return True
978 else:
979 False
980
981 def stop_daemon_fail(cmd):
982 if 'stop' in cmd:
983 raise Exception('ceph osd stop failed')
984 else:
985 return True
986
987 patcher = patch('os.path.exists')
988 check_path = patcher.start()
989 check_path.side_effect = path_exist
990 with patch.multiple(
991 main,
992 check_path,
993 command_check_call=stop_daemon_fail,
994 ):
995 self.assertRaises(Exception, main.stop_daemon, 'ceph', '5566')
996
997 def test_remove_osd_directory_files(self):
998 cluster = 'ceph'
999 mounted_path = 'somewhere'
1000 fake_path_2 = None
1001 fake_path_remove_2 = None
1002 fake_path_remove_init = None
1003
1004 def handle_path_exist(check_path):
1005 if check_path == fake_path:
1006 return True
1007 elif fake_path_2 and check_path == fake_path_2:
1008 return True
1009 else:
1010 return False
1011
1012 def handle_path_remove(remove_path):
1013 if remove_path == fake_path_remove:
1014 return True
1015 elif fake_path_remove_2 and remove_path == fake_path_remove_2:
1016 return True
1017 elif (fake_path_remove_init and
1018 remove_path == fake_path_remove_init):
1019 return True
1020 else:
1021 raise OSError
1022
1023 #
1024 # remove ready file failure
1025 #
1026 fake_path = os.path.join(mounted_path, 'ready')
1027 fake_path_remove = os.path.join(mounted_path, 'no_ready')
1028
1029 patcher_exist = patch('os.path.exists')
1030 patcher_remove = patch('os.remove')
1031 path_exist = patcher_exist.start()
1032 path_remove = patcher_remove.start()
1033 path_exist.side_effect = handle_path_exist
1034 path_remove.side_effect = handle_path_remove
1035 with patch.multiple(
1036 main,
1037 path_exist,
1038 path_remove,
1039 get_conf=lambda cluster, **kwargs: True,
1040 ):
1041 self.assertRaises(Exception, main._remove_osd_directory_files,
1042 'somewhere', cluster)
1043
1044 #
1045 # remove active fil failure
1046 #
1047 fake_path = os.path.join(mounted_path, 'ready')
1048 fake_path_2 = os.path.join(mounted_path, 'active')
1049 fake_path_remove = os.path.join(mounted_path, 'ready')
1050 fake_path_remove_2 = os.path.join(mounted_path, 'no_active')
1051
1052 patcher_exist = patch('os.path.exists')
1053 patcher_remove = patch('os.remove')
1054 path_exist = patcher_exist.start()
1055 path_remove = patcher_remove.start()
1056 path_exist.side_effect = handle_path_exist
1057 path_remove.side_effect = handle_path_remove
1058 with patch.multiple(
1059 main,
1060 path_exist,
1061 path_remove,
1062 get_conf=lambda cluster, **kwargs: True,
1063 ):
1064 self.assertRaises(Exception, main._remove_osd_directory_files,
1065 'somewhere', cluster)
1066
1067 #
1068 # conf_val is None and remove init file failure
1069 #
1070 fake_path = os.path.join(mounted_path, 'ready')
1071 fake_path_2 = os.path.join(mounted_path, 'active')
1072 fake_path_remove = os.path.join(mounted_path, 'ready')
1073 fake_path_remove_2 = os.path.join(mounted_path, 'active')
1074 fake_path_remove_init = os.path.join(mounted_path, 'init_failure')
1075
1076 patcher_exist = patch('os.path.exists')
1077 patcher_remove = patch('os.remove')
1078 path_exist = patcher_exist.start()
1079 path_remove = patcher_remove.start()
1080 path_exist.side_effect = handle_path_exist
1081 path_remove.side_effect = handle_path_remove
1082 with patch.multiple(
1083 main,
1084 path_exist,
1085 path_remove,
1086 get_conf=lambda cluster, **kwargs: None,
1087 init_get=lambda: 'upstart',
1088 ):
1089 self.assertRaises(Exception, main._remove_osd_directory_files,
1090 'somewhere', cluster)
1091
1092 #
1093 # already remove `ready`, `active` and remove init file successfully
1094 #
1095 fake_path = os.path.join(mounted_path, 'no_ready')
1096 fake_path_2 = os.path.join(mounted_path, 'no_active')
1097 fake_path_remove = os.path.join(mounted_path, 'upstart')
1098
1099 patcher_exist = patch('os.path.exists')
1100 patcher_remove = patch('os.remove')
1101 path_exist = patcher_exist.start()
1102 path_remove = patcher_remove.start()
1103 path_exist.side_effect = handle_path_exist
1104 path_remove.side_effect = handle_path_remove
1105 with patch.multiple(
1106 main,
1107 path_exist,
1108 path_remove,
1109 get_conf=lambda cluster, **kwargs: 'upstart',
1110 ):
1111 main._remove_osd_directory_files('somewhere', cluster)
1112
1113 def test_path_set_context(self):
1114 path = '/somewhere'
1115 with patch.multiple(
1116 main,
1117 get_ceph_user=lambda **kwargs: 'ceph',
1118 ):
1119 main.path_set_context(path)
1120
1121 def test_mount(self):
1122 #
1123 # None to mount
1124 #
1125 dev = None
1126 fs_type = 'ext4'
1127 option = ''
1128 self.assertRaises(Exception, main.mount, dev, fs_type, option)
1129
1130 #
1131 # fstype undefine
1132 #
1133 dev = '/dev/Xda1'
1134 fs_type = None
1135 option = ''
1136 self.assertRaises(Exception, main.mount, dev, fs_type, option)
1137
1138 #
1139 # mount failure
1140 #
1141 dev = '/dev/Xda1'
1142 fstype = 'ext4'
1143 options = ''
1144 with patch('tempfile.mkdtemp', return_value='/mnt'):
1145 self.assertRaises(Exception, main.mount, dev, fstype, options)
1146
1147 #
1148 # mount successfully
1149 #
1150 def create_temp_directory(*args, **kwargs):
1151 return '/mnt'
1152
1153 dev = '/dev/Xda1'
1154 fstype = 'ext4'
1155 options = ''
1156 patcher = patch('tempfile.mkdtemp')
1157 create_tmpdir = patcher.start()
1158 create_tmpdir.side_effect = create_temp_directory
1159 with patch.multiple(
1160 main,
1161 create_tmpdir,
1162 command_check_call=lambda cmd: True,
1163 ):
1164 main.mount(dev, fstype, options)
1165
1166 def test_umount(self):
1167 #
1168 # umount failure
1169 #
1170 path = '/somewhere'
1171 self.assertRaises(Exception, main.unmount, path)
1172
1173 #
1174 # umount successfully
1175 #
1176 def remove_directory_successfully(path):
1177 return True
1178
1179 path = '/somewhere'
1180 patcher = patch('os.rmdir')
1181 rm_directory = patcher.start()
1182 rm_directory.side_effect = remove_directory_successfully
1183 with patch.multiple(
1184 main,
1185 rm_directory,
1186 command_check_call=lambda cmd: True,
1187 ):
1188 main.unmount(path)
1189
1190 def test_main_destroy(self):
1191 data = tempfile.mkdtemp()
1192 main.setup_statedir(data)
1193 OSD_UUID = '4fbd7e29-9d25-41b8-afd0-062c0ceff05d'
1194 MPATH_OSD_UUID = '4fbd7e29-8ae0-4982-bf9d-5a8d867af560'
1195 part_uuid = '0ce28a16-6d5d-11e5-aec3-fa163e5c167b'
1196 journal_uuid = "7ad5e65a-0ca5-40e4-a896-62a74ca61c55"
1197 mount_5566 = '/var/lib/ceph/osd/ceph-5566/'
1198
1199 fake_devices_normal = [{'path': '/dev/sdY',
1200 'partitions': [{
1201 'dmcrypt': {},
1202 'type': 'osd',
1203 'ptype': OSD_UUID,
1204 'path': '/dev/sdY1',
1205 'whoami': '5566',
1206 'mount': mount_5566,
1207 'uuid': part_uuid,
1208 'journal_uuid': journal_uuid}]},
1209 {'path': '/dev/sdX',
1210 'partitions': [{
1211 'dmcrypt': {},
1212 'type': 'osd',
1213 'ptype': MPATH_OSD_UUID,
1214 'path': '/dev/sdX1',
1215 'whoami': '7788',
1216 'mount': '/var/lib/ceph/osd/ceph-7788/',
1217 'uuid': part_uuid,
1218 'journal_uuid': journal_uuid}]}]
1219
1220 def list_devices_return():
1221 return fake_devices_normal
1222
1223 #
1224 # input device is not the device partition
1225 #
1226 args = main.parse_args(['destroy', '--cluster', 'ceph', '/dev/sdX'])
1227 with patch.multiple(
1228 main,
1229 is_partition=lambda path: False,
1230 ):
1231 self.assertRaises(Exception, main.main_destroy, args)
1232
1233 #
1234 # skip the redundent devices and not found by dev
1235 #
1236 args = main.parse_args(['destroy', '--cluster', 'ceph', '/dev/sdZ1'])
1237 with patch.multiple(
1238 main,
1239 is_partition=lambda path: True,
1240 list_devices=list_devices_return,
1241 ):
1242 self.assertRaises(Exception, main.main_destroy, args)
1243
1244 #
1245 # skip the redundent devices and not found by osd-id
1246 #
1247 args = main.parse_args(['destroy', '--cluster', 'ceph',
1248 '--destroy-by-id', '1234'])
1249 with patch.multiple(
1250 main,
1251 is_partition=lambda path: True,
1252 list_devices=list_devices_return,
1253 ):
1254 self.assertRaises(Exception, main.main_destroy, args)
1255
1256 #
1257 # skip the redundent devices and found by dev
1258 #
1259 args = main.parse_args(['destroy', '--cluster',
1260 'ceph', '/dev/sdY1', '--zap'])
1261 with patch.multiple(
1262 main,
1263 is_partition=lambda path: True,
1264 list_devices=list_devices_return,
1265 get_partition_base=lambda dev_path: '/dev/sdY',
1266 _check_osd_status=lambda cluster, osd_id: 0,
1267 zap=lambda dev: True
1268 ):
1269 main.main_destroy(args)
1270
1271 #
1272 # skip the redundent devices and found by osd-id
1273 # with active status and MPATH_OSD
1274 #
1275 args = main.parse_args(['destroy', '--cluster', 'ceph',
1276 '--destroy-by-id', '7788'])
1277 with patch.multiple(
1278 main,
1279 is_partition=lambda path: True,
1280 list_devices=list_devices_return,
1281 get_partition_base_mpath=lambda dev_path: '/dev/sdX',
1282 _check_osd_status=lambda cluster, osd_id: 1,
1283 ):
1284 self.assertRaises(Exception, main.main_destroy, args)
1285 shutil.rmtree(data)
1286
1287 def test_main_fix(self):
1288 if platform.system() == "FreeBSD":
1289 return
1290
1291 args = main.parse_args(['fix', '--all', '--selinux', '--permissions'])
1292 commands = []
1293
1294 def _command(x):
1295 commands.append(" ".join(x))
1296 return ("", "", None)
1297
1298 class Os(object):
1299 F_OK = 0
1300
1301 @staticmethod
1302 def access(x, y):
1303 return True
1304
1305 with patch.multiple(
1306 main,
1307 command=_command,
1308 command_init=lambda x: commands.append(x),
1309 command_wait=lambda x: None,
1310 os=Os,
1311 ):
1312 main.main_fix(args)
1313 commands = " ".join(commands)
1314 assert '/var/lib/ceph' in commands
1315 assert 'restorecon' in commands
1316 assert 'chown' in commands
1317 assert 'find' in commands
1318
1319
1320 def raise_command_error(*args):
1321 e = subprocess.CalledProcessError('aaa', 'bbb', 'ccc')
1322 raise e