update to v18.2.1 with staged reef backport

This commit is contained in:
Nic Anderson
2024-02-01 23:44:22 -05:00
parent cea4914262
commit bd7e78cf47
3 changed files with 97 additions and 87 deletions

View File

@@ -1,4 +1,4 @@
FROM quay.io/ceph/ceph:v17.2.5 FROM quay.io/ceph/ceph:v18.2.1
LABEL org.opencontainers.image.source https://github.com/nanderson94/ceph-patch LABEL org.opencontainers.image.source https://github.com/nanderson94/ceph-patch

View File

@@ -33,20 +33,30 @@ class Devices(object):
A container for Device instances with reporting A container for Device instances with reporting
""" """
def __init__(self, filter_for_batch=False, with_lsm=False): def __init__(self,
filter_for_batch=False,
with_lsm=False,
list_all=False):
lvs = lvm.get_lvs() lvs = lvm.get_lvs()
lsblk_all = disk.lsblk_all() lsblk_all = disk.lsblk_all()
all_devices_vgs = lvm.get_all_devices_vgs() all_devices_vgs = lvm.get_all_devices_vgs()
if not sys_info.devices: if not sys_info.devices:
sys_info.devices = disk.get_devices() sys_info.devices = disk.get_devices()
self.devices = [Device(k, self._devices = [Device(k,
with_lsm, with_lsm,
lvs=lvs, lvs=lvs,
lsblk_all=lsblk_all, lsblk_all=lsblk_all,
all_devices_vgs=all_devices_vgs) for k in all_devices_vgs=all_devices_vgs) for k in
sys_info.devices.keys()] sys_info.devices.keys()]
if filter_for_batch: self.devices = []
self.devices = [d for d in self.devices if d.available_lvm_batch] for device in self._devices:
if filter_for_batch and not device.available_lvm_batch:
continue
if device.is_lv and not list_all:
continue
if device.is_partition and not list_all:
continue
self.devices.append(device)
def pretty_report(self): def pretty_report(self):
output = [ output = [
@@ -111,13 +121,8 @@ class Device(object):
# check if we are not a device mapper # check if we are not a device mapper
if "dm-" not in real_path: if "dm-" not in real_path:
self.path = real_path self.path = real_path
if not sys_info.devices: if not sys_info.devices.get(self.path):
if self.path:
sys_info.devices = disk.get_devices(device=self.path)
else:
sys_info.devices = disk.get_devices() sys_info.devices = disk.get_devices()
if sys_info.devices.get(self.path, {}):
self.device_nodes = sys_info.devices[self.path]['device_nodes']
self.sys_api = sys_info.devices.get(self.path, {}) self.sys_api = sys_info.devices.get(self.path, {})
self.partitions = self._get_partitions() self.partitions = self._get_partitions()
self.lv_api = None self.lv_api = None
@@ -133,6 +138,8 @@ class Device(object):
self._is_lvm_member = None self._is_lvm_member = None
self.ceph_device = False self.ceph_device = False
self._parse() self._parse()
if self.path in sys_info.devices.keys():
self.device_nodes = sys_info.devices[self.path]['device_nodes']
self.lsm_data = self.fetch_lsm(with_lsm) self.lsm_data = self.fetch_lsm(with_lsm)
self.available_lvm, self.rejected_reasons_lvm = self._check_lvm_reject_reasons() self.available_lvm, self.rejected_reasons_lvm = self._check_lvm_reject_reasons()
@@ -230,7 +237,7 @@ class Device(object):
self.disk_api = dev self.disk_api = dev
device_type = dev.get('TYPE', '') device_type = dev.get('TYPE', '')
# always check is this is an lvm member # always check is this is an lvm member
valid_types = ['part', 'disk'] valid_types = ['part', 'disk', 'mpath']
if allow_loop_devices(): if allow_loop_devices():
valid_types.append('loop') valid_types.append('loop')
if device_type in valid_types: if device_type in valid_types:
@@ -490,7 +497,7 @@ class Device(object):
@property @property
def is_acceptable_device(self): def is_acceptable_device(self):
return self.is_device or self.is_partition return self.is_device or self.is_partition or self.is_lv
@property @property
def is_encrypted(self): def is_encrypted(self):
@@ -528,6 +535,15 @@ class Device(object):
if lv.tags.get("ceph.type") in ["data", "block"]] if lv.tags.get("ceph.type") in ["data", "block"]]
return any(osd_ids) return any(osd_ids)
@property
def journal_used_by_ceph(self):
# similar to used_by_ceph() above. This is for 'journal' devices (db/wal/..)
# needed by get_lvm_fast_allocs() in devices/lvm/batch.py
# see https://tracker.ceph.com/issues/59640
osd_ids = [lv.tags.get("ceph.osd_id") is not None for lv in self.lvs
if lv.tags.get("ceph.type") in ["db", "wal"]]
return any(osd_ids)
@property @property
def vg_free_percent(self): def vg_free_percent(self):
if self.vgs: if self.vgs:
@@ -577,7 +593,6 @@ class Device(object):
reasons = [ reasons = [
('id_bus', 'usb', 'id_bus'), ('id_bus', 'usb', 'id_bus'),
('ro', '1', 'read-only'), ('ro', '1', 'read-only'),
('locked', 1, 'locked'),
] ]
rejected = [reason for (k, v, reason) in reasons if rejected = [reason for (k, v, reason) in reasons if
self.sys_api.get(k, '') == v] self.sys_api.get(k, '') == v]
@@ -613,6 +628,8 @@ class Device(object):
rejected.append('Has GPT headers') rejected.append('Has GPT headers')
if self.has_partitions: if self.has_partitions:
rejected.append('Has partitions') rejected.append('Has partitions')
if self.has_fs:
rejected.append('Has a FileSystem')
return rejected return rejected
def _check_lvm_reject_reasons(self): def _check_lvm_reject_reasons(self):

View File

@@ -6,6 +6,7 @@ import time
from ceph_volume import process from ceph_volume import process
from ceph_volume.api import lvm from ceph_volume.api import lvm
from ceph_volume.util.system import get_file_contents from ceph_volume.util.system import get_file_contents
from typing import Dict, List
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -238,11 +239,14 @@ def _udevadm_info(device):
def lsblk(device, columns=None, abspath=False): def lsblk(device, columns=None, abspath=False):
result = []
if not os.path.isdir(device):
result = lsblk_all(device=device, result = lsblk_all(device=device,
columns=columns, columns=columns,
abspath=abspath) abspath=abspath)
if not result: if not result:
raise RuntimeError(f"{device} not found is lsblk report") logger.debug(f"{device} not found is lsblk report")
return {}
return result[0] return result[0]
@@ -356,31 +360,23 @@ def is_device(dev):
if not allow_loop_devices(): if not allow_loop_devices():
return False return False
TYPE = lsblk(dev).get('TYPE')
if TYPE:
return TYPE in ['disk', 'mpath']
# fallback to stat # fallback to stat
return _stat_is_device(os.lstat(dev).st_mode) return _stat_is_device(os.lstat(dev).st_mode) and not is_partition(dev)
def is_partition(dev): def is_partition(dev: str) -> bool:
""" """
Boolean to determine if a given device is a partition, like /dev/sda1 Boolean to determine if a given device is a partition, like /dev/sda1
""" """
if not os.path.exists(dev): if not os.path.exists(dev):
return False return False
# use lsblk first, fall back to using stat
TYPE = lsblk(dev).get('TYPE')
if TYPE:
return TYPE == 'part'
# fallback to stat partitions = get_partitions()
stat_obj = os.stat(dev) return dev.split("/")[-1] in partitions
if _stat_is_device(stat_obj.st_mode):
return False
major = os.major(stat_obj.st_rdev)
minor = os.minor(stat_obj.st_rdev)
if os.path.exists('/sys/dev/block/%d:%d/partition' % (major, minor)):
return True
return False
def is_ceph_rbd(dev): def is_ceph_rbd(dev):
@@ -731,28 +727,6 @@ def is_mapper_device(device_name):
return device_name.startswith(('/dev/mapper', '/dev/dm-')) return device_name.startswith(('/dev/mapper', '/dev/dm-'))
def is_locked_raw_device(disk_path):
"""
A device can be locked by a third party software like a database.
To detect that case, the device is opened in Read/Write and exclusive mode
"""
open_flags = (os.O_RDWR | os.O_EXCL)
open_mode = 0
fd = None
try:
fd = os.open(disk_path, open_flags, open_mode)
except OSError:
return 1
try:
os.close(fd)
except OSError:
return 1
return 0
class AllowLoopDevices(object): class AllowLoopDevices(object):
allow = False allow = False
warned = False warned = False
@@ -778,34 +752,34 @@ class AllowLoopDevices(object):
allow_loop_devices = AllowLoopDevices() allow_loop_devices = AllowLoopDevices()
def get_block_devs_sysfs(_sys_block_path='/sys/block', _sys_dev_block_path='/sys/dev/block', device=''): def get_block_devs_sysfs(_sys_block_path: str = '/sys/block', _sys_dev_block_path: str = '/sys/dev/block', device: str = '') -> List[List[str]]:
def holder_inner_loop(): def holder_inner_loop() -> bool:
for holder in holders: for holder in holders:
# /sys/block/sdy/holders/dm-8/dm/uuid # /sys/block/sdy/holders/dm-8/dm/uuid
holder_dm_type = get_file_contents(os.path.join(_sys_block_path, dev, f'holders/{holder}/dm/uuid')).split('-')[0].lower() holder_dm_type: str = get_file_contents(os.path.join(_sys_block_path, dev, f'holders/{holder}/dm/uuid')).split('-')[0].lower()
if holder_dm_type == 'mpath': if holder_dm_type == 'mpath':
return True return True
# First, get devices that are _not_ partitions # First, get devices that are _not_ partitions
result = list() result: List[List[str]] = list()
if not device: if not device:
dev_names = os.listdir(_sys_block_path) dev_names: List[str] = os.listdir(_sys_block_path)
else: else:
dev_names = [device] dev_names = [device]
for dev in dev_names: for dev in dev_names:
name = kname = os.path.join("/dev", dev) name = kname = pname = os.path.join("/dev", dev)
if not os.path.exists(name): if not os.path.exists(name):
continue continue
type_ = 'disk' type_: str = 'disk'
holders = os.listdir(os.path.join(_sys_block_path, dev, 'holders')) holders: List[str] = os.listdir(os.path.join(_sys_block_path, dev, 'holders'))
if holder_inner_loop(): if holder_inner_loop():
continue continue
dm_dir_path = os.path.join(_sys_block_path, dev, 'dm') dm_dir_path: str = os.path.join(_sys_block_path, dev, 'dm')
if os.path.isdir(dm_dir_path): if os.path.isdir(dm_dir_path):
dm_type = get_file_contents(os.path.join(dm_dir_path, 'uuid')) dm_type: str = get_file_contents(os.path.join(dm_dir_path, 'uuid'))
type_ = dm_type.split('-')[0].lower() type_: List[str] = dm_type.split('-')[0].lower()
basename = get_file_contents(os.path.join(dm_dir_path, 'name')) basename: str = get_file_contents(os.path.join(dm_dir_path, 'name'))
name = os.path.join("/dev/mapper", basename) name: str = os.path.join("/dev/mapper", basename)
if dev.startswith('loop'): if dev.startswith('loop'):
if not allow_loop_devices(): if not allow_loop_devices():
continue continue
@@ -813,17 +787,27 @@ def get_block_devs_sysfs(_sys_block_path='/sys/block', _sys_dev_block_path='/sys
if not os.path.exists(os.path.join(_sys_block_path, dev, 'loop')): if not os.path.exists(os.path.join(_sys_block_path, dev, 'loop')):
continue continue
type_ = 'loop' type_ = 'loop'
result.append([kname, name, type_]) result.append([kname, name, type_, pname])
# Next, look for devices that _are_ partitions # Next, look for devices that _are_ partitions
for item in os.listdir(_sys_dev_block_path): partitions: Dict[str, str] = get_partitions()
is_part = get_file_contents(os.path.join(_sys_dev_block_path, item, 'partition')) == "1" for partition in partitions.keys():
dev = os.path.basename(os.readlink(os.path.join(_sys_dev_block_path, item))) name = kname = os.path.join("/dev", partition)
if not is_part: result.append([name, kname, "part", partitions[partition]])
continue
name = kname = os.path.join("/dev", dev)
result.append([name, kname, "part"])
return sorted(result, key=lambda x: x[0]) return sorted(result, key=lambda x: x[0])
def get_partitions(_sys_dev_block_path ='/sys/dev/block') -> List[str]:
devices: List[str] = os.listdir(_sys_dev_block_path)
result: Dict[str, str] = dict()
for device in devices:
device_path: str = os.path.join(_sys_dev_block_path, device)
is_partition: bool = int(get_file_contents(os.path.join(device_path, 'partition'), '0')) > 0
if not is_partition:
continue
partition_sys_name: str = os.path.basename(os.path.realpath(device_path))
parent_device_sys_name: str = os.path.realpath(device_path).split('/')[-2:-1][0]
result[partition_sys_name] = parent_device_sys_name
return result
def get_devices(_sys_block_path='/sys/block', device=''): def get_devices(_sys_block_path='/sys/block', device=''):
""" """
@@ -840,16 +824,20 @@ def get_devices(_sys_block_path='/sys/block', device=''):
block_devs = get_block_devs_sysfs(_sys_block_path) block_devs = get_block_devs_sysfs(_sys_block_path)
block_types = ['disk', 'mpath'] block_types = ['disk', 'mpath', 'lvm', 'part']
if allow_loop_devices(): if allow_loop_devices():
block_types.append('loop') block_types.append('loop')
for block in block_devs: for block in block_devs:
if block[2] == 'lvm':
block[1] = lvm.get_lv_path_from_mapper(block[1])
devname = os.path.basename(block[0]) devname = os.path.basename(block[0])
diskname = block[1] diskname = block[1]
if block[2] not in block_types: if block[2] not in block_types:
continue continue
sysdir = os.path.join(_sys_block_path, devname) sysdir = os.path.join(_sys_block_path, devname)
if block[2] == 'part':
sysdir = os.path.join(_sys_block_path, block[3], devname)
metadata = {} metadata = {}
# If the device is ceph rbd it gets excluded # If the device is ceph rbd it gets excluded
@@ -877,9 +865,15 @@ def get_devices(_sys_block_path='/sys/block', device=''):
for key, file_ in facts: for key, file_ in facts:
metadata[key] = get_file_contents(os.path.join(sysdir, file_)) metadata[key] = get_file_contents(os.path.join(sysdir, file_))
if block[2] != 'part':
device_slaves = os.listdir(os.path.join(sysdir, 'slaves')) device_slaves = os.listdir(os.path.join(sysdir, 'slaves'))
metadata['partitions'] = get_partitions_facts(sysdir)
if device_slaves: if device_slaves:
metadata['device_nodes'] = ','.join(device_slaves) metadata['device_nodes'] = ','.join(device_slaves)
else:
if block[2] == 'part':
metadata['device_nodes'] = block[3]
else: else:
metadata['device_nodes'] = devname metadata['device_nodes'] = devname
@@ -909,7 +903,6 @@ def get_devices(_sys_block_path='/sys/block', device=''):
metadata['size'] = float(size) * 512 metadata['size'] = float(size) * 512
metadata['human_readable_size'] = human_readable_size(metadata['size']) metadata['human_readable_size'] = human_readable_size(metadata['size'])
metadata['path'] = diskname metadata['path'] = diskname
metadata['locked'] = is_locked_raw_device(metadata['path'])
metadata['type'] = block[2] metadata['type'] = block[2]
# some facts from udevadm # some facts from udevadm