Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
    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, {})
Ejemplo n.º 7
0
    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, {})
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)