From: Guillaume Abrioux Date: Tue, 22 Mar 2022 15:35:58 +0000 (+0100) Subject: DriveSelection: skip unavailable devices X-Git-Tag: v18.0.0~1129^2~3 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=3a88547559769f4dd438f6557cef22ef9004fa2a;p=ceph.git DriveSelection: skip unavailable devices 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 --- diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py index 8e888d02b3b51..1665d76c3884a 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_create.py @@ -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=[ diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py index c5afe674da03f..7e4d963c8b450 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_listing.py @@ -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) diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py index e6e42463465b2..9f0a5e0bbc223 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_prepare.py @@ -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' diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py index eff187228fc2b..53c69463317a6 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_zap.py @@ -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) diff --git a/src/ceph-volume/ceph_volume/tests/devices/test_zap.py b/src/ceph-volume/ceph_volume/tests/devices/test_zap.py index 42c4940f157bd..745b58ae55a2e 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/test_zap.py +++ b/src/ceph-volume/ceph_volume/tests/devices/test_zap.py @@ -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() diff --git a/src/ceph-volume/ceph_volume/tests/test_inventory.py b/src/ceph-volume/ceph_volume/tests/test_inventory.py index 28654cec33e56..b00bd668d01aa 100644 --- a/src/ceph-volume/ceph_volume/tests/test_inventory.py +++ b/src/ceph-volume/ceph_volume/tests/test_inventory.py @@ -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) diff --git a/src/ceph-volume/ceph_volume/tests/util/test_device.py b/src/ceph-volume/ceph_volume/tests/util/test_device.py index 578f2fa5e70e3..f6e439279d78c 100644 --- a/src/ceph-volume/ceph_volume/tests/util/test_device.py +++ b/src/ceph-volume/ceph_volume/tests/util/test_device.py @@ -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 diff --git a/src/ceph-volume/ceph_volume/util/device.py b/src/ceph-volume/ceph_volume/util/device.py index feddb59d99c50..edd6e804fb19e 100644 --- a/src/ceph-volume/ceph_volume/util/device.py +++ b/src/ceph-volume/ceph_volume/util/device.py @@ -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) diff --git a/src/python-common/ceph/deployment/drive_selection/selector.py b/src/python-common/ceph/deployment/drive_selection/selector.py index 8aed3d19794f5..07b0549f3a201 100644 --- a/src/python-common/ceph/deployment/drive_selection/selector.py +++ b/src/python-common/ceph/deployment/drive_selection/selector.py @@ -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( diff --git a/src/python-common/ceph/deployment/inventory.py b/src/python-common/ceph/deployment/inventory.py index 880881b2a0580..570c1dbb3615e 100644 --- a/src/python-common/ceph/deployment/inventory.py +++ b/src/python-common/ceph/deployment/inventory.py @@ -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