示例#1
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)
示例#2
0
    def safe_prepare(self, args=None):
        """
        An intermediate step between `main()` and `prepare()` so that we can
        capture the `self.osd_id` in case we need to rollback

        :param args: Injected args, usually from `lvm create` which compounds
                     both `prepare` and `create`
        """
        if args is not None:
            self.args = args

        try:
            vgname, lvname = self.args.data.split('/')
            lv = api.get_single_lv(filters={
                'lv_name': lvname,
                'vg_name': vgname
            })
        except ValueError:
            lv = None

        if api.is_ceph_device(lv):
            logger.info("device {} is already used".format(self.args.data))
            raise RuntimeError("skipping {}, it is already prepared".format(
                self.args.data))
        try:
            self.prepare()
        except Exception:
            logger.exception('lvm prepare was unable to complete')
            logger.info('will rollback OSD ID creation')
            rollback_osd(self.args, self.osd_id)
            raise
        terminal.success("ceph-volume lvm prepare successful for: %s" %
                         self.args.data)
示例#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()
示例#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
示例#5
0
文件: test_lvm.py 项目: zhangsw/ceph
    def test_get_single_lv_multiple_matches_raises_runtimeerror(self, m_get_lvs):
        fake_lvs = []
        fake_lvs.append(api.Volume(lv_name='lv1',
                                   lv_path='/dev/vg1/lv1',
                                   vg_name='vg1',
                                   lv_tags='',
                                   lv_uuid='fake-uuid'))
        fake_lvs.append(api.Volume(lv_name='lv1',
                                   lv_path='/dev/vg2/lv1',
                                   vg_name='vg2',
                                   lv_tags='',
                                   lv_uuid='fake-uuid'))
        m_get_lvs.return_value = fake_lvs

        with pytest.raises(RuntimeError) as e:
            api.get_single_lv()
        assert "matched more than 1 LV present on this host" in str(e.value)
示例#6
0
文件: test_lvm.py 项目: zhangsw/ceph
    def test_get_single_lv_one_match(self, m_get_lvs):
        fake_lvs = []
        fake_lvs.append(api.Volume(lv_name='lv1', lv_path='/dev/vg1/lv1', vg_name='vg1', lv_tags='', lv_uuid='fake-uuid'))
        m_get_lvs.return_value = fake_lvs

        lv_ = api.get_single_lv()

        assert isinstance(lv_, api.Volume)
        assert lv_.name == 'lv1'
示例#7
0
文件: device.py 项目: whaddock/ceph
    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)
示例#8
0
    def setup_device(self, device_type, device_name, tags, size, slots):
        """
        Check if ``device`` is an lv, if so, set the tags, making sure to
        update the tags with the lv_uuid and lv_path which the incoming tags
        will not have.

        If the device is not a logical volume, then retrieve the partition UUID
        by querying ``blkid``
        """
        if device_name is None:
            return '', '', tags
        tags['ceph.type'] = device_type
        tags['ceph.vdo'] = api.is_vdo(device_name)

        try:
            vg_name, lv_name = device_name.split('/')
            lv = api.get_single_lv(filters={
                'lv_name': lv_name,
                'vg_name': vg_name
            })
        except ValueError:
            lv = None

        if lv:
            lv_uuid = lv.lv_uuid
            path = lv.lv_path
            tags['ceph.%s_uuid' % device_type] = lv_uuid
            tags['ceph.%s_device' % device_type] = path
            lv.set_tags(tags)
        elif disk.is_device(device_name):
            # We got a disk, create an lv
            lv_type = "osd-{}".format(device_type)
            name_uuid = system.generate_uuid()
            kwargs = {'device': device_name, 'tags': tags, 'slots': slots}
            #TODO use get_block_db_size and co here to get configured size in
            #conf file
            if size != 0:
                kwargs['size'] = size
            lv = api.create_lv(lv_type, name_uuid, **kwargs)
            path = lv.lv_path
            tags['ceph.{}_device'.format(device_type)] = path
            tags['ceph.{}_uuid'.format(device_type)] = lv.lv_uuid
            lv_uuid = lv.lv_uuid
            lv.set_tags(tags)
        else:
            # otherwise assume this is a regular disk partition
            name_uuid = self.get_ptuuid(device_name)
            path = device_name
            tags['ceph.%s_uuid' % device_type] = name_uuid
            tags['ceph.%s_device' % device_type] = path
            lv_uuid = name_uuid
        return path, lv_uuid, tags
示例#9
0
    def scan_device(self, path):
        device_metadata = {'path': None, 'uuid': None}
        if not path:
            return device_metadata
        if self.is_encrypted:
            encryption_metadata = encryption.legacy_encrypted(path)
            device_metadata['path'] = encryption_metadata['device']
            device_metadata['uuid'] = disk.get_partuuid(encryption_metadata['device'])
            return device_metadata
        # cannot read the symlink if this is tmpfs
        if os.path.islink(path):
            device = os.readlink(path)
        else:
            device = path
        lvm_device = lvm.get_single_lv(filters={'lv_path': device})
        if lvm_device:
            device_uuid = lvm_device.lv_uuid
        else:
            device_uuid = disk.get_partuuid(device)

        device_metadata['uuid'] = device_uuid
        device_metadata['path'] = device

        return device_metadata
示例#10
0
    def prepare(self):
        # FIXME we don't allow re-using a keyring, we always generate one for the
        # OSD, this needs to be fixed. This could either be a file (!) or a string
        # (!!) or some flags that we would need to compound into a dict so that we
        # can convert to JSON (!!!)
        secrets = {'cephx_secret': prepare_utils.create_key()}
        cephx_lockbox_secret = ''
        encrypted = 1 if self.args.dmcrypt else 0
        cephx_lockbox_secret = '' if not encrypted else prepare_utils.create_key(
        )

        if encrypted:
            secrets['dmcrypt_key'] = encryption_utils.create_dmcrypt_key()
            secrets['cephx_lockbox_secret'] = cephx_lockbox_secret

        cluster_fsid = self.get_cluster_fsid()

        osd_fsid = self.args.osd_fsid or system.generate_uuid()
        crush_device_class = self.args.crush_device_class
        if crush_device_class:
            secrets['crush_device_class'] = crush_device_class
        # reuse a given ID if it exists, otherwise create a new ID
        self.osd_id = prepare_utils.create_id(osd_fsid,
                                              json.dumps(secrets),
                                              osd_id=self.args.osd_id)
        tags = {
            'ceph.osd_fsid': osd_fsid,
            'ceph.osd_id': self.osd_id,
            'ceph.cluster_fsid': cluster_fsid,
            'ceph.cluster_name': conf.cluster,
            'ceph.crush_device_class': crush_device_class,
            'ceph.osdspec_affinity': prepare_utils.get_osdspec_affinity()
        }
        if self.args.filestore:
            if not self.args.journal:
                logger.info(('no journal was specifed, creating journal lv '
                             'on {}').format(self.args.data))
                self.args.journal = self.args.data
                self.args.journal_size = disk.Size(g=5)
                # need to adjust data size/slots for colocated journal
                if self.args.data_size:
                    self.args.data_size -= self.args.journal_size
                if self.args.data_slots == 1:
                    self.args.data_slots = 0
                else:
                    raise RuntimeError('Can\'t handle multiple filestore OSDs '
                                       'with colocated journals yet. Please '
                                       'create journal LVs manually')
            tags['ceph.cephx_lockbox_secret'] = cephx_lockbox_secret
            tags['ceph.encrypted'] = encrypted

            journal_device, journal_uuid, tags = self.setup_device(
                'journal', self.args.journal, tags, self.args.journal_size,
                self.args.journal_slots)

            try:
                vg_name, lv_name = self.args.data.split('/')
                data_lv = api.get_single_lv(filters={
                    'lv_name': lv_name,
                    'vg_name': vg_name
                })
            except ValueError:
                data_lv = None

            if not data_lv:
                data_lv = self.prepare_data_device('data', osd_fsid)

            tags['ceph.data_device'] = data_lv.lv_path
            tags['ceph.data_uuid'] = data_lv.lv_uuid
            tags['ceph.vdo'] = api.is_vdo(data_lv.lv_path)
            tags['ceph.type'] = 'data'
            data_lv.set_tags(tags)
            if not journal_device.startswith('/'):
                # we got a journal lv, set rest of the tags
                api.get_single_lv(filters={
                    'lv_name': lv_name,
                    'vg_name': vg_name
                }).set_tags(tags)

            prepare_filestore(
                data_lv.lv_path,
                journal_device,
                secrets,
                tags,
                self.osd_id,
                osd_fsid,
            )
        elif self.args.bluestore:
            try:
                vg_name, lv_name = self.args.data.split('/')
                block_lv = api.get_single_lv(filters={
                    'lv_name': lv_name,
                    'vg_name': vg_name
                })
            except ValueError:
                block_lv = None

            if not block_lv:
                block_lv = self.prepare_data_device('block', osd_fsid)

            tags['ceph.block_device'] = block_lv.lv_path
            tags['ceph.block_uuid'] = block_lv.lv_uuid
            tags['ceph.cephx_lockbox_secret'] = cephx_lockbox_secret
            tags['ceph.encrypted'] = encrypted
            tags['ceph.vdo'] = api.is_vdo(block_lv.lv_path)

            wal_device, wal_uuid, tags = self.setup_device(
                'wal', self.args.block_wal, tags, self.args.block_wal_size,
                self.args.block_wal_slots)
            db_device, db_uuid, tags = self.setup_device(
                'db', self.args.block_db, tags, self.args.block_db_size,
                self.args.block_db_slots)

            tags['ceph.type'] = 'block'
            block_lv.set_tags(tags)

            prepare_bluestore(
                block_lv.lv_path,
                wal_device,
                db_device,
                secrets,
                tags,
                self.osd_id,
                osd_fsid,
            )
示例#11
0
文件: test_lvm.py 项目: zhangsw/ceph
    def test_get_single_lv_no_match_returns_none(self, m_get_lvs):
        m_get_lvs.return_value = []

        lv = api.get_single_lv()
        assert lv == None