]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/ceph-volume/ceph_volume/devices/lvm/activate.py
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / ceph-volume / ceph_volume / devices / lvm / activate.py
index 81ebe6b0b1c8d7e5bef8b0581f75f4580ff950e1..d46db9edfa5866aa4632134940cdbde02267ca0e 100644 (file)
@@ -3,33 +3,36 @@ import argparse
 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)
@@ -54,10 +57,14 @@ def activate_filestore(lvs):
         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
@@ -67,11 +74,15 @@ def activate_filestore(lvs):
     # 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)
 
 
@@ -98,19 +109,23 @@ def get_osd_device_path(osd_lv, lvs, device_type, dmcrypt_secret=None):
             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']
@@ -141,11 +156,20 @@ def activate_bluestore(lvs):
     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
@@ -156,16 +180,22 @@ def activate_bluestore(lvs):
         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)
 
 
@@ -177,15 +207,48 @@ class Activate(object):
         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):
@@ -195,14 +258,13 @@ class Activate(object):
                 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("""
@@ -214,6 +276,11 @@ class Activate(object):
         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',
@@ -241,12 +308,24 @@ class Activate(object):
         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)
@@ -256,4 +335,7 @@ class Activate(object):
         # 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)