diff options
Diffstat (limited to 'src/ceph-volume/ceph_volume/util')
-rw-r--r-- | src/ceph-volume/ceph_volume/util/arg_validators.py | 11 | ||||
-rw-r--r-- | src/ceph-volume/ceph_volume/util/device.py | 25 | ||||
-rw-r--r-- | src/ceph-volume/ceph_volume/util/disk.py | 89 | ||||
-rw-r--r-- | src/ceph-volume/ceph_volume/util/encryption.py | 27 |
4 files changed, 87 insertions, 65 deletions
diff --git a/src/ceph-volume/ceph_volume/util/arg_validators.py b/src/ceph-volume/ceph_volume/util/arg_validators.py index 1abb5165e..e936cab89 100644 --- a/src/ceph-volume/ceph_volume/util/arg_validators.py +++ b/src/ceph-volume/ceph_volume/util/arg_validators.py @@ -4,11 +4,20 @@ import math from ceph_volume import terminal, decorators, process from ceph_volume.util.device import Device from ceph_volume.util import disk - +from ceph_volume.util.encryption import set_dmcrypt_no_workqueue +from ceph_volume import process, conf def valid_osd_id(val): return str(int(val)) +class DmcryptAction(argparse._StoreTrueAction): + def __init__(self, *args, **kwargs): + super(DmcryptAction, self).__init__(*args, **kwargs) + + def __call__(self, *args, **kwargs): + set_dmcrypt_no_workqueue() + super(DmcryptAction, self).__call__(*args, **kwargs) + class ValidDevice(object): def __init__(self, as_string=False, gpt_ok=False): diff --git a/src/ceph-volume/ceph_volume/util/device.py b/src/ceph-volume/ceph_volume/util/device.py index d61222afe..1b52774d1 100644 --- a/src/ceph-volume/ceph_volume/util/device.py +++ b/src/ceph-volume/ceph_volume/util/device.py @@ -121,13 +121,8 @@ class Device(object): # check if we are not a device mapper if "dm-" not in real_path: self.path = real_path - if not sys_info.devices: - if self.path: - sys_info.devices = disk.get_devices(device=self.path) - else: - sys_info.devices = disk.get_devices() - if sys_info.devices.get(self.path, {}): - self.device_nodes = sys_info.devices[self.path]['device_nodes'] + if not sys_info.devices.get(self.path): + sys_info.devices = disk.get_devices() self.sys_api = sys_info.devices.get(self.path, {}) self.partitions = self._get_partitions() self.lv_api = None @@ -143,6 +138,8 @@ class Device(object): self._is_lvm_member = None self.ceph_device = False 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.available_lvm, self.rejected_reasons_lvm = self._check_lvm_reject_reasons() @@ -460,11 +457,11 @@ class Device(object): def device_type(self): self.load_blkid_api() if 'type' in self.sys_api: - return self.sys_api['type'] + return self.sys_api.get('type') elif self.disk_api: - return self.disk_api['TYPE'] + return self.disk_api.get('TYPE') elif self.blkid_api: - return self.blkid_api['TYPE'] + return self.blkid_api.get('TYPE') @property def is_mpath(self): @@ -478,9 +475,9 @@ class Device(object): def is_partition(self): self.load_blkid_api() if self.disk_api: - return self.disk_api['TYPE'] == 'part' + return self.disk_api.get('TYPE') == 'part' elif self.blkid_api: - return self.blkid_api['TYPE'] == 'part' + return self.blkid_api.get('TYPE') == 'part' return False @property @@ -594,8 +591,8 @@ class Device(object): def _check_generic_reject_reasons(self): reasons = [ - ('removable', 1, 'removable'), - ('ro', 1, 'read-only'), + ('id_bus', 'usb', 'id_bus'), + ('ro', '1', 'read-only'), ] rejected = [reason for (k, v, reason) in reasons if self.sys_api.get(k, '') == v] diff --git a/src/ceph-volume/ceph_volume/util/disk.py b/src/ceph-volume/ceph_volume/util/disk.py index ee061b724..2984c391d 100644 --- a/src/ceph-volume/ceph_volume/util/disk.py +++ b/src/ceph-volume/ceph_volume/util/disk.py @@ -6,6 +6,7 @@ import time from ceph_volume import process from ceph_volume.api import lvm from ceph_volume.util.system import get_file_contents +from typing import Dict, List, Any logger = logging.getLogger(__name__) @@ -364,30 +365,18 @@ def is_device(dev): return TYPE in ['disk', 'mpath'] # 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 """ if not os.path.exists(dev): return False - # use lsblk first, fall back to using stat - TYPE = lsblk(dev).get('TYPE') - if TYPE: - return TYPE == 'part' - - # fallback to stat - stat_obj = os.stat(dev) - 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 + partitions = get_partitions() + return dev.split("/")[-1] in partitions def is_ceph_rbd(dev): @@ -763,36 +752,34 @@ class AllowLoopDevices(object): allow_loop_devices = AllowLoopDevices() -def get_block_devs_sysfs(_sys_block_path='/sys/block', _sys_dev_block_path='/sys/dev/block', device=''): - def holder_inner_loop(): +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() -> bool: for holder in holders: # /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': return True # First, get devices that are _not_ partitions - result = list() + result: List[List[str]] = list() if not device: - dev_names = os.listdir(_sys_block_path) + dev_names: List[str] = os.listdir(_sys_block_path) else: dev_names = [device] 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): continue - type_ = 'disk' - holders = os.listdir(os.path.join(_sys_block_path, dev, 'holders')) - if get_file_contents(os.path.join(_sys_block_path, dev, 'removable')) == "1": - continue + type_: str = 'disk' + holders: List[str] = os.listdir(os.path.join(_sys_block_path, dev, 'holders')) if holder_inner_loop(): 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): - dm_type = get_file_contents(os.path.join(dm_dir_path, 'uuid')) - type_ = dm_type.split('-')[0].lower() - basename = get_file_contents(os.path.join(dm_dir_path, 'name')) - name = os.path.join("/dev/mapper", basename) + dm_type: str = get_file_contents(os.path.join(dm_dir_path, 'uuid')) + type_: List[str] = dm_type.split('-')[0].lower() + basename: str = get_file_contents(os.path.join(dm_dir_path, 'name')) + name: str = os.path.join("/dev/mapper", basename) if dev.startswith('loop'): if not allow_loop_devices(): continue @@ -800,28 +787,25 @@ 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')): continue type_ = 'loop' - result.append([kname, name, type_]) + result.append([kname, name, type_, pname]) # Next, look for devices that _are_ partitions - for item in os.listdir(_sys_dev_block_path): - is_part = get_file_contents(os.path.join(_sys_dev_block_path, item, 'partition')) == "1" - dev = os.path.basename(os.readlink(os.path.join(_sys_dev_block_path, item))) - if not is_part: - continue - name = kname = os.path.join("/dev", dev) - result.append([name, kname, "part"]) + partitions: Dict[str, str] = get_partitions() + for partition in partitions.keys(): + name = kname = os.path.join("/dev", partition) + result.append([name, kname, "part", partitions[partition]]) return sorted(result, key=lambda x: x[0]) -def get_partitions(_sys_dev_block_path ='/sys/dev/block'): - devices = os.listdir(_sys_dev_block_path) - result = dict() +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 = os.path.join(_sys_dev_block_path, device) - is_partition = get_file_contents(os.path.join(device_path, 'partition')) == "1" + 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 = os.path.basename(os.readlink(device_path)) - parent_device_sys_name = os.readlink(device_path).split('/')[-2:-1][0] + 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 @@ -839,13 +823,13 @@ def get_devices(_sys_block_path='/sys/block', device=''): device_facts = {} block_devs = get_block_devs_sysfs(_sys_block_path) - partitions = get_partitions() block_types = ['disk', 'mpath', 'lvm', 'part'] if allow_loop_devices(): block_types.append('loop') for block in block_devs: + metadata: Dict[str, Any] = {} if block[2] == 'lvm': block[1] = lvm.get_lv_path_from_mapper(block[1]) devname = os.path.basename(block[0]) @@ -854,8 +838,7 @@ def get_devices(_sys_block_path='/sys/block', device=''): continue sysdir = os.path.join(_sys_block_path, devname) if block[2] == 'part': - sysdir = os.path.join(_sys_block_path, partitions[devname], devname) - metadata = {} + sysdir = os.path.join(_sys_block_path, block[3], devname) # If the device is ceph rbd it gets excluded if is_ceph_rbd(diskname): @@ -890,7 +873,7 @@ def get_devices(_sys_block_path='/sys/block', device=''): metadata['device_nodes'] = ','.join(device_slaves) else: if block[2] == 'part': - metadata['device_nodes'] = partitions[devname] + metadata['device_nodes'] = block[3] else: metadata['device_nodes'] = devname @@ -920,7 +903,13 @@ def get_devices(_sys_block_path='/sys/block', device=''): metadata['size'] = float(size) * 512 metadata['human_readable_size'] = human_readable_size(metadata['size']) metadata['path'] = diskname + metadata['devname'] = devname metadata['type'] = block[2] + metadata['parent'] = block[3] + + # some facts from udevadm + p = udevadm_property(sysdir) + metadata['id_bus'] = p.get('ID_BUS', '') device_facts[diskname] = metadata return device_facts diff --git a/src/ceph-volume/ceph_volume/util/encryption.py b/src/ceph-volume/ceph_volume/util/encryption.py index f8aea80b4..844a81620 100644 --- a/src/ceph-volume/ceph_volume/util/encryption.py +++ b/src/ceph-volume/ceph_volume/util/encryption.py @@ -6,10 +6,28 @@ from ceph_volume.util import constants, system from ceph_volume.util.device import Device from .prepare import write_keyring from .disk import lsblk, device_family, get_part_entry_type +from packaging import version logger = logging.getLogger(__name__) mlogger = terminal.MultiLogger(__name__) +def set_dmcrypt_no_workqueue(target_version: str = '2.3.4') -> None: + """ + set `conf.dmcrypt_no_workqueue` to `True` if the available + version of `cryptsetup` is greater or equal to `version` + """ + command = ["cryptsetup", "--version"] + out, err, rc = process.call(command) + try: + if version.parse(out[0]) >= version.parse(f'cryptsetup {target_version}'): + conf.dmcrypt_no_workqueue = True + except IndexError: + mlogger.debug(f'cryptsetup version check: rc={rc} out={out} err={err}') + raise RuntimeError("Couldn't check the cryptsetup version.") + +def bypass_workqueue(device: str) -> bool: + return not Device(device).rotational and conf.dmcrypt_no_workqueue + def get_key_size_from_conf(): """ Return the osd dmcrypt key size from config file. @@ -79,6 +97,10 @@ def plain_open(key, device, mapping): '--key-size', '256', ] + if bypass_workqueue(device): + command.extend(['--perf-no_read_workqueue', + '--perf-no_write_workqueue']) + process.call(command, stdin=key, terminal_verbose=True, show_command=True) @@ -103,6 +125,11 @@ def luks_open(key, device, mapping): device, mapping, ] + + if bypass_workqueue(device): + command.extend(['--perf-no_read_workqueue', + '--perf-no_write_workqueue']) + process.call(command, stdin=key, terminal_verbose=True, show_command=True) |