diff options
author | Jan Fajerski <jfajerski@suse.com> | 2019-12-03 13:44:00 +0100 |
---|---|---|
committer | Jan Fajerski <jfajerski@suse.com> | 2020-01-27 14:35:40 +0100 |
commit | 2e985053deec6c4cf60c0b85aec3df16cd77ceeb (patch) | |
tree | f32855c156ec2daadde99507e726e36f0331dda0 /src/ceph-volume | |
parent | Merge PR #32853 into master (diff) | |
download | ceph-2e985053deec6c4cf60c0b85aec3df16cd77ceeb.tar.xz ceph-2e985053deec6c4cf60c0b85aec3df16cd77ceeb.zip |
ceph-volume/batch: fail on filtered devices when non-interactive
When batch is called non-interactively and a user explicitly specifies,
say a db-device, this will be filtered when unavailable. This can cause
the resulting OSD to be very different from the users intention
(standalone vs external db when the db-device was filtered). If devices
get filtered in non-interactive mode, ceph-volume should fail.
Fixes: https://tracker.ceph.com/issues/43105
Signed-off-by: Jan Fajerski <jfajerski@suse.com>
Diffstat (limited to 'src/ceph-volume')
-rw-r--r-- | src/ceph-volume/ceph_volume/devices/lvm/batch.py | 11 | ||||
-rw-r--r-- | src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py | 23 |
2 files changed, 30 insertions, 4 deletions
diff --git a/src/ceph-volume/ceph_volume/devices/lvm/batch.py b/src/ceph-volume/ceph_volume/devices/lvm/batch.py index 8685f588c61..27ee5bb47e0 100644 --- a/src/ceph-volume/ceph_volume/devices/lvm/batch.py +++ b/src/ceph-volume/ceph_volume/devices/lvm/batch.py @@ -325,7 +325,6 @@ class Batch(object): self.execute() def _get_explicit_strategy(self): - # TODO assert that none of the device lists overlap? self._filter_devices() self._ensure_disjoint_device_lists() if self.args.bluestore: @@ -355,18 +354,22 @@ class Batch(object): # filter devices by their available property. # TODO: Some devices are rejected in the argparser already. maybe it # makes sense to unifiy this - used_reason = {"reasons": ["Used by ceph as a data device already"]} + used_reason = {"reasons": ["Used by ceph already"]} self.filtered_devices = {} for dev_list in ['', 'db_', 'wal_', 'journal_']: dev_list_prop = '{}devices'.format(dev_list) if hasattr(self.args, dev_list_prop): usable_dev_list_prop = '{}usable'.format(dev_list) - usable = [d for d in getattr(self.args, dev_list_prop) if - d.available] + devs = getattr(self.args, dev_list_prop) + usable = [d for d in devs if d.available] setattr(self, usable_dev_list_prop, usable) self.filtered_devices.update({d: used_reason for d in getattr(self.args, dev_list_prop) if d.used_by_ceph}) + if self.args.yes and dev_list and devs != usable: + err = '{} devices were filtered in non-interactive mode, bailing out' + raise RuntimeError(err.format(len(devs) - len(usable))) + def _ensure_disjoint_device_lists(self): # check that all device lists are disjoint with each other diff --git a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py index c6b3f3b6d4d..1c3c25f67e3 100644 --- a/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py +++ b/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py @@ -126,3 +126,26 @@ class TestFilterDevices(object): result, filtered_devices = batch.filter_devices(args) assert result assert len(filtered_devices) == 1 + + def test_no_auto_fails_on_unavailable_device(self, factory): + hdd1 = factory( + used_by_ceph=False, + abspath="/dev/sda", + rotational=True, + is_lvm_member=False, + available=True + ) + ssd1 = factory( + used_by_ceph=True, + abspath="/dev/nvme0n1", + rotational=False, + is_lvm_member=True, + available=False + ) + args = factory(devices=[hdd1], db_devices=[ssd1], filtered_devices={}, + yes=True) + b = batch.Batch([]) + b.args = args + with pytest.raises(RuntimeError) as ex: + b._filter_devices() + assert '1 devices were filtered in non-interactive mode, bailing out' in str(ex.value) |