From: Alfredo Deza Date: Thu, 6 Dec 2018 15:54:11 +0000 (-0500) Subject: ceph-volume lvm.zap initial take on zapping by OSD ID, FSID X-Git-Tag: v12.2.11~10^2~7 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d853b99db7e6bf03fc82136342952989820dd668;p=ceph.git ceph-volume lvm.zap initial take on zapping by OSD ID, FSID Signed-off-by: Alfredo Deza (cherry picked from commit 59f6cec6dd0687a2528f75a518bd0d4617c27fe0) --- diff --git a/src/ceph-volume/ceph_volume/devices/lvm/zap.py b/src/ceph-volume/ceph_volume/devices/lvm/zap.py index a77ac5f907ae..fbd784b63faa 100644 --- a/src/ceph-volume/ceph_volume/devices/lvm/zap.py +++ b/src/ceph-volume/ceph_volume/devices/lvm/zap.py @@ -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()