From: Alfredo Deza Date: Thu, 12 Jul 2018 20:10:28 +0000 (-0400) Subject: ceph-volume lvm rename auto to batch X-Git-Tag: v12.2.8~10^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ba7b2ee04dc75a6fb5acc11e2d0897eea1fc0315;p=ceph.git ceph-volume lvm rename auto to batch Signed-off-by: Alfredo Deza (cherry picked from commit d7707650a59855eac75e37ddb4053c62b0dc11e9) --- diff --git a/src/ceph-volume/ceph_volume/devices/lvm/auto.py b/src/ceph-volume/ceph_volume/devices/lvm/auto.py deleted file mode 100644 index f8a2169a87ff..000000000000 --- a/src/ceph-volume/ceph_volume/devices/lvm/auto.py +++ /dev/null @@ -1,236 +0,0 @@ -import argparse -from textwrap import dedent -from ceph_volume import terminal, decorators -from ceph_volume.util import disk, prompt_bool -from . import strategies - - -device_list_template = """ - * {path: <25} {size: <10} {state}""" - - -def device_formatter(devices): - lines = [] - for path, details in devices: - lines.append(device_list_template.format( - path=path, size=details['human_readable_size'], - state='solid' if details['rotational'] == '0' else 'rotational') - ) - - return ''.join(lines) - - -# Scenario filtering/detection -def bluestore_single_type(device_facts): - """ - Detect devices that are just HDDs or solid state so that a 1:1 - device-to-osd provisioning can be done - """ - types = [device['rotational'] for device in device_facts] - if len(set(types)) == 1: - return strategies.bluestore.SingleType - - -def bluestore_mixed_type(device_facts): - """ - Detect if devices are HDDs as well as solid state so that block.db can be - placed in solid devices while data is kept in the spinning drives. - """ - types = [device['rotational'] for device in device_facts] - if len(set(types)) > 1: - return strategies.bluestore.MixedType - - -def filestore_single_type(device_facts): - """ - Detect devices that are just HDDs or solid state so that a 1:1 - device-to-osd provisioning can be done, keeping the journal on the OSD - """ - types = [device['rotational'] for device in device_facts] - if len(set(types)) == 1: - return strategies.filestore.SingleType - - -def filestore_mixed_type(device_facts): - """ - Detect if devices are HDDs as well as solid state so that the journal can be - placed in solid devices while data is kept in the spinning drives. - """ - types = [device['rotational'] for device in device_facts] - if len(set(types)) > 1: - return strategies.filestore.MixedType - - -def get_strategy(devices, args): - """ - 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 - total: - - * Single device type on Bluestore - * Mixed device types on Bluestore - * Single device type on Filestore - * Mixed device types on Filestore - - When the function matches to a scenario it returns the strategy class. This - allows for dynamic loading of the conditions needed for each scenario, with - normalized classes - """ - bluestore_strategies = [bluestore_mixed_type, bluestore_single_type] - filestore_strategies = [filestore_mixed_type, filestore_single_type] - if args.bluestore: - strategies = bluestore_strategies - else: - strategies = filestore_strategies - - for strategy in strategies: - backend = strategy(devices) - if backend: - return backend(devices, args) - - -class Auto(object): - - help = 'Automatically size devices for multi-OSD provisioning with minimal interaction' - - _help = dedent(""" - Automatically size devices ready for OSD provisioning based on default strategies. - - Detected devices: - {detected_devices} - - Usage: - - ceph-volume lvm auto [DEVICE...] - - Optional reporting on possible outcomes is enabled with --report - - ceph-volume lvm auto --report [DEVICE...] - """) - - def __init__(self, argv): - self.argv = argv - - def get_devices(self): - all_devices = disk.get_devices() - # remove devices with partitions - # XXX Should be optional when getting device info - for device, detail in all_devices.items(): - if detail.get('partitions') != {}: - del all_devices[device] - devices = sorted(all_devices.items(), key=lambda x: (x[0], x[1]['size'])) - return device_formatter(devices) - - def print_help(self): - return self._help.format( - detected_devices=self.get_devices(), - ) - - def get_filtered_devices(self, devices): - """ - Parse all devices in the current system and keep only the ones that are - being explicity passed in - """ - system_devices = disk.get_devices() - if not devices: - return system_devices.values() - parsed_devices = [] - for device in devices: - try: - parsed_devices.append(system_devices[device]) - except KeyError: - continue - - return parsed_devices - - def report(self, args): - strategy = get_strategy(self.get_filtered_devices(args.devices), args) - if args.format == 'pretty': - strategy.report_pretty() - elif args.format == 'json': - strategy.report_json() - else: - raise RuntimeError('report format must be "pretty" or "json"') - - def execute(self, args): - strategy = get_strategy(self.get_filtered_devices(args.devices), args) - if not args.yes: - strategy.report_pretty() - terminal.info('The above OSDs would be created if the operation continues') - if not prompt_bool('do you want to proceed? (yes/no)'): - terminal.error('aborting OSD provisioning for %s' % ','.join(args.devices)) - raise SystemExit(0) - - strategy.execute() - - @decorators.needs_root - def main(self): - parser = argparse.ArgumentParser( - prog='ceph-volume auto', - formatter_class=argparse.RawDescriptionHelpFormatter, - description=self.print_help(), - ) - - parser.add_argument( - 'devices', - metavar='DEVICES', - nargs='*', - default=[], - help='Devices to provision OSDs', - ) - parser.add_argument( - '--bluestore', - action='store_true', - help='bluestore objectstore (default)', - ) - parser.add_argument( - '--filestore', - action='store_true', - help='filestore objectstore', - ) - parser.add_argument( - '--report', - action='store_true', - help='Autodetect the objectstore by inspecting the OSD', - ) - parser.add_argument( - '--yes', - action='store_true', - help='Avoid prompting for confirmation when provisioning', - ) - parser.add_argument( - '--format', - help='output format, defaults to "pretty"', - default='pretty', - choices=['json', 'pretty'], - ) - parser.add_argument( - '--dmcrypt', - action='store_true', - help='Enable device encryption via dm-crypt', - ) - parser.add_argument( - '--crush-device-class', - dest='crush_device_class', - help='Crush device class to assign this OSD to', - ) - parser.add_argument( - '--no-systemd', - dest='no_systemd', - action='store_true', - help='Skip creating and enabling systemd units and starting OSD services', - ) - args = parser.parse_args(self.argv) - - if not args.devices: - return parser.print_help() - - # Default to bluestore here since defaulting it in add_argument may - # cause both to be True - if not args.bluestore and not args.filestore: - args.bluestore = True - - if args.report: - self.report(args) - else: - self.execute(args) diff --git a/src/ceph-volume/ceph_volume/devices/lvm/batch.py b/src/ceph-volume/ceph_volume/devices/lvm/batch.py new file mode 100644 index 000000000000..f8a2169a87ff --- /dev/null +++ b/src/ceph-volume/ceph_volume/devices/lvm/batch.py @@ -0,0 +1,236 @@ +import argparse +from textwrap import dedent +from ceph_volume import terminal, decorators +from ceph_volume.util import disk, prompt_bool +from . import strategies + + +device_list_template = """ + * {path: <25} {size: <10} {state}""" + + +def device_formatter(devices): + lines = [] + for path, details in devices: + lines.append(device_list_template.format( + path=path, size=details['human_readable_size'], + state='solid' if details['rotational'] == '0' else 'rotational') + ) + + return ''.join(lines) + + +# Scenario filtering/detection +def bluestore_single_type(device_facts): + """ + Detect devices that are just HDDs or solid state so that a 1:1 + device-to-osd provisioning can be done + """ + types = [device['rotational'] for device in device_facts] + if len(set(types)) == 1: + return strategies.bluestore.SingleType + + +def bluestore_mixed_type(device_facts): + """ + Detect if devices are HDDs as well as solid state so that block.db can be + placed in solid devices while data is kept in the spinning drives. + """ + types = [device['rotational'] for device in device_facts] + if len(set(types)) > 1: + return strategies.bluestore.MixedType + + +def filestore_single_type(device_facts): + """ + Detect devices that are just HDDs or solid state so that a 1:1 + device-to-osd provisioning can be done, keeping the journal on the OSD + """ + types = [device['rotational'] for device in device_facts] + if len(set(types)) == 1: + return strategies.filestore.SingleType + + +def filestore_mixed_type(device_facts): + """ + Detect if devices are HDDs as well as solid state so that the journal can be + placed in solid devices while data is kept in the spinning drives. + """ + types = [device['rotational'] for device in device_facts] + if len(set(types)) > 1: + return strategies.filestore.MixedType + + +def get_strategy(devices, args): + """ + 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 + total: + + * Single device type on Bluestore + * Mixed device types on Bluestore + * Single device type on Filestore + * Mixed device types on Filestore + + When the function matches to a scenario it returns the strategy class. This + allows for dynamic loading of the conditions needed for each scenario, with + normalized classes + """ + bluestore_strategies = [bluestore_mixed_type, bluestore_single_type] + filestore_strategies = [filestore_mixed_type, filestore_single_type] + if args.bluestore: + strategies = bluestore_strategies + else: + strategies = filestore_strategies + + for strategy in strategies: + backend = strategy(devices) + if backend: + return backend(devices, args) + + +class Auto(object): + + help = 'Automatically size devices for multi-OSD provisioning with minimal interaction' + + _help = dedent(""" + Automatically size devices ready for OSD provisioning based on default strategies. + + Detected devices: + {detected_devices} + + Usage: + + ceph-volume lvm auto [DEVICE...] + + Optional reporting on possible outcomes is enabled with --report + + ceph-volume lvm auto --report [DEVICE...] + """) + + def __init__(self, argv): + self.argv = argv + + def get_devices(self): + all_devices = disk.get_devices() + # remove devices with partitions + # XXX Should be optional when getting device info + for device, detail in all_devices.items(): + if detail.get('partitions') != {}: + del all_devices[device] + devices = sorted(all_devices.items(), key=lambda x: (x[0], x[1]['size'])) + return device_formatter(devices) + + def print_help(self): + return self._help.format( + detected_devices=self.get_devices(), + ) + + def get_filtered_devices(self, devices): + """ + Parse all devices in the current system and keep only the ones that are + being explicity passed in + """ + system_devices = disk.get_devices() + if not devices: + return system_devices.values() + parsed_devices = [] + for device in devices: + try: + parsed_devices.append(system_devices[device]) + except KeyError: + continue + + return parsed_devices + + def report(self, args): + strategy = get_strategy(self.get_filtered_devices(args.devices), args) + if args.format == 'pretty': + strategy.report_pretty() + elif args.format == 'json': + strategy.report_json() + else: + raise RuntimeError('report format must be "pretty" or "json"') + + def execute(self, args): + strategy = get_strategy(self.get_filtered_devices(args.devices), args) + if not args.yes: + strategy.report_pretty() + terminal.info('The above OSDs would be created if the operation continues') + if not prompt_bool('do you want to proceed? (yes/no)'): + terminal.error('aborting OSD provisioning for %s' % ','.join(args.devices)) + raise SystemExit(0) + + strategy.execute() + + @decorators.needs_root + def main(self): + parser = argparse.ArgumentParser( + prog='ceph-volume auto', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.print_help(), + ) + + parser.add_argument( + 'devices', + metavar='DEVICES', + nargs='*', + default=[], + help='Devices to provision OSDs', + ) + parser.add_argument( + '--bluestore', + action='store_true', + help='bluestore objectstore (default)', + ) + parser.add_argument( + '--filestore', + action='store_true', + help='filestore objectstore', + ) + parser.add_argument( + '--report', + action='store_true', + help='Autodetect the objectstore by inspecting the OSD', + ) + parser.add_argument( + '--yes', + action='store_true', + help='Avoid prompting for confirmation when provisioning', + ) + parser.add_argument( + '--format', + help='output format, defaults to "pretty"', + default='pretty', + choices=['json', 'pretty'], + ) + parser.add_argument( + '--dmcrypt', + action='store_true', + help='Enable device encryption via dm-crypt', + ) + parser.add_argument( + '--crush-device-class', + dest='crush_device_class', + help='Crush device class to assign this OSD to', + ) + parser.add_argument( + '--no-systemd', + dest='no_systemd', + action='store_true', + help='Skip creating and enabling systemd units and starting OSD services', + ) + args = parser.parse_args(self.argv) + + if not args.devices: + return parser.print_help() + + # Default to bluestore here since defaulting it in add_argument may + # cause both to be True + if not args.bluestore and not args.filestore: + args.bluestore = True + + if args.report: + self.report(args) + else: + self.execute(args)