]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-volume lvm.zap initial take on zapping by OSD ID, FSID
authorAlfredo Deza <adeza@redhat.com>
Thu, 6 Dec 2018 15:54:11 +0000 (10:54 -0500)
committerAlfredo Deza <adeza@redhat.com>
Thu, 17 Jan 2019 19:01:03 +0000 (14:01 -0500)
Signed-off-by: Alfredo Deza <adeza@redhat.com>
(cherry picked from commit 59f6cec6dd0687a2528f75a518bd0d4617c27fe0)

src/ceph-volume/ceph_volume/devices/lvm/zap.py

index a77ac5f907ae0c19efef0ae3b0e3d57e1d2a7357..fbd784b63faa254742c5bb64a4436b441153e7a2 100644 (file)
@@ -8,6 +8,7 @@ from ceph_volume import decorators, terminal, process
 from ceph_volume.api import lvm as api
 from ceph_volume.util import system, encryption, disk, arg_validators
 from ceph_volume.util.device import Device
+from ceph_volume.systemd import systemctl
 
 logger = logging.getLogger(__name__)
 mlogger = terminal.MultiLogger(__name__)
@@ -41,6 +42,79 @@ def zap_data(path):
     ])
 
 
+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.Volumes()
+    lvs.filter(lv_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)
+
+    return [Device(path) for path in set(devices_to_zap) if path]
+
+
+def ensure_associated_lvs(lvs):
+    """
+    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
+    # recieve 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 = lvs._filter(lv_tags={'ceph.type': 'journal'})
+    db_lvs = lvs._filter(lv_tags={'ceph.type': 'db'})
+    wal_lvs = lvs._filter(lv_tags={'ceph.type': 'wal'})
+    backing_devices = [
+        (journal_lvs, 'journal'),
+        (db_lvs, 'block'),
+        (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))
+
+
 class Zap(object):
 
     help = 'Removes all data and filesystems from a logical volume or partition.'
@@ -147,8 +221,10 @@ class Zap(object):
         zap_data(device.abspath)
 
     @decorators.needs_root
-    def zap(self):
-        for device in self.args.devices:
+    def zap(self, devices=None):
+        devices = devices or self.args.devices
+
+        for device in devices:
             mlogger.info("Zapping: %s", device.abspath)
             if device.is_mapper:
                 terminal.error("Refusing to zap the mapper device: {}".format(device))
@@ -164,6 +240,17 @@ class Zap(object):
 
         terminal.success("Zapping successful for: %s" % ", ".join([str(d) for d in self.args.devices]))
 
+    @decorators.needs_root
+    def zap_osd(self):
+        if self.args.osd_id:
+            osd_is_running = systemctl.osd_is_active(self.args.osd_id)
+            if osd_is_running:
+                mlogger.error("OSD ID %s is running, stop it with:" % self.args.osd_id)
+                mlogger.error("systemctl stop ceph-osd@%s" % self.args.osd_id)
+                raise SystemExit("Unable to zap devices associated with OSD ID: %s" % self.args.osd_id)
+        devices = find_associated_devices(self.args.osd_id, self.args.osd_fsid)
+        self.zap(devices)
+
     def dmcrypt_close(self, dmcrypt_uuid):
         dmcrypt_path = "/dev/mapper/{}".format(dmcrypt_uuid)
         mlogger.info("Closing encrypted path %s", dmcrypt_path)
@@ -195,6 +282,14 @@ class Zap(object):
 
               ceph-volume lvm zap /dev/sda /dev/sdb /db/sdc
 
+          Zapping devices associated with an OSD ID:
+
+              ceph-volume lvm zap --osd-id 1
+
+            Optionally include the OSD FSID
+
+              ceph-volume lvm zap --osd-id 1 --osd-fsid 55BD4219-16A7-4037-BC20-0F158EFCC83D
+
         If the --destroy flag is given and you are zapping a raw device or partition
         then all vgs and lvs that exist on that raw device or partition will be destroyed.
 
@@ -223,14 +318,31 @@ class Zap(object):
             default=[],
             help='Path to one or many lv (as vg/lv), partition (as /dev/sda1) or device (as /dev/sda)'
         )
+
         parser.add_argument(
             '--destroy',
             action='store_true',
             default=False,
             help='Destroy all volume groups and logical volumes if you are zapping a raw device or partition',
         )
+
+        parser.add_argument(
+            '--osd-id',
+            help='Specify an OSD ID to detect associated devices for zapping',
+        )
+
+        parser.add_argument(
+            '--osd-fsid',
+            help='Specify an OSD FSID to detect associated devices for zapping',
+        )
+
         if len(self.argv) == 0:
             print(sub_command_help)
             return
+
         self.args = parser.parse_args(self.argv)
-        self.zap()
+
+        if self.args.osd_id or self.args.osd_fsid:
+            self.zap_osd()
+        else:
+            self.zap()