summaryrefslogtreecommitdiffstats
path: root/src/ceph-volume
diff options
context:
space:
mode:
authorJan Fajerski <jfajerski@suse.com>2019-12-03 13:44:00 +0100
committerJan Fajerski <jfajerski@suse.com>2020-01-27 14:35:40 +0100
commit2e985053deec6c4cf60c0b85aec3df16cd77ceeb (patch)
treef32855c156ec2daadde99507e726e36f0331dda0 /src/ceph-volume
parentMerge PR #32853 into master (diff)
downloadceph-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.py11
-rw-r--r--src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py23
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)