Esempio n. 1
0
    def single_report(self, device):
        """
        Generate a report for a single device. This can be either a logical
        volume in the form of vg/lv or a device with an absolute path like
        /dev/sda1 or /dev/sda. Returns '{}' to denote failure.
        """
        lvs = []
        if os.path.isabs(device):
            # we have a block device
            lvs = api.get_device_lvs(device)
            if not lvs:
                # maybe this was a LV path /dev/vg_name/lv_name or /dev/mapper/
                lvs = api.get_lvs(filters={'path': device})
        else:
            # vg_name/lv_name was passed
            vg_name, lv_name = device.split('/')
            lvs = api.get_lvs(filters={'lv_name': lv_name, 'vg_name': vg_name})

        report = self.create_report(lvs)

        if not report:
            # check if device is a non-lvm journals or wal/db
            for dev_type in ['journal', 'wal', 'db']:
                lvs = api.get_lvs(
                    tags={'ceph.{}_device'.format(dev_type): device})
                if lvs:
                    # just taking the first lv here should work
                    lv = lvs[0]
                    phys_dev = self.create_report_non_lv_device(lv)
                    osd_id = lv.tags.get('ceph.osd_id')
                    if osd_id:
                        report[osd_id] = [phys_dev]

        return report
Esempio n. 2
0
def ensure_associated_lvs(lvs, lv_tags={}):
    """
    Go through each LV and ensure if backing devices (journal, wal, block)
    are LVs or partitions, so that they can be accurately reported.
    """
    # look for many LVs for each backing type, because it is possible to
    # receive a filtering for osd.1, and have multiple failed deployments
    # leaving many journals with osd.1 - usually, only a single LV will be
    # returned

    journal_lvs = api.get_lvs(
        tags=merge_dict(lv_tags, {'ceph.type': 'journal'}))
    db_lvs = api.get_lvs(tags=merge_dict(lv_tags, {'ceph.type': 'db'}))
    wal_lvs = api.get_lvs(tags=merge_dict(lv_tags, {'ceph.type': 'wal'}))
    backing_devices = [(journal_lvs, 'journal'), (db_lvs, 'db'),
                       (wal_lvs, 'wal')]

    verified_devices = []

    for lv in lvs:
        # go through each lv and append it, otherwise query `blkid` to find
        # a physical device. Do this for each type (journal,db,wal) regardless
        # if they have been processed in the previous LV, so that bad devices
        # with the same ID can be caught
        for ceph_lvs, _type in backing_devices:
            if ceph_lvs:
                verified_devices.extend([l.lv_path for l in ceph_lvs])
                continue

            # must be a disk partition, by querying blkid by the uuid we are
            # ensuring that the device path is always correct
            try:
                device_uuid = lv.tags['ceph.%s_uuid' % _type]
            except KeyError:
                # Bluestore will not have ceph.journal_uuid, and Filestore
                # will not not have ceph.db_uuid
                continue

            osd_device = disk.get_device_from_partuuid(device_uuid)
            if not osd_device:
                # if the osd_device is not found by the partuuid, then it is
                # not possible to ensure this device exists anymore, so skip it
                continue
            verified_devices.append(osd_device)

        verified_devices.append(lv.lv_path)

    # reduce the list from all the duplicates that were added
    return list(set(verified_devices))
Esempio n. 3
0
    def zap_lv(self, device):
        """
        Device examples: vg-name/lv-name, /dev/vg-name/lv-name
        Requirements: Must be a logical volume (LV)
        """
        lv = api.get_single_lv(filters={
            'lv_name': device.lv_name,
            'vg_name': device.vg_name
        })
        self.unmount_lv(lv)

        wipefs(device.abspath)
        zap_data(device.abspath)

        if self.args.destroy:
            lvs = api.get_lvs(filters={'vg_name': device.vg_name})
            if lvs == []:
                mlogger.info('No LVs left, exiting', device.vg_name)
                return
            elif len(lvs) <= 1:
                mlogger.info(
                    'Only 1 LV left in VG, will proceed to destroy '
                    'volume group %s', device.vg_name)
                api.remove_vg(device.vg_name)
            else:
                mlogger.info('More than 1 LV left in VG, will proceed to '
                             'destroy LV only')
                mlogger.info('Removing LV because --destroy was given: %s',
                             device.abspath)
                api.remove_lv(device.abspath)
        elif lv:
            # just remove all lvm metadata, leaving the LV around
            lv.clear_tags()
Esempio n. 4
0
    def single_report(self, arg):
        """
        Generate a report for a single device. This can be either a logical
        volume in the form of vg/lv, a device with an absolute path like
        /dev/sda1 or /dev/sda, or a list of devices under same OSD ID.

        Return value '{}' denotes failure.
        """
        if isinstance(arg, int) or arg.isdigit():
            lv = api.get_lvs_from_osd_id(arg)
        elif arg[0] == '/':
            lv = api.get_lvs_from_path(arg)
        else:
            lv = [api.get_single_lv(filters={'lv_name': arg.split('/')[1]})]

        report = self.create_report(lv)

        if not report:
            # check if device is a non-lvm journals or wal/db
            for dev_type in ['journal', 'wal', 'db']:
                lvs = api.get_lvs(
                    tags={'ceph.{}_device'.format(dev_type): arg})
                if lvs:
                    # just taking the first lv here should work
                    lv = lvs[0]
                    phys_dev = self.create_report_non_lv_device(lv)
                    osd_id = lv.tags.get('ceph.osd_id')
                    if osd_id:
                        report[osd_id] = [phys_dev]

        return report
Esempio n. 5
0
    def test_get_lvs_single_lv(self, monkeypatch):
        stdout = ['ceph.type=data;/dev/vg/lv;lv;vg']
        monkeypatch.setattr(api.process, 'call', lambda x,**kw: (stdout, '', 0))
        lvs = []
        lvs.append((api.Volume(lv_tags='ceph.type=data',
                           lv_path='/dev/vg/lv',
                           lv_name='lv', vg_name='vg')))

        lvs_ = api.get_lvs()
        assert len(lvs_) == len(lvs)
        assert lvs[0].__dict__ == lvs_[0].__dict__
Esempio n. 6
0
    def activate(self, args, osd_id=None, osd_fsid=None):
        """
        :param args: The parsed arguments coming from the CLI
        :param osd_id: When activating all, this gets populated with an
                       existing OSD ID
        :param osd_fsid: When activating all, this gets populated with an
                         existing OSD FSID
        """
        osd_id = osd_id if osd_id else args.osd_id
        osd_fsid = osd_fsid if osd_fsid else args.osd_fsid

        if osd_id and osd_fsid:
            tags = {'ceph.osd_id': osd_id, 'ceph.osd_fsid': osd_fsid}
        elif not osd_id and osd_fsid:
            tags = {'ceph.osd_fsid': osd_fsid}
        elif osd_id and not osd_fsid:
            raise RuntimeError('could not activate osd.{}, please provide the '
                               'osd_fsid too'.format(osd_id))
        else:
            raise RuntimeError('Please provide both osd_id and osd_fsid')
        lvs = api.get_lvs(tags=tags)
        if not lvs:
            raise RuntimeError('could not find osd.%s with osd_fsid %s' %
                               (osd_id, osd_fsid))

        # This argument is only available when passed in directly or via
        # systemd, not when ``create`` is being used
        if getattr(args, 'auto_detect_objectstore', False):
            logger.info('auto detecting objectstore')
            # may get multiple lvs, so can't do get_the_lvs() calls here
            for lv in lvs:
                has_journal = lv.tags.get('ceph.journal_uuid')
                if has_journal:
                    logger.info('found a journal associated with the OSD, '
                                'assuming filestore')
                    return activate_filestore(lvs, args.no_systemd)

            logger.info('unable to find a journal associated with the OSD, '
                        'assuming bluestore')

            return activate_bluestore(lvs, args.no_systemd)

        # explicit filestore/bluestore flags take precedence
        if getattr(args, 'bluestore', False):
            activate_bluestore(lvs, args.no_systemd,
                               getattr(args, 'no_tmpfs', False))
        elif getattr(args, 'filestore', False):
            activate_filestore(lvs, args.no_systemd)
        elif any('ceph.block_device' in lv.tags for lv in lvs):
            activate_bluestore(lvs, args.no_systemd,
                               getattr(args, 'no_tmpfs', False))
        elif any('ceph.data_device' in lv.tags for lv in lvs):
            activate_filestore(lvs, args.no_systemd)
Esempio n. 7
0
    def test_get_lvs(self, monkeypatch):
        lv1 = api.Volume(lv_tags='ceph.type=data', lv_path='/dev/vg1/lv1',
                         lv_name='lv1', vg_name='vg1')
        lv2 = api.Volume(lv_tags='ceph.type=data', lv_path='/dev/vg2/lv2',
                         lv_name='lv2', vg_name='vg2')
        lvs = [lv1, lv2]
        stdout = ['{};{};{};{}'.format(lv1.lv_tags, lv1.lv_path, lv1.lv_name,
                                       lv1.vg_name),
                  '{};{};{};{}'.format(lv2.lv_tags, lv2.lv_path, lv2.lv_name,
                                       lv2.vg_name)]
        monkeypatch.setattr(api.process, 'call', lambda x,**kw: (stdout, '', 0))

        lvs_ = api.get_lvs()
        assert len(lvs_) == len(lvs)
        for lv, lv_ in zip(lvs, lvs_):
            assert lv.__dict__ == lv_.__dict__
Esempio n. 8
0
 def __init__(self, filter_for_batch=False, with_lsm=False):
     lvs = lvm.get_lvs()
     lsblk_all = disk.lsblk_all()
     all_devices_vgs = lvm.get_all_devices_vgs()
     if not sys_info.devices:
         sys_info.devices = disk.get_devices()
     self.devices = [
         Device(k,
                with_lsm,
                lvs=lvs,
                lsblk_all=lsblk_all,
                all_devices_vgs=all_devices_vgs)
         for k in sys_info.devices.keys()
     ]
     if filter_for_batch:
         self.devices = [d for d in self.devices if d.available_lvm_batch]
Esempio n. 9
0
def get_cluster_name(osd_id, osd_fsid):
    """
    From an ``osd_id`` and/or an ``osd_fsid``, filter out all the LVs in the
    system that match those tag values, then return cluster_name for the first
    one.
    """
    lv_tags = {}
    lv_tags['ceph.osd_id'] = osd_id
    lv_tags['ceph.osd_fsid'] = osd_fsid

    lvs = api.get_lvs(tags=lv_tags)
    if not lvs:
        mlogger.error(
            'Unable to find any LV for source OSD: id:{} fsid:{}'.format(
                osd_id,  osd_fsid)        )
        raise SystemExit('Unexpected error, terminating')
    return next(iter(lvs)).tags["ceph.cluster_name"]
Esempio n. 10
0
def find_associated_devices(osd_id, osd_fsid):
    """
    From an ``osd_id`` and/or an ``osd_fsid``, filter out all the LVs in the
    system that match those tag values, further detect if any partitions are
    part of the OSD, and then return the set of LVs and partitions (if any).
    """
    lv_tags = {}
    lv_tags['ceph.osd_id'] = osd_id
    lv_tags['ceph.osd_fsid'] = osd_fsid

    lvs = api.get_lvs(tags=lv_tags)
    if not lvs:
        mlogger.error(
            'Unable to find any LV for source OSD: id:{} fsid:{}'.format(
                osd_id,  osd_fsid)        )
        raise SystemExit('Unexpected error, terminating')

    devices = set(ensure_associated_lvs(lvs, lv_tags))
    return [(Device(path), type) for path, type in devices if path]
Esempio n. 11
0
def find_associated_devices(osd_id=None, osd_fsid=None):
    """
    From an ``osd_id`` and/or an ``osd_fsid``, filter out all the LVs in the
    system that match those tag values, further detect if any partitions are
    part of the OSD, and then return the set of LVs and partitions (if any).
    """
    lv_tags = {}
    if osd_id:
        lv_tags['ceph.osd_id'] = osd_id
    if osd_fsid:
        lv_tags['ceph.osd_fsid'] = osd_fsid

    lvs = api.get_lvs(tags=lv_tags)
    if not lvs:
        raise RuntimeError('Unable to find any LV for zapping OSD: '
                           '%s' % osd_id or osd_fsid)

    devices_to_zap = ensure_associated_lvs(lvs, lv_tags)
    return [Device(path) for path in set(devices_to_zap) if path]
Esempio n. 12
0
 def full_report(self):
     """
     Create a report of all Ceph LVs. Returns '{}' to denote failure.
     """
     return self.create_report(api.get_lvs())
Esempio n. 13
0
 def test_get_first_lv_empty(self, monkeypatch):
     monkeypatch.setattr(api.process, 'call', lambda x,**kw: ('', '', 0))
     assert api.get_lvs() == []