X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fceph-volume%2Fceph_volume%2Fdevices%2Flvm%2Factivate.py;fp=src%2Fceph%2Fsrc%2Fceph-volume%2Fceph_volume%2Fdevices%2Flvm%2Factivate.py;h=f0392fed67432130b5c800bc0d33d8c9a6ab1a5b;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py b/src/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py new file mode 100644 index 0000000..f0392fe --- /dev/null +++ b/src/ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py @@ -0,0 +1,217 @@ +from __future__ import print_function +import argparse +import logging +import os +from textwrap import dedent +from ceph_volume import process, conf, decorators +from ceph_volume.util import system, disk +from ceph_volume.util import prepare as prepare_utils +from ceph_volume.systemd import systemctl +from ceph_volume.api import lvm as api + + +logger = logging.getLogger(__name__) + + +def activate_filestore(lvs): + # find the osd + osd_lv = lvs.get(lv_tags={'ceph.type': 'data'}) + if not osd_lv: + raise RuntimeError('Unable to find a data LV for filestore activation') + osd_id = osd_lv.tags['ceph.osd_id'] + conf.cluster = osd_lv.tags['ceph.cluster_name'] + # it may have a volume with a journal + osd_journal_lv = lvs.get(lv_tags={'ceph.type': 'journal'}) + # TODO: add sensible error reporting if this is ever the case + # blow up with a KeyError if this doesn't exist + osd_fsid = osd_lv.tags['ceph.osd_fsid'] + if not osd_journal_lv: + # must be a disk partition, by quering blkid by the uuid we are ensuring that the + # device path is always correct + osd_journal = disk.get_device_from_partuuid(osd_lv.tags['ceph.journal_uuid']) + else: + osd_journal = osd_lv.tags['ceph.journal_device'] + + if not osd_journal: + raise RuntimeError('unable to detect an lv or device journal for OSD %s' % osd_id) + + # mount the osd + source = osd_lv.lv_path + destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) + if not system.device_is_mounted(source, destination=destination): + process.run(['mount', '-v', source, destination]) + + # always re-do the symlink regardless if it exists, so that the journal + # device path that may have changed can be mapped correctly every time + destination = '/var/lib/ceph/osd/%s-%s/journal' % (conf.cluster, osd_id) + process.run(['ln', '-snf', osd_journal, destination]) + + # make sure that the journal has proper permissions + system.chown(osd_journal) + + # enable the ceph-volume unit for this OSD + systemctl.enable_volume(osd_id, osd_fsid, 'lvm') + + # start the OSD + systemctl.start_osd(osd_id) + + +def get_osd_device_path(osd_lv, lvs, device_type): + """ + ``device_type`` can be one of ``db``, ``wal`` or ``block`` so that + we can query ``lvs`` (a ``Volumes`` object) and fallback to querying the uuid + if that is not present. + + Return a path if possible, failing to do that a ``None``, since some of these devices + are optional + """ + osd_lv = lvs.get(lv_tags={'ceph.type': 'block'}) + uuid_tag = 'ceph.%s_uuid' % device_type + device_uuid = osd_lv.tags.get(uuid_tag) + if not device_uuid: + return None + + device_lv = lvs.get(lv_uuid=device_uuid) + if device_lv: + return device_lv.lv_path + else: + # this could be a regular device, so query it with blkid + physical_device = disk.get_device_from_partuuid(device_uuid) + return physical_device or None + return None + + +def activate_bluestore(lvs): + # find the osd + osd_lv = lvs.get(lv_tags={'ceph.type': 'block'}) + osd_id = osd_lv.tags['ceph.osd_id'] + conf.cluster = osd_lv.tags['ceph.cluster_name'] + osd_fsid = osd_lv.tags['ceph.osd_fsid'] + db_device_path = get_osd_device_path(osd_lv, lvs, 'db') + wal_device_path = get_osd_device_path(osd_lv, lvs, 'wal') + + # mount on tmpfs the osd directory + osd_path = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) + if not system.path_is_mounted(osd_path): + # mkdir -p and mount as tmpfs + prepare_utils.create_osd_path(osd_id, tmpfs=True) + # XXX This needs to be removed once ceph-bluestore-tool can deal with + # symlinks that exist in the osd dir + for link_name in ['block', 'block.db', 'block.wal']: + link_path = os.path.join(osd_path, link_name) + if os.path.exists(link_path): + os.unlink(os.path.join(osd_path, link_name)) + # Once symlinks are removed, the osd dir can be 'primed again. + process.run([ + 'ceph-bluestore-tool', '--cluster=%s' % conf.cluster, + 'prime-osd-dir', '--dev', osd_lv.lv_path, + '--path', osd_path]) + # always re-do the symlink regardless if it exists, so that the block, + # block.wal, and block.db devices that may have changed can be mapped + # correctly every time + process.run(['ln', '-snf', osd_lv.lv_path, os.path.join(osd_path, 'block')]) + system.chown(os.path.join(osd_path, 'block')) + system.chown(osd_path) + if db_device_path: + destination = os.path.join(osd_path, 'block.db') + process.run(['ln', '-snf', db_device_path, destination]) + system.chown(db_device_path) + if wal_device_path: + destination = os.path.join(osd_path, 'block.wal') + process.run(['ln', '-snf', wal_device_path, destination]) + system.chown(wal_device_path) + + # enable the ceph-volume unit for this OSD + systemctl.enable_volume(osd_id, osd_fsid, 'lvm') + + # start the OSD + systemctl.start_osd(osd_id) + + +class Activate(object): + + help = 'Discover and mount the LVM device associated with an OSD ID and start the Ceph OSD' + + def __init__(self, argv): + self.argv = argv + + @decorators.needs_root + def activate(self, args): + lvs = api.Volumes() + # filter them down for the OSD ID and FSID we need to activate + if args.osd_id and args.osd_fsid: + lvs.filter(lv_tags={'ceph.osd_id': args.osd_id, 'ceph.osd_fsid': args.osd_fsid}) + elif args.osd_fsid and not args.osd_id: + lvs.filter(lv_tags={'ceph.osd_fsid': args.osd_fsid}) + if not lvs: + raise RuntimeError('could not find osd.%s with fsid %s' % (args.osd_id, args.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 lvs.get() 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) + logger.info('unable to find a journal associated with the OSD, assuming bluestore') + return activate_bluestore(lvs) + if args.bluestore: + activate_bluestore(lvs) + elif args.filestore: + activate_filestore(lvs) + + def main(self): + sub_command_help = dedent(""" + Activate OSDs by discovering them with LVM and mounting them in their + appropriate destination: + + ceph-volume lvm activate {ID} {FSID} + + The lvs associated with the OSD need to have been prepared previously, + so that all needed tags and metadata exist. + + """) + parser = argparse.ArgumentParser( + prog='ceph-volume lvm activate', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=sub_command_help, + ) + + parser.add_argument( + 'osd_id', + metavar='ID', + nargs='?', + help='The ID of the OSD, usually an integer, like 0' + ) + parser.add_argument( + 'osd_fsid', + metavar='FSID', + nargs='?', + help='The FSID of the OSD, similar to a SHA1' + ) + parser.add_argument( + '--auto-detect-objectstore', + action='store_true', + help='Autodetect the objectstore by inspecting the OSD', + ) + parser.add_argument( + '--bluestore', + action='store_true', + help='filestore objectstore (not yet implemented)', + ) + parser.add_argument( + '--filestore', + action='store_true', + help='filestore objectstore (current default)', + ) + if len(self.argv) == 0: + print(sub_command_help) + return + args = parser.parse_args(self.argv) + # 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 + self.activate(args)