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__)
])
+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.'
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))
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)
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.
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()