import logging
import os
from textwrap import dedent
-from ceph_volume import process, conf, decorators, terminal
+from ceph_volume import process, conf, decorators, terminal, __release__, configuration
from ceph_volume.util import system, disk
from ceph_volume.util import prepare as prepare_utils
from ceph_volume.util import encryption as encryption_utils
from ceph_volume.systemd import systemctl
from ceph_volume.api import lvm as api
+from .listing import direct_report
logger = logging.getLogger(__name__)
-def activate_filestore(lvs):
+def activate_filestore(lvs, no_systemd=False):
# 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')
is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1'
+ is_vdo = osd_lv.tags.get('ceph.vdo', '0')
osd_id = osd_lv.tags['ceph.osd_id']
- conf.cluster = osd_lv.tags['ceph.cluster_name']
+ configuration.load_ceph_conf_path(osd_lv.tags['ceph.cluster_name'])
+ configuration.load()
# 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
+ # must be a disk partition, by querying blkid by the uuid we are ensuring that the
# device path is always correct
journal_uuid = osd_lv.tags['ceph.journal_uuid']
osd_journal = disk.get_device_from_partuuid(journal_uuid)
source = '/dev/mapper/%s' % osd_lv.lv_uuid
else:
source = osd_lv.lv_path
+
# mount the osd
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])
+ prepare_utils.mount_osd(source, osd_id, is_vdo=is_vdo)
+
+ # ensure that the OSD destination is always chowned properly
+ system.chown(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
# 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')
+ if no_systemd is False:
+ # enable the ceph-volume unit for this OSD
+ systemctl.enable_volume(osd_id, osd_fsid, 'lvm')
+
+ # enable the OSD
+ systemctl.enable_osd(osd_id)
- # start the OSD
- systemctl.start_osd(osd_id)
+ # start the OSD
+ systemctl.start_osd(osd_id)
terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
encryption_utils.luks_open(dmcrypt_secret, device_lv.lv_path, device_uuid)
return '/dev/mapper/%s' % device_uuid
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)
- if physical_device and is_encrypted:
+
+ # this could be a regular device, so query it with blkid
+ physical_device = disk.get_device_from_partuuid(device_uuid)
+ if physical_device:
+ if is_encrypted:
encryption_utils.luks_open(dmcrypt_secret, physical_device, device_uuid)
return '/dev/mapper/%s' % device_uuid
- return physical_device or None
- return None
+ return physical_device
+ raise RuntimeError('could not find %s with uuid %s' % (device_type, device_uuid))
-def activate_bluestore(lvs):
+
+def activate_bluestore(lvs, no_systemd=False):
# find the osd
osd_lv = lvs.get(lv_tags={'ceph.type': 'block'})
+ if not osd_lv:
+ raise RuntimeError('could not find a bluestore OSD to activate')
is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1'
dmcrypt_secret = None
osd_id = osd_lv.tags['ceph.osd_id']
db_device_path = get_osd_device_path(osd_lv, lvs, 'db', dmcrypt_secret=dmcrypt_secret)
wal_device_path = get_osd_device_path(osd_lv, lvs, 'wal', dmcrypt_secret=dmcrypt_secret)
- # Once symlinks are removed, the osd dir can be 'primed again.
- process.run([
+ # Once symlinks are removed, the osd dir can be 'primed again. chown first,
+ # regardless of what currently exists so that ``prime-osd-dir`` can succeed
+ # even if permissions are somehow messed up
+ system.chown(osd_path)
+ prime_command = [
'ceph-bluestore-tool', '--cluster=%s' % conf.cluster,
'prime-osd-dir', '--dev', osd_lv_path,
- '--path', osd_path])
+ '--path', osd_path]
+
+ if __release__ != "luminous":
+ # mon-config changes are not available in Luminous
+ prime_command.append('--no-mon-config')
+
+ process.run(prime_command)
# 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
destination = os.path.join(osd_path, 'block.db')
process.run(['ln', '-snf', db_device_path, destination])
system.chown(db_device_path)
+ system.chown(destination)
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)
+ system.chown(destination)
+
+ if no_systemd is False:
+ # enable the ceph-volume unit for this OSD
+ systemctl.enable_volume(osd_id, osd_fsid, 'lvm')
- # enable the ceph-volume unit for this OSD
- systemctl.enable_volume(osd_id, osd_fsid, 'lvm')
+ # enable the OSD
+ systemctl.enable_osd(osd_id)
- # start the OSD
- systemctl.start_osd(osd_id)
+ # start the OSD
+ systemctl.start_osd(osd_id)
terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
self.argv = argv
@decorators.needs_root
- def activate(self, args):
+ def activate_all(self, args):
+ listed_osds = direct_report()
+ osds = {}
+ for osd_id, devices in listed_osds.items():
+ # the metadata for all devices in each OSD will contain
+ # the FSID which is required for activation
+ for device in devices:
+ fsid = device.get('tags', {}).get('ceph.osd_fsid')
+ if fsid:
+ osds[fsid] = osd_id
+ break
+ if not osds:
+ terminal.warning('Was unable to find any OSDs to activate')
+ terminal.warning('Verify OSDs are present with "ceph-volume lvm list"')
+ return
+ for osd_fsid, osd_id in osds.items():
+ if systemctl.osd_is_active(osd_id):
+ terminal.warning(
+ 'OSD ID %s FSID %s process is active. Skipping activation' % (osd_id, osd_fsid)
+ )
+ else:
+ terminal.info('Activating OSD ID %s FSID %s' % (osd_id, osd_fsid))
+ self.activate(args, osd_id=osd_id, osd_fsid=osd_fsid)
+
+ @decorators.needs_root
+ 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 is not None else args.osd_id
+ osd_fsid = osd_fsid if osd_fsid is not None else args.osd_fsid
+
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 osd_id and osd_fsid:
+ lvs.filter(lv_tags={'ceph.osd_id': osd_id, 'ceph.osd_fsid': osd_fsid})
+ elif osd_fsid and not osd_id:
+ lvs.filter(lv_tags={'ceph.osd_fsid': osd_fsid})
if not lvs:
- raise RuntimeError('could not find osd.%s with fsid %s' % (args.osd_id, args.osd_fsid))
+ raise RuntimeError('could not find osd.%s with 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):
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)
+ return activate_filestore(lvs, no_systemd=args.no_systemd)
logger.info('unable to find a journal associated with the OSD, assuming bluestore')
- return activate_bluestore(lvs)
+ return activate_bluestore(lvs, no_systemd=args.no_systemd)
if args.bluestore:
- activate_bluestore(lvs)
+ activate_bluestore(lvs, no_systemd=args.no_systemd)
elif args.filestore:
- activate_filestore(lvs)
- terminal.success("ceph-volume lvm activate successful for osd ID: %s" % args.osd_id)
+ activate_filestore(lvs, no_systemd=args.no_systemd)
def main(self):
sub_command_help = dedent("""
The lvs associated with the OSD need to have been prepared previously,
so that all needed tags and metadata exist.
+ When migrating OSDs, or a multiple-osd activation is needed, the
+ ``--all`` flag can be used instead of the individual ID and FSID:
+
+ ceph-volume lvm activate --all
+
""")
parser = argparse.ArgumentParser(
prog='ceph-volume lvm activate',
parser.add_argument(
'--bluestore',
action='store_true',
- help='filestore objectstore (not yet implemented)',
+ help='bluestore objectstore (default)',
)
parser.add_argument(
'--filestore',
action='store_true',
- help='filestore objectstore (current default)',
+ help='filestore objectstore',
+ )
+ parser.add_argument(
+ '--all',
+ dest='activate_all',
+ action='store_true',
+ help='Activate all OSDs found in the system',
+ )
+ parser.add_argument(
+ '--no-systemd',
+ dest='no_systemd',
+ action='store_true',
+ help='Skip creating and enabling systemd units and starting OSD services',
)
if len(self.argv) == 0:
print(sub_command_help)
# cause both to be True
if not args.bluestore and not args.filestore:
args.bluestore = True
- self.activate(args)
+ if args.activate_all:
+ self.activate_all(args)
+ else:
+ self.activate(args)