]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
DriveSelection: skip unavailable devices
authorGuillaume Abrioux <gabrioux@redhat.com>
Tue, 22 Mar 2022 15:35:58 +0000 (16:35 +0100)
committerGuillaume Abrioux <gabrioux@redhat.com>
Wed, 30 Mar 2022 21:49:01 +0000 (23:49 +0200)
Cephadm shouldn't try to deploy a disk reported as unavailable by ceph-volume.
The idea here is to check the rejection reason so we can still use DB devices
in case of OSD replacement.

Signed-off-by: Guillaume Abrioux <gabrioux@redhat.com>
src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py
src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py
src/ceph-volume/ceph_volume/tests/devices/test_zap.py
src/ceph-volume/ceph_volume/tests/test_inventory.py
src/ceph-volume/ceph_volume/tests/util/test_device.py
src/ceph-volume/ceph_volume/util/device.py
src/python-common/ceph/deployment/drive_selection/selector.py
src/python-common/ceph/deployment/inventory.py

index 8e888d02b3b51e85675813992c4b5025736eff42..1665d76c3884a139ffbae06b3f5ebbab8889c4d6 100644 (file)
@@ -19,7 +19,7 @@ class TestCreate(object):
         assert 'A physical device or logical' in stdout
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_filestore_bluestore_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_filestore_bluestore_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.create.Create(argv=['--data', '/dev/sdfoo', '--filestore', '--bluestore']).main()
@@ -28,7 +28,7 @@ class TestCreate(object):
         assert expected in stderr
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_other_filestore_bluestore_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_other_filestore_bluestore_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.create.Create(argv=[
@@ -40,7 +40,7 @@ class TestCreate(object):
         assert expected in stderr
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_block_and_journal_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_block_and_journal_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.create.Create(argv=[
index c5afe674da03f9acc0819fe9f3fb340252f5825c..7e4d963c8b450f1a813a03bcd80544b747e1230d 100644 (file)
@@ -62,7 +62,7 @@ class TestPrettyReport(object):
 
 class TestList(object):
 
-    def test_empty_full_json_zero_exit_status(self, is_root,factory,capsys):
+    def test_empty_full_json_zero_exit_status(self, fake_call, is_root, factory, capsys):
         args = factory(format='json', device=None)
         lvm.listing.List([]).list(args)
         stdout, stderr = capsys.readouterr()
@@ -74,7 +74,7 @@ class TestList(object):
         stdout, stderr = capsys.readouterr()
         assert stdout == '{}\n'
 
-    def test_empty_full_zero_exit_status(self, is_root, factory):
+    def test_empty_full_zero_exit_status(self, fake_call, is_root, factory):
         args = factory(format='pretty', device=None)
         with pytest.raises(SystemExit):
             lvm.listing.List([]).list(args)
index e6e42463465b26c74b94ef869c2a6ec2e3bf1ebf..9f0a5e0bbc2239816cc9f5d43182dd3843468d8a 100644 (file)
@@ -1,7 +1,7 @@
 import pytest
 from ceph_volume.devices import lvm
 from ceph_volume.api import lvm as api
-from mock.mock import patch, Mock
+from mock.mock import patch, Mock, MagicMock
 
 
 class TestLVM(object):
@@ -68,7 +68,7 @@ class TestPrepare(object):
 
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_filestore_bluestore_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_filestore_bluestore_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.prepare.Prepare(argv=['--data', '/dev/sdfoo', '--filestore', '--bluestore']).main()
@@ -78,7 +78,7 @@ class TestPrepare(object):
 
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_other_filestore_bluestore_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_other_filestore_bluestore_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.prepare.Prepare(argv=[
@@ -90,7 +90,7 @@ class TestPrepare(object):
         assert expected in stderr
 
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_excludes_block_and_journal_flags(self, m_has_bs_label, capsys, device_info):
+    def test_excludes_block_and_journal_flags(self, m_has_bs_label, fake_call, capsys, device_info):
         device_info()
         with pytest.raises(SystemExit):
             lvm.prepare.Prepare(argv=[
@@ -101,10 +101,15 @@ class TestPrepare(object):
         expected = 'Cannot use --block.db (bluestore) with --journal (filestore)'
         assert expected in stderr
 
+    @patch('ceph_volume.util.arg_validators.Device')
     @patch('ceph_volume.util.disk.has_bluestore_label', return_value=False)
-    def test_journal_is_required_with_filestore(self, m_has_bs_label, is_root, monkeypatch, device_info):
+    def test_journal_is_required_with_filestore(self, m_has_bs_label, m_device, is_root, monkeypatch, device_info):
+        m_device.return_value = MagicMock(exists=True,
+                                          has_fs=False,
+                                          used_by_ceph=False,
+                                          has_partitions=False,
+                                          has_gpt_headers=False)
         monkeypatch.setattr("os.path.exists", lambda path: True)
-        device_info()
         with pytest.raises(SystemExit) as error:
             lvm.prepare.Prepare(argv=['--filestore', '--data', '/dev/sdfoo']).main()
         expected = '--journal is required when using --filestore'
index eff187228fc2b7b08072c44410f48f1045a85120..53c69463317a6078927164c64ad43c10687d9cf7 100644 (file)
@@ -105,7 +105,7 @@ class TestEnsureAssociatedLVs(object):
         result = zap.ensure_associated_lvs(volumes)
         assert result == []
 
-    def test_data_is_found(self):
+    def test_data_is_found(self, fake_call):
         tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=data'
         osd = api.Volume(
             lv_name='volume1', lv_uuid='y', vg_name='', lv_path='/dev/VolGroup/data', lv_tags=tags)
@@ -114,7 +114,7 @@ class TestEnsureAssociatedLVs(object):
         result = zap.ensure_associated_lvs(volumes)
         assert result == ['/dev/VolGroup/data']
 
-    def test_block_is_found(self):
+    def test_block_is_found(self, fake_call):
         tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=block'
         osd = api.Volume(
             lv_name='volume1', lv_uuid='y', vg_name='', lv_path='/dev/VolGroup/block', lv_tags=tags)
@@ -150,7 +150,7 @@ class TestEnsureAssociatedLVs(object):
         assert '/dev/sdb1' in result
         assert '/dev/VolGroup/block' in result
 
-    def test_journal_is_found(self):
+    def test_journal_is_found(self, fake_call):
         tags = 'ceph.osd_id=0,ceph.osd_fsid=asdf-lkjh,ceph.journal_uuid=x,ceph.type=journal'
         osd = api.Volume(
             lv_name='volume1', lv_uuid='y', vg_name='', lv_path='/dev/VolGroup/lv', lv_tags=tags)
index 42c4940f157bd496f2d65bf9822bcc3981f0c956..745b58ae55a2e49ddb7b0a08f3d4b1a955c79166 100644 (file)
@@ -1,5 +1,6 @@
 import pytest
 from ceph_volume.devices import lvm
+from mock.mock import patch, MagicMock
 
 
 class TestZap(object):
@@ -19,9 +20,18 @@ class TestZap(object):
         '/dev/mapper/foo',
         '/dev/dm-0',
     ])
-    def test_can_not_zap_mapper_device(self, monkeypatch, device_info, capsys, is_root, device_name):
+    @patch('ceph_volume.util.arg_validators.Device')
+    def test_can_not_zap_mapper_device(self, mocked_device, monkeypatch, device_info, capsys, is_root, device_name):
         monkeypatch.setattr('os.path.exists', lambda x: True)
-        device_info()
+        mocked_device.return_value = MagicMock(
+            is_mapper=True,
+            is_mpath=False,
+            used_by_ceph=True,
+            exists=True,
+            has_partitions=False,
+            has_gpt_headers=False,
+            has_fs=False
+        )
         with pytest.raises(SystemExit):
             lvm.zap.Zap(argv=[device_name]).main()
         stdout, stderr = capsys.readouterr()
index 28654cec33e567311c90b8e4a1f3042adcae59f2..b00bd668d01aa666b35dead238ad2c40f9ee6502 100644 (file)
@@ -111,6 +111,7 @@ def device_data(device_info):
 class TestInventory(object):
 
     expected_keys = [
+        'ceph_device',
         'path',
         'rejected_reasons',
         'sys_api',
@@ -152,30 +153,30 @@ class TestInventory(object):
         'errors',
     ]
 
-    def test_json_inventory_keys_unexpected(self, device_report_keys):
+    def test_json_inventory_keys_unexpected(self, fake_call, device_report_keys):
         for k in device_report_keys:
             assert k in self.expected_keys, "unexpected key {} in report".format(k)
 
-    def test_json_inventory_keys_missing(self, device_report_keys):
+    def test_json_inventory_keys_missing(self, fake_call, device_report_keys):
         for k in self.expected_keys:
             assert k in device_report_keys, "expected key {} in report".format(k)
 
-    def test_sys_api_keys_unexpected(self, device_sys_api_keys):
+    def test_sys_api_keys_unexpected(self, fake_call, device_sys_api_keys):
         for k in device_sys_api_keys:
             assert k in self.expected_sys_api_keys, "unexpected key {} in sys_api field".format(k)
 
-    def test_sys_api_keys_missing(self, device_sys_api_keys):
+    def test_sys_api_keys_missing(self, fake_call, device_sys_api_keys):
         for k in self.expected_sys_api_keys:
             assert k in device_sys_api_keys, "expected key {} in sys_api field".format(k)
 
-    def test_lsm_data_type_unexpected(self, device_data):
+    def test_lsm_data_type_unexpected(self, fake_call, device_data):
         assert isinstance(device_data['lsm_data'], dict), "lsm_data field must be of type dict"
 
-    def test_lsm_data_keys_unexpected(self, device_data):
+    def test_lsm_data_keys_unexpected(self, fake_call, device_data):
         for k in device_data['lsm_data'].keys():
             assert k in self.expected_lsm_keys, "unexpected key {} in lsm_data field".format(k)
 
-    def test_lsm_data_keys_missing(self, device_data):
+    def test_lsm_data_keys_missing(self, fake_call, device_data):
         lsm_keys = device_data['lsm_data'].keys()
         assert lsm_keys
         for k in self.expected_lsm_keys:
@@ -251,4 +252,4 @@ class TestLSM(object):
     def test_lsmdisk_led_fault(self, lsm_info):
         assert lsm_info.led_fault_state == 'Off'
     def test_lsmdisk_report(self, lsm_info):
-        assert isinstance(lsm_info.json_report(), dict)
\ No newline at end of file
+        assert isinstance(lsm_info.json_report(), dict)
index 578f2fa5e70e3d2384dade633970b9180a1ebc38..f6e439279d78c4e80e6b6aafdf0882dcf8bfd5fa 100644 (file)
@@ -37,7 +37,7 @@ class TestDevice(object):
         disk = device.Device("/dev/sda")
         assert disk.lvm_size.gb == 4
 
-    def test_lvm_size_rounds_down(self, device_info):
+    def test_lvm_size_rounds_down(self, fake_call, device_info):
         # 5.5GB in size
         data = {"/dev/sda": {"size": "5905580032"}}
         lsblk = {"TYPE": "disk"}
@@ -45,14 +45,14 @@ class TestDevice(object):
         disk = device.Device("/dev/sda")
         assert disk.lvm_size.gb == 4
 
-    def test_is_lv(self, device_info):
+    def test_is_lv(self, fake_call, device_info):
         data = {"lv_path": "vg/lv", "vg_name": "vg", "name": "lv"}
         lsblk = {"TYPE": "lvm"}
         device_info(lv=data,lsblk=lsblk)
         disk = device.Device("vg/lv")
         assert disk.is_lv
 
-    def test_vgs_is_empty(self, device_info, monkeypatch):
+    def test_vgs_is_empty(self, fake_call, device_info, monkeypatch):
         BarPVolume = api.PVolume(pv_name='/dev/sda', pv_uuid="0000",
                                  pv_tags={})
         pvolumes = []
@@ -64,7 +64,7 @@ class TestDevice(object):
         disk = device.Device("/dev/nvme0n1")
         assert disk.vgs == []
 
-    def test_vgs_is_not_empty(self, device_info, monkeypatch):
+    def test_vgs_is_not_empty(self, fake_call, device_info, monkeypatch):
         vg = api.VolumeGroup(vg_name='foo/bar', vg_free_count=6,
                              vg_extent_size=1073741824)
         monkeypatch.setattr(api, 'get_device_vgs', lambda x: [vg])
@@ -73,42 +73,42 @@ class TestDevice(object):
         disk = device.Device("/dev/nvme0n1")
         assert len(disk.vgs) == 1
 
-    def test_device_is_device(self, device_info):
+    def test_device_is_device(self, fake_call, device_info):
         data = {"/dev/sda": {"foo": "bar"}}
         lsblk = {"TYPE": "device"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.is_device is True
 
-    def test_device_is_rotational(self, device_info):
+    def test_device_is_rotational(self, fake_call, device_info):
         data = {"/dev/sda": {"rotational": "1"}}
         lsblk = {"TYPE": "device"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.rotational
 
-    def test_device_is_not_rotational(self, device_info):
+    def test_device_is_not_rotational(self, fake_call, device_info):
         data = {"/dev/sda": {"rotational": "0"}}
         lsblk = {"TYPE": "device"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert not disk.rotational
 
-    def test_device_is_rotational_lsblk(self, device_info):
+    def test_device_is_rotational_lsblk(self, fake_call, device_info):
         data = {"/dev/sda": {"foo": "bar"}}
         lsblk = {"TYPE": "device", "ROTA": "1"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.rotational
 
-    def test_device_is_not_rotational_lsblk(self, device_info):
+    def test_device_is_not_rotational_lsblk(self, fake_call, device_info):
         data = {"/dev/sda": {"rotational": "0"}}
         lsblk = {"TYPE": "device", "ROTA": "0"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert not disk.rotational
 
-    def test_device_is_rotational_defaults_true(self, device_info):
+    def test_device_is_rotational_defaults_true(self, fake_call, device_info):
         # rotational will default true if no info from sys_api or lsblk is found
         data = {"/dev/sda": {"foo": "bar"}}
         lsblk = {"TYPE": "device", "foo": "bar"}
@@ -116,54 +116,54 @@ class TestDevice(object):
         disk = device.Device("/dev/sda")
         assert disk.rotational
 
-    def test_disk_is_device(self, device_info):
+    def test_disk_is_device(self, fake_call, device_info):
         data = {"/dev/sda": {"foo": "bar"}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.is_device is True
 
-    def test_is_partition(self, device_info):
+    def test_is_partition(self, fake_call, device_info):
         data = {"/dev/sda1": {"foo": "bar"}}
         lsblk = {"TYPE": "part", "PKNAME": "sda"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda1")
         assert disk.is_partition
 
-    def test_mpath_device_is_device(self, device_info):
+    def test_mpath_device_is_device(self, fake_call, device_info):
         data = {"/dev/foo": {"foo": "bar"}}
         lsblk = {"TYPE": "mpath"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/foo")
         assert disk.is_device is True
 
-    def test_is_not_lvm_member(self, device_info):
+    def test_is_not_lvm_member(self, fake_call, device_info):
         data = {"/dev/sda1": {"foo": "bar"}}
         lsblk = {"TYPE": "part", "PKNAME": "sda"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda1")
         assert not disk.is_lvm_member
 
-    def test_is_lvm_member(self, device_info):
+    def test_is_lvm_member(self, fake_call, device_info):
         data = {"/dev/sda1": {"foo": "bar"}}
         lsblk = {"TYPE": "part", "PKNAME": "sda"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/sda1")
         assert not disk.is_lvm_member
 
-    def test_is_mapper_device(self, device_info):
+    def test_is_mapper_device(self, fake_call, device_info):
         lsblk = {"TYPE": "lvm"}
         device_info(lsblk=lsblk)
         disk = device.Device("/dev/mapper/foo")
         assert disk.is_mapper
 
-    def test_dm_is_mapper_device(self, device_info):
+    def test_dm_is_mapper_device(self, fake_call, device_info):
         lsblk = {"TYPE": "lvm"}
         device_info(lsblk=lsblk)
         disk = device.Device("/dev/dm-4")
         assert disk.is_mapper
 
-    def test_is_not_mapper_device(self, device_info):
+    def test_is_not_mapper_device(self, fake_call, device_info):
         lsblk = {"TYPE": "disk"}
         device_info(lsblk=lsblk)
         disk = device.Device("/dev/sda")
@@ -171,19 +171,19 @@ class TestDevice(object):
 
     @pytest.mark.usefixtures("lsblk_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_ceph_disk_lsblk(self, monkeypatch, patch_bluestore_label):
+    def test_is_ceph_disk_lsblk(self, fake_call, monkeypatch, patch_bluestore_label):
         disk = device.Device("/dev/sda")
         assert disk.is_ceph_disk_member
 
     @pytest.mark.usefixtures("blkid_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_ceph_disk_blkid(self, monkeypatch, patch_bluestore_label):
+    def test_is_ceph_disk_blkid(self, fake_call, monkeypatch, patch_bluestore_label):
         disk = device.Device("/dev/sda")
         assert disk.is_ceph_disk_member
 
     @pytest.mark.usefixtures("lsblk_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_ceph_disk_member_not_available_lsblk(self, monkeypatch, patch_bluestore_label):
+    def test_is_ceph_disk_member_not_available_lsblk(self, fake_call, monkeypatch, patch_bluestore_label):
         disk = device.Device("/dev/sda")
         assert disk.is_ceph_disk_member
         assert not disk.available
@@ -191,20 +191,20 @@ class TestDevice(object):
 
     @pytest.mark.usefixtures("blkid_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_ceph_disk_member_not_available_blkid(self, monkeypatch, patch_bluestore_label):
+    def test_is_ceph_disk_member_not_available_blkid(self, fake_call, monkeypatch, patch_bluestore_label):
         disk = device.Device("/dev/sda")
         assert disk.is_ceph_disk_member
         assert not disk.available
         assert "Used by ceph-disk" in disk.rejected_reasons
 
-    def test_reject_removable_device(self, device_info):
+    def test_reject_removable_device(self, fake_call, device_info):
         data = {"/dev/sdb": {"removable": 1}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data,lsblk=lsblk)
         disk = device.Device("/dev/sdb")
         assert not disk.available
 
-    def test_reject_device_with_gpt_headers(self, device_info):
+    def test_reject_device_with_gpt_headers(self, fake_call, device_info):
         data = {"/dev/sdb": {"removable": 0, "size": 5368709120}}
         lsblk = {"TYPE": "disk"}
         blkid= {"PTTYPE": "gpt"}
@@ -216,42 +216,42 @@ class TestDevice(object):
         disk = device.Device("/dev/sdb")
         assert not disk.available
 
-    def test_accept_non_removable_device(self, device_info):
+    def test_accept_non_removable_device(self, fake_call, device_info):
         data = {"/dev/sdb": {"removable": 0, "size": 5368709120}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data,lsblk=lsblk)
         disk = device.Device("/dev/sdb")
         assert disk.available
 
-    def test_reject_not_acceptable_device(self, device_info):
+    def test_reject_not_acceptable_device(self, fake_call, device_info):
         data = {"/dev/dm-0": {"foo": "bar"}}
         lsblk = {"TYPE": "mpath"}
         device_info(devices=data, lsblk=lsblk)
         disk = device.Device("/dev/dm-0")
         assert not disk.available
 
-    def test_reject_readonly_device(self, device_info):
+    def test_reject_readonly_device(self, fake_call, device_info):
         data = {"/dev/cdrom": {"ro": 1}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data,lsblk=lsblk)
         disk = device.Device("/dev/cdrom")
         assert not disk.available
 
-    def test_reject_smaller_than_5gb(self, device_info):
+    def test_reject_smaller_than_5gb(self, fake_call, device_info):
         data = {"/dev/sda": {"size": 5368709119}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data,lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert not disk.available, 'too small device is available'
 
-    def test_accept_non_readonly_device(self, device_info):
+    def test_accept_non_readonly_device(self, fake_call, device_info):
         data = {"/dev/sda": {"ro": 0, "size": 5368709120}}
         lsblk = {"TYPE": "disk"}
         device_info(devices=data,lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.available
 
-    def test_reject_bluestore_device(self, monkeypatch, patch_bluestore_label, device_info):
+    def test_reject_bluestore_device(self, fake_call, monkeypatch, patch_bluestore_label, device_info):
         patch_bluestore_label.return_value = True
         lsblk = {"TYPE": "disk"}
         device_info(lsblk=lsblk)
@@ -259,7 +259,7 @@ class TestDevice(object):
         assert not disk.available
         assert "Has BlueStore device label" in disk.rejected_reasons
 
-    def test_reject_device_with_oserror(self, monkeypatch, patch_bluestore_label, device_info):
+    def test_reject_device_with_oserror(self, fake_call, monkeypatch, patch_bluestore_label, device_info):
         patch_bluestore_label.side_effect = OSError('test failure')
         lsblk = {"TYPE": "disk"}
         device_info(lsblk=lsblk)
@@ -269,11 +269,11 @@ class TestDevice(object):
 
     @pytest.mark.usefixtures("device_info_not_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_not_ceph_disk_member_lsblk(self, patch_bluestore_label):
+    def test_is_not_ceph_disk_member_lsblk(self, fake_call, patch_bluestore_label):
         disk = device.Device("/dev/sda")
         assert disk.is_ceph_disk_member is False
 
-    def test_existing_vg_available(self, monkeypatch, device_info):
+    def test_existing_vg_available(self, fake_call, monkeypatch, device_info):
         vg = api.VolumeGroup(vg_name='foo/bar', vg_free_count=1536,
                              vg_extent_size=4194304)
         monkeypatch.setattr(api, 'get_device_vgs', lambda x: [vg])
@@ -285,7 +285,7 @@ class TestDevice(object):
         assert not disk.available
         assert not disk.available_raw
 
-    def test_existing_vg_too_small(self, monkeypatch, device_info):
+    def test_existing_vg_too_small(self, fake_call, monkeypatch, device_info):
         vg = api.VolumeGroup(vg_name='foo/bar', vg_free_count=4,
                              vg_extent_size=1073741824)
         monkeypatch.setattr(api, 'get_device_vgs', lambda x: [vg])
@@ -297,7 +297,7 @@ class TestDevice(object):
         assert not disk.available
         assert not disk.available_raw
 
-    def test_multiple_existing_vgs(self, monkeypatch, device_info):
+    def test_multiple_existing_vgs(self, fake_call, monkeypatch, device_info):
         vg1 = api.VolumeGroup(vg_name='foo/bar', vg_free_count=1000,
                              vg_extent_size=4194304)
         vg2 = api.VolumeGroup(vg_name='foo/bar', vg_free_count=536,
@@ -312,7 +312,7 @@ class TestDevice(object):
         assert not disk.available_raw
 
     @pytest.mark.parametrize("ceph_type", ["data", "block"])
-    def test_used_by_ceph(self, device_info,
+    def test_used_by_ceph(self, fake_call, device_info,
                           monkeypatch, ceph_type):
         data = {"/dev/sda": {"foo": "bar"}}
         lsblk = {"TYPE": "part", "PKNAME": "sda"}
@@ -337,7 +337,7 @@ class TestDevice(object):
         disk = device.Device("/dev/sda")
         assert disk.used_by_ceph
 
-    def test_not_used_by_ceph(self, device_info, monkeypatch):
+    def test_not_used_by_ceph(self, fake_call, device_info, monkeypatch):
         FooPVolume = api.PVolume(pv_name='/dev/sda', pv_uuid="0000", lv_uuid="0000", pv_tags={}, vg_name="vg")
         pvolumes = []
         pvolumes.append(FooPVolume)
@@ -350,7 +350,7 @@ class TestDevice(object):
         disk = device.Device("/dev/sda")
         assert not disk.used_by_ceph
 
-    def test_get_device_id(self, device_info):
+    def test_get_device_id(self, fake_call, device_info):
         udev = {k:k for k in ['ID_VENDOR', 'ID_MODEL', 'ID_SCSI_SERIAL']}
         lsblk = {"TYPE": "disk"}
         device_info(udevadm=udev,lsblk=lsblk)
@@ -371,33 +371,33 @@ class TestDevice(object):
 
 class TestDeviceEncryption(object):
 
-    def test_partition_is_not_encrypted_lsblk(self, device_info):
+    def test_partition_is_not_encrypted_lsblk(self, fake_call, device_info):
         lsblk = {'TYPE': 'part', 'FSTYPE': 'xfs', 'PKNAME': 'sda'}
         device_info(lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.is_encrypted is False
 
-    def test_partition_is_encrypted_lsblk(self, device_info):
+    def test_partition_is_encrypted_lsblk(self, fake_call, device_info):
         lsblk = {'TYPE': 'part', 'FSTYPE': 'crypto_LUKS', 'PKNAME': 'sda'}
         device_info(lsblk=lsblk)
         disk = device.Device("/dev/sda")
         assert disk.is_encrypted is True
 
-    def test_partition_is_not_encrypted_blkid(self, device_info):
+    def test_partition_is_not_encrypted_blkid(self, fake_call, device_info):
         lsblk = {'TYPE': 'part', 'PKNAME': 'sda'}
         blkid = {'TYPE': 'ceph data'}
         device_info(lsblk=lsblk, blkid=blkid)
         disk = device.Device("/dev/sda")
         assert disk.is_encrypted is False
 
-    def test_partition_is_encrypted_blkid(self, device_info):
+    def test_partition_is_encrypted_blkid(self, fake_call, device_info):
         lsblk = {'TYPE': 'part', 'PKNAME': 'sda'}
         blkid = {'TYPE': 'crypto_LUKS'}
         device_info(lsblk=lsblk, blkid=blkid)
         disk = device.Device("/dev/sda")
         assert disk.is_encrypted is True
 
-    def test_mapper_is_encrypted_luks1(self, device_info, monkeypatch):
+    def test_mapper_is_encrypted_luks1(self, fake_call, device_info, monkeypatch):
         status = {'type': 'LUKS1'}
         monkeypatch.setattr(device, 'encryption_status', lambda x: status)
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
@@ -406,7 +406,7 @@ class TestDeviceEncryption(object):
         disk = device.Device("/dev/mapper/uuid")
         assert disk.is_encrypted is True
 
-    def test_mapper_is_encrypted_luks2(self, device_info, monkeypatch):
+    def test_mapper_is_encrypted_luks2(self, fake_call, device_info, monkeypatch):
         status = {'type': 'LUKS2'}
         monkeypatch.setattr(device, 'encryption_status', lambda x: status)
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
@@ -415,7 +415,7 @@ class TestDeviceEncryption(object):
         disk = device.Device("/dev/mapper/uuid")
         assert disk.is_encrypted is True
 
-    def test_mapper_is_encrypted_plain(self, device_info, monkeypatch):
+    def test_mapper_is_encrypted_plain(self, fake_call, device_info, monkeypatch):
         status = {'type': 'PLAIN'}
         monkeypatch.setattr(device, 'encryption_status', lambda x: status)
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
@@ -424,7 +424,7 @@ class TestDeviceEncryption(object):
         disk = device.Device("/dev/mapper/uuid")
         assert disk.is_encrypted is True
 
-    def test_mapper_is_not_encrypted_plain(self, device_info, monkeypatch):
+    def test_mapper_is_not_encrypted_plain(self, fake_call, device_info, monkeypatch):
         monkeypatch.setattr(device, 'encryption_status', lambda x: {})
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
         blkid = {'TYPE': 'mapper'}
@@ -432,7 +432,7 @@ class TestDeviceEncryption(object):
         disk = device.Device("/dev/mapper/uuid")
         assert disk.is_encrypted is False
 
-    def test_lv_is_encrypted_blkid(self, device_info):
+    def test_lv_is_encrypted_blkid(self, fake_call, device_info):
         lsblk = {'TYPE': 'lvm'}
         blkid = {'TYPE': 'crypto_LUKS'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -440,7 +440,7 @@ class TestDeviceEncryption(object):
         disk.lv_api = {}
         assert disk.is_encrypted is True
 
-    def test_lv_is_not_encrypted_blkid(self, factory, device_info):
+    def test_lv_is_not_encrypted_blkid(self, fake_call, factory, device_info):
         lsblk = {'TYPE': 'lvm'}
         blkid = {'TYPE': 'xfs'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -448,7 +448,7 @@ class TestDeviceEncryption(object):
         disk.lv_api = factory(encrypted=None)
         assert disk.is_encrypted is False
 
-    def test_lv_is_encrypted_lsblk(self, device_info):
+    def test_lv_is_encrypted_lsblk(self, fake_call, device_info):
         lsblk = {'FSTYPE': 'crypto_LUKS', 'TYPE': 'lvm'}
         blkid = {'TYPE': 'mapper'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -456,7 +456,7 @@ class TestDeviceEncryption(object):
         disk.lv_api = {}
         assert disk.is_encrypted is True
 
-    def test_lv_is_not_encrypted_lsblk(self, factory, device_info):
+    def test_lv_is_not_encrypted_lsblk(self, fake_call, factory, device_info):
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
         blkid = {'TYPE': 'mapper'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -464,7 +464,7 @@ class TestDeviceEncryption(object):
         disk.lv_api = factory(encrypted=None)
         assert disk.is_encrypted is False
 
-    def test_lv_is_encrypted_lvm_api(self, factory, device_info):
+    def test_lv_is_encrypted_lvm_api(self, fake_call, factory, device_info):
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
         blkid = {'TYPE': 'mapper'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -472,7 +472,7 @@ class TestDeviceEncryption(object):
         disk.lv_api = factory(encrypted=True)
         assert disk.is_encrypted is True
 
-    def test_lv_is_not_encrypted_lvm_api(self, factory, device_info):
+    def test_lv_is_not_encrypted_lvm_api(self, fake_call, factory, device_info):
         lsblk = {'FSTYPE': 'xfs', 'TYPE': 'lvm'}
         blkid = {'TYPE': 'mapper'}
         device_info(lsblk=lsblk, blkid=blkid)
@@ -491,7 +491,7 @@ class TestDeviceOrdering(object):
                 "/dev/sdd": {"removable": 1}, # invalid
         }
 
-    def test_valid_before_invalid(self, device_info):
+    def test_valid_before_invalid(self, fake_call, device_info):
         lsblk = {"TYPE": "disk"}
         device_info(devices=self.data,lsblk=lsblk)
         sda = device.Device("/dev/sda")
@@ -500,7 +500,7 @@ class TestDeviceOrdering(object):
         assert sda < sdb
         assert sdb > sda
 
-    def test_valid_alphabetical_ordering(self, device_info):
+    def test_valid_alphabetical_ordering(self, fake_call, device_info):
         lsblk = {"TYPE": "disk"}
         device_info(devices=self.data,lsblk=lsblk)
         sda = device.Device("/dev/sda")
@@ -509,7 +509,7 @@ class TestDeviceOrdering(object):
         assert sda < sdc
         assert sdc > sda
 
-    def test_invalid_alphabetical_ordering(self, device_info):
+    def test_invalid_alphabetical_ordering(self, fake_call, device_info):
         lsblk = {"TYPE": "disk"}
         device_info(devices=self.data,lsblk=lsblk)
         sdb = device.Device("/dev/sdb")
@@ -521,14 +521,14 @@ class TestDeviceOrdering(object):
 
 class TestCephDiskDevice(object):
 
-    def test_partlabel_lsblk(self, device_info):
+    def test_partlabel_lsblk(self, fake_call, device_info):
         lsblk = {"TYPE": "disk", "PARTLABEL": ""}
         device_info(lsblk=lsblk)
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
 
         assert disk.partlabel == ''
 
-    def test_partlabel_blkid(self, device_info):
+    def test_partlabel_blkid(self, fake_call, device_info):
         blkid = {"TYPE": "disk", "PARTLABEL": "ceph data"}
         device_info(blkid=blkid)
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
@@ -537,21 +537,21 @@ class TestCephDiskDevice(object):
 
     @pytest.mark.usefixtures("blkid_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_member_blkid(self, monkeypatch, patch_bluestore_label):
+    def test_is_member_blkid(self, fake_call, monkeypatch, patch_bluestore_label):
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
 
         assert disk.is_member is True
 
     @pytest.mark.usefixtures("lsblk_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_is_member_lsblk(self, patch_bluestore_label, device_info):
+    def test_is_member_lsblk(self, fake_call, patch_bluestore_label, device_info):
         lsblk = {"TYPE": "disk", "PARTLABEL": "ceph"}
         device_info(lsblk=lsblk)
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
 
         assert disk.is_member is True
 
-    def test_unknown_type(self, device_info):
+    def test_unknown_type(self, fake_call, device_info):
         lsblk = {"TYPE": "disk", "PARTLABEL": "gluster"}
         device_info(lsblk=lsblk)
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
@@ -562,7 +562,7 @@ class TestCephDiskDevice(object):
 
     @pytest.mark.usefixtures("blkid_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_type_blkid(self, monkeypatch, device_info, ceph_partlabel):
+    def test_type_blkid(self, monkeypatch, fake_call, device_info, ceph_partlabel):
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
 
         assert disk.type in self.ceph_types
@@ -570,7 +570,7 @@ class TestCephDiskDevice(object):
     @pytest.mark.usefixtures("blkid_ceph_disk_member",
                              "lsblk_ceph_disk_member",
                              "disable_kernel_queries")
-    def test_type_lsblk(self, device_info, ceph_partlabel):
+    def test_type_lsblk(self, fake_call, device_info, ceph_partlabel):
         disk = device.CephDiskDevice(device.Device("/dev/sda"))
 
         assert disk.type in self.ceph_types
index feddb59d99c50e70e95ae9f04f55fce36bec6c47..edd6e804fb19ea10c63f07eb0046ba754c47fca7 100644 (file)
@@ -3,7 +3,7 @@
 import logging
 import os
 from functools import total_ordering
-from ceph_volume import sys_info
+from ceph_volume import sys_info, process
 from ceph_volume.api import lvm
 from ceph_volume.util import disk, system
 from ceph_volume.util.lsmdisk import LSMDisk
@@ -66,6 +66,7 @@ class Device(object):
      {attr:<25} {value}"""
 
     report_fields = [
+        'ceph_device',
         'rejected_reasons',
         'available',
         'path',
@@ -104,6 +105,7 @@ class Device(object):
         self._is_lvm_member = None
         self._parse()
         self.lsm_data = self.fetch_lsm(with_lsm)
+        self.ceph_device = None
 
         self.available_lvm, self.rejected_reasons_lvm = self._check_lvm_reject_reasons()
         self.available_raw, self.rejected_reasons_raw = self._check_raw_reject_reasons()
@@ -173,6 +175,7 @@ class Device(object):
             self.abspath = lv.lv_path
             self.vg_name = lv.vg_name
             self.lv_name = lv.name
+            self.ceph_device = lvm.is_ceph_device(lv)
         else:
             dev = disk.lsblk(self.path)
             self.blkid_api = disk.blkid(self.path)
@@ -181,6 +184,11 @@ class Device(object):
             # always check is this is an lvm member
             if device_type in ['part', 'disk']:
                 self._set_lvm_membership()
+            out, err, rc = process.call([
+                'ceph-bluestore-tool', 'show-label',
+                '--dev', self.path], verbose_on_failure=False)
+            if rc:
+                self.ceph_device = True
 
         self.ceph_disk = CephDiskDevice(self)
 
index 8aed3d19794f5bd12167377c000b7a190d43d7ba..07b0549f3a201f726b44eb7e4998e6c510efd248 100644 (file)
@@ -121,6 +121,13 @@ class DriveSelection(object):
         for disk in self.disks:
             logger.debug("Processing disk {}".format(disk.path))
 
+            if not disk.available and not disk.ceph_device:
+                logger.debug(
+                    ("Ignoring disk {}. "
+                     "Disk is unavailable due to {}".format(disk.path, disk.rejected_reasons))
+                )
+                continue
+
             if not self._has_mandatory_idents(disk):
                 logger.debug(
                     "Ignoring disk {}. Missing mandatory idents".format(
index 880881b2a0580db80a47de9fe10da20fa0bb915a..570c1dbb3615e0cd41ac24e7a08ac12ee35bea1f 100644 (file)
@@ -43,6 +43,7 @@ class Devices(object):
 
 class Device(object):
     report_fields = [
+        'ceph_device',
         'rejected_reasons',
         'available',
         'path',
@@ -62,7 +63,8 @@ class Device(object):
                  lvs=None,  # type: Optional[List[str]]
                  device_id=None,  # type: Optional[str]
                  lsm_data=None,  # type: Optional[Dict[str, Dict[str, str]]]
-                 created=None  # type: Optional[datetime.datetime]
+                 created=None,  # type: Optional[datetime.datetime]
+                 ceph_device=None  # type: Optional[bool]
                  ):
         self.path = path
         self.sys_api = sys_api if sys_api is not None else {}  # type: Dict[str, Any]
@@ -72,6 +74,7 @@ class Device(object):
         self.device_id = device_id
         self.lsm_data = lsm_data if lsm_data is not None else {}  # type: Dict[str, Dict[str, str]]
         self.created = created if created is not None else datetime_now()
+        self.ceph_device = ceph_device
 
     def __eq__(self, other):
         # type: (Any) -> bool
@@ -120,6 +123,7 @@ class Device(object):
             'path': self.path if self.path is not None else 'unknown',
             'lvs': self.lvs if self.lvs else 'None',
             'available': str(self.available),
+            'ceph_device': str(self.ceph_device)
         }
         if not self.available and self.rejected_reasons:
             device_desc['rejection reasons'] = self.rejected_reasons