def generate(self, devs=None): logger.debug('Listing block devices via lsblk...') if devs is None or devs == []: devs = [] # If no devs are given initially, we want to list ALL devices including children and # parents. Parent disks with child partitions may be the appropriate device to return if # the parent disk has a bluestore header, but children may be the most appropriate # devices to return if the parent disk does not have a bluestore header. out, err, ret = process.call([ 'lsblk', '--paths', '--output=NAME', '--noheadings', ]) assert not ret devs = out result = {} logger.debug('inspecting devices: {}'.format(devs)) for dev in devs: info = disk.lsblk(dev, abspath=True) # Linux kernels built with CONFIG_ATARI_PARTITION enabled can falsely interpret # bluestore's on-disk format as an Atari partition table. These false Atari partitions # can be interpreted as real OSDs if a bluestore OSD was previously created on the false # partition. See https://tracker.ceph.com/issues/52060 for more info. If a device has a # parent, it is a child. If the parent is a valid bluestore OSD, the child will only # exist if it is a phantom Atari partition, and the child should be ignored. If the # parent isn't bluestore, then the child could be a valid bluestore OSD. If we fail to # determine whether a parent is bluestore, we should err on the side of not reporting # the child so as not to give a false negative. if 'PKNAME' in info and info['PKNAME'] != "": parent = info['PKNAME'] try: if disk.has_bluestore_label(parent): logger.warning(( 'ignoring child device {} whose parent {} is a BlueStore OSD.' .format(dev, parent), 'device is likely a phantom Atari partition. device info: {}' .format(info))) continue except OSError as e: logger.error(( 'ignoring child device {} to avoid reporting invalid BlueStore data from phantom Atari partitions.' .format(dev), 'failed to determine if parent device {} is BlueStore. err: {}' .format(parent, e))) continue bs_info = _get_bluestore_info(dev) if bs_info is None: # None is also returned in the rare event that there is an issue reading info from # a BlueStore disk, so be sure to log our assumption that it isn't bluestore logger.info( 'device {} does not have BlueStore information'.format( dev)) continue result[bs_info['osd_uuid']] = bs_info return result
def _parse(self): if not sys_info.devices: sys_info.devices = disk.get_devices() self.sys_api = sys_info.devices.get(self.abspath, {}) if not self.sys_api: # if no device was found check if we are a partition partname = self.abspath.split('/')[-1] for device, info in sys_info.devices.items(): part = info['partitions'].get(partname, {}) if part: self.sys_api = part break # start with lvm since it can use an absolute or relative path lv = lvm.get_lv_from_argument(self.path) if lv: self.lv_api = lv self.lvs = [lv] self.abspath = lv.lv_path self.vg_name = lv.vg_name self.lv_name = lv.name else: dev = disk.lsblk(self.path) self.blkid_api = disk.blkid(self.path) self.disk_api = dev device_type = dev.get('TYPE', '') # always check is this is an lvm member if device_type in ['part', 'disk']: self._set_lvm_membership() self.ceph_disk = CephDiskDevice(self)
def _parse(self): lv = None if not self.sys_api: # if no device was found check if we are a partition partname = self.path.split('/')[-1] for device, info in sys_info.devices.items(): part = info['partitions'].get(partname, {}) if part: self.sys_api = part break if self.lvs: for _lv in self.lvs: # if the path is not absolute, we have 'vg/lv', let's use LV name # to get the LV. if self.path[0] == '/': if _lv.lv_path == self.path: lv = _lv break else: vgname, lvname = self.path.split('/') if _lv.lv_name == lvname and _lv.vg_name == vgname: lv = _lv break else: if self.path[0] == '/': lv = lvm.get_single_lv(filters={'lv_path': self.path}) else: vgname, lvname = self.path.split('/') lv = lvm.get_single_lv(filters={ 'lv_name': lvname, 'vg_name': vgname }) if lv: self.lv_api = lv self.lvs = [lv] self.path = lv.lv_path self.vg_name = lv.vg_name self.lv_name = lv.name self.ceph_device = lvm.is_ceph_device(lv) else: if self.lsblk_all: for dev in self.lsblk_all: if dev['NAME'] == os.path.basename(self.path): break else: dev = disk.lsblk(self.path) self.disk_api = dev device_type = dev.get('TYPE', '') # always check is this is an lvm member valid_types = ['part', 'disk'] if allow_loop_devices(): valid_types.append('loop') if device_type in valid_types: self._set_lvm_membership() self.ceph_device = disk.has_bluestore_label(self.path) self.ceph_disk = CephDiskDevice(self)
def prepare_dmcrypt(key, device, device_type, fsid): """ Helper for devices that are encrypted. The operations needed for block, db, wal, or data/journal devices are all the same """ if not device: return '' kname = disk.lsblk(device)['KNAME'] mapping = 'ceph-{}-{}-{}-dmcrypt'.format(fsid, kname, device_type) # format data device encryption_utils.luks_format(key, device) encryption_utils.luks_open(key, device, mapping) return '/dev/mapper/{}'.format(mapping)
def _parse(self): # start with lvm since it can use an absolute or relative path lv = lvm.get_lv_from_argument(self.path) if lv: self.lv_api = lv self.abspath = lv.lv_path else: dev = disk.lsblk(self.path) self.disk_api = dev device_type = dev.get('TYPE', '') # always check is this is an lvm member if device_type in ['part', 'disk']: self._set_lvm_membership() if not sys_info.devices: sys_info.devices = disk.get_devices() self.sys_api = sys_info.devices.get(self.abspath, {})
def _parse(self): if not sys_info.devices: sys_info.devices = disk.get_devices() self.sys_api = sys_info.devices.get(self.abspath, {}) if not self.sys_api: # if no device was found check if we are a partition partname = self.abspath.split('/')[-1] for device, info in sys_info.devices.items(): part = info['partitions'].get(partname, {}) if part: self.sys_api = part break # if the path is not absolute, we have 'vg/lv', let's use LV name # to get the LV. if self.path[0] == '/': lv = lvm.get_single_lv(filters={'lv_path': self.path}) else: vgname, lvname = self.path.split('/') lv = lvm.get_single_lv(filters={'lv_name': lvname, 'vg_name': vgname}) if lv: self.lv_api = lv self.lvs = [lv] 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) self.disk_api = dev device_type = dev.get('TYPE', '') # 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)
def _parse(self): if not sys_info.devices: sys_info.devices = disk.get_devices() self.sys_api = sys_info.devices.get(self.abspath, {}) if not self.sys_api: # if no device was found check if we are a partition partname = self.abspath.split('/')[-1] for device, info in sys_info.devices.items(): part = info['partitions'].get(partname, {}) if part: self.sys_api = part break # if the path is not absolute, we have 'vg/lv', let's use LV name # to get the LV. if self.path[0] == '/': lv = lvm.get_first_lv(filters={'lv_path': self.path}) else: vgname, lvname = self.path.split('/') lv = lvm.get_first_lv(filters={ 'lv_name': lvname, 'vg_name': vgname }) if lv: self.lv_api = lv self.lvs = [lv] self.abspath = lv.lv_path self.vg_name = lv.vg_name self.lv_name = lv.name else: dev = disk.lsblk(self.path) self.blkid_api = disk.blkid(self.path) self.disk_api = dev device_type = dev.get('TYPE', '') # always check is this is an lvm member if device_type in ['part', 'disk']: self._set_lvm_membership() self.ceph_disk = CephDiskDevice(self)
def main(self): sub_command_help = dedent(""" Scan an OSD directory (or data device) for files and configurations that will allow to take over the management of the OSD. Scanned OSDs will get their configurations stored in /etc/ceph/osd/<id>-<fsid>.json For an OSD ID of 0 with fsid of ``a9d50838-e823-43d6-b01f-2f8d0a77afc2`` that could mean a scan command that looks like:: ceph-volume lvm scan /var/lib/ceph/osd/ceph-0 Which would store the metadata in a JSON file at:: /etc/ceph/osd/0-a9d50838-e823-43d6-b01f-2f8d0a77afc2.json To a scan an existing, running, OSD: ceph-volume simple scan /var/lib/ceph/osd/{cluster}-{osd id} And to scan a device (mounted or unmounted) that has OSD data in it, for example /dev/sda1 ceph-volume simple scan /dev/sda1 """) parser = argparse.ArgumentParser( prog='ceph-volume simple scan', formatter_class=argparse.RawDescriptionHelpFormatter, description=sub_command_help, ) parser.add_argument( '-f', '--force', action='store_true', help='If OSD has already been scanned, the JSON file will be overwritten' ) parser.add_argument( '--stdout', action='store_true', help='Do not save to a file, output metadata to stdout' ) parser.add_argument( 'osd_path', metavar='OSD_PATH', type=arg_validators.OSDPath(), nargs='?', help='Path to an existing OSD directory or OSD data partition' ) if len(self.argv) == 0: print(sub_command_help) return args = parser.parse_args(self.argv) if disk.is_partition(args.osd_path): label = disk.lsblk(args.osd_path)['PARTLABEL'] if 'data' not in label: raise RuntimeError('Device must be the data partition, but got: %s' % label) # Capture some environment status, so that it can be reused all over self.device_mounts = system.get_mounts(devices=True) self.path_mounts = system.get_mounts(paths=True) self.encryption_metadata = encryption.legacy_encrypted(args.osd_path) self.is_encrypted = self.encryption_metadata['encrypted'] self.scan(args)
def main(self): sub_command_help = dedent(""" Scan an OSD directory (or data device) for files and configurations that will allow to take over the management of the OSD. Scanned OSDs will get their configurations stored in /etc/ceph/osd/<id>-<fsid>.json For an OSD ID of 0 with fsid of ``a9d50838-e823-43d6-b01f-2f8d0a77afc2`` that could mean a scan command that looks like:: ceph-volume lvm scan /var/lib/ceph/osd/ceph-0 Which would store the metadata in a JSON file at:: /etc/ceph/osd/0-a9d50838-e823-43d6-b01f-2f8d0a77afc2.json To a scan an existing, running, OSD: ceph-volume simple scan /var/lib/ceph/osd/{cluster}-{osd id} And to scan a device (mounted or unmounted) that has OSD data in it, for example /dev/sda1 ceph-volume simple scan /dev/sda1 """) parser = argparse.ArgumentParser( prog='ceph-volume simple scan', formatter_class=argparse.RawDescriptionHelpFormatter, description=sub_command_help, ) parser.add_argument( '-f', '--force', action='store_true', help= 'If OSD has already been scanned, the JSON file will be overwritten' ) parser.add_argument( '--stdout', action='store_true', help='Do not save to a file, output metadata to stdout') parser.add_argument( 'osd_path', metavar='OSD_PATH', type=arg_validators.OSDPath(), nargs='?', help='Path to an existing OSD directory or OSD data partition') if len(self.argv) == 0: print(sub_command_help) return args = parser.parse_args(self.argv) if disk.is_partition(args.osd_path): label = disk.lsblk(args.osd_path)['PARTLABEL'] if 'data' not in label: raise RuntimeError( 'Device must be the data partition, but got: %s' % label) # Capture some environment status, so that it can be reused all over self.device_mounts = system.get_mounts(devices=True) self.path_mounts = system.get_mounts(paths=True) self.encryption_metadata = encryption.legacy_encrypted(args.osd_path) self.is_encrypted = self.encryption_metadata['encrypted'] self.scan(args)