From 4529f2d6053b0b07583a3d7501f4e05e08cad385 Mon Sep 17 00:00:00 2001 From: Andrew Schoen Date: Thu, 27 Sep 2018 15:22:17 -0500 Subject: [PATCH] ceph-volume: pick strategy for batch with only the unused devices This will pick a strategy, filter out any devices already been used by ceph and then pick a strategy again. If the strategy has changed the call should error, if the strategy is the same proceed. If there are no unused devices then the command is a noop. Signed-off-by: Andrew Schoen --- .../ceph_volume/devices/lvm/batch.py | 37 ++++++++++++++++--- .../devices/lvm/strategies/filestore.py | 6 +-- src/ceph-volume/ceph_volume/util/device.py | 4 +- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/ceph-volume/ceph_volume/devices/lvm/batch.py b/src/ceph-volume/ceph_volume/devices/lvm/batch.py index 45e99c5a795..a643e0aa186 100644 --- a/src/ceph-volume/ceph_volume/devices/lvm/batch.py +++ b/src/ceph-volume/ceph_volume/devices/lvm/batch.py @@ -5,6 +5,8 @@ from ceph_volume.util import disk, prompt_bool from ceph_volume.util import arg_validators from . import strategies +mlogger = terminal.MultiLogger(__name__) + device_list_template = """ * {path: <25} {size: <10} {state}""" @@ -62,7 +64,7 @@ def filestore_mixed_type(device_facts): return strategies.filestore.MixedType -def get_strategy(args): +def get_strategy(args, devices): """ Given a set of devices as input, go through the different detection mechanisms to narrow down on a strategy to use. The strategies are 4 in @@ -85,9 +87,9 @@ def get_strategy(args): strategies = filestore_strategies for strategy in strategies: - backend = strategy(args.devices) + backend = strategy(devices) if backend: - return backend(args.devices, args) + return backend class Batch(object): @@ -128,7 +130,7 @@ class Batch(object): ) def report(self, args): - strategy = get_strategy(args) + strategy = self._get_strategy(args) if args.format == 'pretty': strategy.report_pretty() elif args.format == 'json': @@ -137,7 +139,7 @@ class Batch(object): raise RuntimeError('report format must be "pretty" or "json"') def execute(self, args): - strategy = get_strategy(args) + strategy = self._get_strategy(args) if not args.yes: strategy.report_pretty() terminal.info('The above OSDs would be created if the operation continues') @@ -148,6 +150,31 @@ class Batch(object): strategy.execute() + def _get_strategy(self, args): + strategy = get_strategy(args, args.devices) + unused_devices = [device for device in args.devices if not device.used_by_ceph] + # only data devices, journals can be reused + used_devices = [device.abspath for device in args.devices if device.used_by_ceph] + args.filtered_devices = {} + if used_devices: + for device in used_devices: + args.filtered_devices[device] = {"reasons": ["Used by ceph as a data device already"]} + if not args.report: + mlogger.info("Ignoring devices already used by ceph: %s" % ",".join(used_devices)) + if not unused_devices and not args.report: + # report nothing changed + mlogger.info("All devices are already used by ceph. No OSDs will be created.") + raise SystemExit(0) + else: + new_strategy = get_strategy(args, unused_devices) + if type(strategy) != type(new_strategy): + if not args.report: + mlogger.error("aborting because strategy changed from %s to %s after filtering" % (strategy, new_strategy)) + raise SystemExit(0) + else: + strategy = new_strategy + return strategy(unused_devices, args) + @decorators.needs_root def main(self): parser = argparse.ArgumentParser( diff --git a/src/ceph-volume/ceph_volume/devices/lvm/strategies/filestore.py b/src/ceph-volume/ceph_volume/devices/lvm/strategies/filestore.py index fa7dc6ecb88..d2a3bd54fe7 100644 --- a/src/ceph-volume/ceph_volume/devices/lvm/strategies/filestore.py +++ b/src/ceph-volume/ceph_volume/devices/lvm/strategies/filestore.py @@ -31,7 +31,7 @@ class SingleType(object): self.devices = devices self.hdds = [device for device in devices if device.sys_api['rotational'] == '1'] self.ssds = [device for device in devices if device.sys_api['rotational'] == '0'] - self.computed = {'osds': [], 'vgs': []} + self.computed = {'osds': [], 'vgs': [], 'filtered_devices': args.filtered_devices} self.journal_size = get_journal_size(args) self.validate() self.compute() @@ -99,7 +99,6 @@ class SingleType(object): # chose whichever is the one group we have to compute against devices = self.hdds or self.ssds osds = self.computed['osds'] - used_osds = [] for device in devices: for osd in range(self.osds_per_device): device_size = disk.Size(b=device.sys_api['size']) @@ -107,7 +106,6 @@ class SingleType(object): journal_size = self.journal_size data_size = osd_size - journal_size data_percentage = data_size * 100 / device_size - used_osds.append(device.used_by_ceph) osd = {'data': {}, 'journal': {}, 'used_by_ceph': device.used_by_ceph} osd['data']['path'] = device.abspath osd['data']['size'] = data_size.b.as_int() @@ -120,7 +118,7 @@ class SingleType(object): osd['journal']['human_readable_size'] = str(journal_size) osds.append(osd) - self.computed['changed'] = not any(used_osds) + self.computed['changed'] = len(osds) > 0 def execute(self): """ diff --git a/src/ceph-volume/ceph_volume/util/device.py b/src/ceph-volume/ceph_volume/util/device.py index 2eb68d18f18..6e355fc4a64 100644 --- a/src/ceph-volume/ceph_volume/util/device.py +++ b/src/ceph-volume/ceph_volume/util/device.py @@ -118,7 +118,9 @@ class Device(object): @property def used_by_ceph(self): - osd_ids = [lv.tags.get("ceph.osd_id") for lv in self.lvs] + # only filter out data devices as journals could potentially be reused + osd_ids = [lv.tags.get("ceph.osd_id") for lv in self.lvs + if lv.tags.get("ceph.type") == "data"] return any(osd_ids) -- 2.39.5