def is_mpath_partition(devpath, info=None): """ Check if a device is a multipath partition, returns boolean. """ result = False if devpath.startswith('/dev/dm-'): if not info: info = udev.udevadm_info(devpath) if 'DM_PART' in udev.udevadm_info(devpath): result = True LOG.debug("%s is multipath device partition? %s", devpath, result) return result
def mpath_partition_to_mpath_id(devpath): """ Return the mpath id of a multipath partition. """ info = udev.udevadm_info(devpath) if 'DM_MPATH' in info: return info['DM_MPATH'] return None
def test_udevadm_info_escape_quotes(self, m_subp): """verify we escape quotes when we fail to split. """ mypath = '/dev/sdz' datafile = 'tests/data/udevadm_info_sandisk_cruzer.txt' m_subp.return_value = (util.load_file(datafile), "") info = udevadm_info(mypath) m_subp.assert_called_with( ['udevadm', 'info', '--query=property', '--export', mypath], capture=True) """ Replicate what udevadm_info parsing does and use pdb to examine what's happening. (Pdb) original_value "SanDisk'" (Pdb) quoted_value '\'SanDisk\'"\'"\'\'' (Pdb) split_value ["SanDisk'"] (Pdb) expected_value "SanDisk'" """ original_value = "SanDisk'" quoted_value = shlex_quote(original_value) split_value = shlex.split(quoted_value) expected_value = split_value if ' ' in split_value else split_value[0] self.assertEqual(expected_value, info['SCSI_VENDOR']) self.assertEqual(expected_value, info['SCSI_VENDOR_ENC'])
def lookup_disk(serial): """ Search for a disk by its serial number using /dev/disk/by-id/ """ # Get all volumes in /dev/disk/by-id/ containing the serial string. The # string specified can be either in the short or long serial format # hack, some serials have spaces, udev usually converts ' ' -> '_' serial_udev = serial.replace(' ', '_') LOG.info('Processing serial %s via udev to %s', serial, serial_udev) disks = list( filter(lambda x: serial_udev in x, os.listdir("/dev/disk/by-id/"))) if not disks or len(disks) < 1: raise ValueError("no disk with serial '%s' found" % serial_udev) # Sort by length and take the shortest path name, as the longer path names # will be the partitions on the disk. Then use os.path.realpath to # determine the path to the block device in /dev/ disks.sort(key=lambda x: len(x)) LOG.debug('lookup_disks found: %s', disks) path = os.path.realpath("/dev/disk/by-id/%s" % disks[0]) # /dev/dm-X if multipath.is_mpath_device(path): info = udevadm_info(path) path = os.path.join('/dev/mapper', info['DM_NAME']) # /dev/sdX elif multipath.is_mpath_member(path): mp_name = multipath.find_mpath_id_by_path(path) path = os.path.join('/dev/mapper', mp_name) if not os.path.exists(path): raise ValueError("path '%s' to block device for disk with serial '%s' \ does not exist" % (path, serial_udev)) LOG.debug('block.lookup_disk() returning path %s', path) return path
def _device_is_multipathed(devpath): devpath = os.path.realpath(devpath) info = udevadm_info(devpath) if multipath.is_mpath_device(devpath, info=info): return True if multipath.is_mpath_partition(devpath, info=info): return True if devpath.startswith('/dev/dm-'): # check members of composed devices (LVM, dm-crypt) if 'DM_LV_NAME' in info: volgroup = info.get('DM_VG_NAME') if volgroup: if any((multipath.is_mpath_member(pv) for pv in lvm.get_pvols_in_volgroup(volgroup))): return True elif devpath.startswith('/dev/md'): if any((multipath.is_mpath_member(md) for md in md_get_devices_list(devpath) + md_get_spares_list(devpath))): return True result = multipath.is_mpath_member(devpath) return result
def is_mpath_partition(devpath): if devpath.startswith('/dev/dm-'): if 'DM_PART' in udev.udevadm_info(devpath): LOG.debug("%s is multipath device partition", devpath) return True return False
def mpath_partition_to_mpath_id_and_partnumber(devpath): """ Return the mpath id and partition number of a multipath partition. """ info = udev.udevadm_info(devpath) if 'DM_MPATH' in info and 'DM_PART' in info: return info['DM_MPATH'], info['DM_PART'] return None
def test_udevadm_info(self, m_subp): """ udevadm_info returns dictionary for specified device """ mypath = '/dev/nvme0n1' m_subp.return_value = (UDEVADM_INFO_QUERY, "") info = udev.udevadm_info(mypath) m_subp.assert_called_with( ['udevadm', 'info', '--query=property', mypath], capture=True) self.assertEqual(sorted(INFO_DICT), sorted(info))
def is_mpath_device(devpath, info=None): """ Check if devpath is a multipath device, returns boolean. """ result = False if not info: info = udev.udevadm_info(devpath) if info.get('DM_UUID', '').startswith('mpath-'): result = True LOG.debug('%s is multipath device? %s', devpath, result) return result
def get_mpath_id_from_device(device): # /dev/dm-X if is_mpath_device(device) or is_mpath_partition(device): info = udev.udevadm_info(device) return info.get('DM_NAME') # /dev/sdX if is_mpath_member(device): return find_mpath_id_by_path(device) return None
def test_udevadm_info_multiple_equals(self, m_subp): """ udevadm_info handles parsing values with multiple '=' chars. """ mypath = '/dev/nvme0n1' m_subp.return_value = ("SCSI_IDENT_TARGET_VENDOR='clusterid=92901'", "") info = udevadm_info(mypath) m_subp.assert_called_with( ['udevadm', 'info', '--query=property', '--export', mypath], capture=True) self.assertEqual({'SCSI_IDENT_TARGET_VENDOR': 'clusterid=92901'}, info)
def is_mpath_member(devpath, info=None): """ Check if a device is a multipath member (a path), returns boolean. """ result = False if not info: info = udev.udevadm_info(devpath) if info.get("DM_MULTIPATH_DEVICE_PATH") == "1": result = True LOG.debug('%s is multipath device member? %s', devpath, result) return result
def get_device_mapper_links(devpath, first=False): """ Return the best devlink to device at devpath. """ info = udevadm_info(devpath) if 'DEVLINKS' not in info: raise ValueError('Device %s does not have device symlinks' % devpath) devlinks = [devlink for devlink in sorted(info['DEVLINKS']) if devlink] if not devlinks: raise ValueError('Unexpected DEVLINKS list contained empty values') if first: return devlinks[0] return devlinks
def is_mpath_device(devpath): info = udev.udevadm_info(devpath) if info.get('DM_UUID', '').startswith('mpath-'): return True return False
def mpath_partition_to_mpath_id(devpath): info = udev.udevadm_info(devpath) if 'DM_MPATH' in info: return info['DM_MPATH'] return None
def find_mpath_id(devpath): """ Return the mpath_id associated with a specified device path. """ info = udev.udevadm_info(devpath) return info.get('DM_NAME')
def test_udevadm_info_path_not_exists(self, m_subp): """ udevadm_info raises ProcessExecutionError for invalid path value""" mypath = self.random_string() m_subp.side_effect = util.ProcessExecutionError() with self.assertRaises(util.ProcessExecutionError): udevadm_info(mypath)
def test_udevadm_info_no_path(self): """ udevadm_info raises ValueError for invalid path value""" mypath = None with self.assertRaises(ValueError): udevadm_info(mypath)