def get_partitions_facts(sys_block_path): partition_metadata = {} for folder in os.listdir(sys_block_path): folder_path = os.path.join(sys_block_path, folder) if os.path.exists(os.path.join(folder_path, 'partition')): contents = get_file_contents(os.path.join(folder_path, 'partition')) if contents: part = {} partname = folder part_sys_block_path = os.path.join(sys_block_path, partname) part['start'] = get_file_contents(part_sys_block_path + "/start", 0) part['sectors'] = get_file_contents(part_sys_block_path + "/size", 0) part['sectorsize'] = get_file_contents( part_sys_block_path + "/queue/logical_block_size") if not part['sectorsize']: part['sectorsize'] = get_file_contents( part_sys_block_path + "/queue/hw_sector_size", 512) part['size'] = float(part['sectors']) * 512 part['human_readable_size'] = human_readable_size(float(part['sectors']) * 512) part['holders'] = [] for holder in os.listdir(part_sys_block_path + '/holders'): part['holders'].append(holder) partition_metadata[partname] = part return partition_metadata
def get_partitions_facts(sys_block_path): partition_metadata = {} for folder in os.listdir(sys_block_path): folder_path = os.path.join(sys_block_path, folder) if os.path.exists(os.path.join(folder_path, 'partition')): contents = get_file_contents(os.path.join(folder_path, 'partition')) if contents: part = {} partname = folder part_sys_block_path = os.path.join(sys_block_path, partname) part['start'] = get_file_contents(part_sys_block_path + "/start", 0) part['sectors'] = get_file_contents(part_sys_block_path + "/size", 0) part['sectorsize'] = get_file_contents( part_sys_block_path + "/queue/logical_block_size") if not part['sectorsize']: part['sectorsize'] = get_file_contents( part_sys_block_path + "/queue/hw_sector_size", 512) part['size'] = human_readable_size(float(part['sectors']) * 512) part['holders'] = [] for holder in os.listdir(part_sys_block_path + '/holders'): part['holders'].append(holder) partition_metadata[partname] = part return partition_metadata
def get_block_devs_sysfs(_sys_block_path='/sys/block', _sys_dev_block_path='/sys/dev/block'): def holder_inner_loop(): 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() if holder_dm_type == 'mpath': return True # First, get devices that are _not_ partitions result = list() dev_names = os.listdir(_sys_block_path) for dev in dev_names: name = kname = 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 if holder_inner_loop(): continue dm_dir_path = 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) if dev.startswith('loop'): if not allow_loop_devices(): continue # Skip loop devices that are not attached if not os.path.exists(os.path.join(_sys_block_path, dev, 'loop')): continue type_ = 'loop' result.append([kname, name, type_]) # 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"]) return sorted(result, key=lambda x: x[0])
def holder_inner_loop(): 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() if holder_dm_type == 'mpath': return True
def test_exception_returns_default(self): with patch('builtins.open') as mocked_open: mocked_open.side_effect = Exception() result = system.get_file_contents('/tmp/fake-file') assert result == ''
def test_path_has_multiline_contents(self, fake_filesystem): interesting_file = fake_filesystem.create_file('/tmp/fake-file', contents="0\n1") result = system.get_file_contents(interesting_file.path) assert result == "0\n1"
def test_path_does_not_exist(self, tmpdir): filepath = os.path.join(str(tmpdir), 'doesnotexist') assert system.get_file_contents(filepath, 'default') == 'default'
def test_exception_returns_default(self, tmpfile): interesting_file = tmpfile(contents="0") # remove read, causes IOError os.chmod(interesting_file, 0o000) result = system.get_file_contents(interesting_file) assert result == ''
def test_path_has_multiline_contents(self, tmpfile): interesting_file = tmpfile(contents="0\n1") result = system.get_file_contents(interesting_file) assert result == "0\n1"
def get_devices(_sys_block_path='/sys/block'): """ Captures all available block devices as reported by lsblk. Additional interesting metadata like sectors, size, vendor, solid/rotational, etc. is collected from /sys/block/<device> Returns a dictionary, where keys are the full paths to devices. ..note:: loop devices, removable media, and logical volumes are never included. """ device_facts = {} block_devs = get_block_devs_lsblk() for block in block_devs: devname = os.path.basename(block[0]) diskname = block[1] if block[2] not in ['disk', 'mpath']: continue sysdir = os.path.join(_sys_block_path, devname) metadata = {} # If the mapper device is a logical volume it gets excluded if is_mapper_device(diskname): if lvm.get_device_lvs(diskname): continue # all facts that have no defaults # (<name>, <path relative to _sys_block_path>) facts = [('removable', 'removable'), ('ro', 'ro'), ('vendor', 'device/vendor'), ('model', 'device/model'), ('rev', 'device/rev'), ('sas_address', 'device/sas_address'), ('sas_device_handle', 'device/sas_device_handle'), ('support_discard', 'queue/discard_granularity'), ('rotational', 'queue/rotational'), ('nr_requests', 'queue/nr_requests'), ] for key, file_ in facts: metadata[key] = get_file_contents(os.path.join(sysdir, file_)) metadata['scheduler_mode'] = "" scheduler = get_file_contents(sysdir + "/queue/scheduler") if scheduler is not None: m = re.match(r".*?(\[(.*)\])", scheduler) if m: metadata['scheduler_mode'] = m.group(2) metadata['partitions'] = get_partitions_facts(sysdir) size = get_file_contents(os.path.join(sysdir, 'size'), 0) metadata['sectors'] = get_file_contents(os.path.join(sysdir, 'sectors'), 0) fallback_sectorsize = get_file_contents(sysdir + "/queue/hw_sector_size", 512) metadata['sectorsize'] = get_file_contents(sysdir + "/queue/logical_block_size", fallback_sectorsize) metadata['size'] = float(size) * 512 metadata['human_readable_size'] = human_readable_size(metadata['size']) metadata['path'] = diskname metadata['locked'] = is_locked_raw_device(metadata['path']) device_facts[diskname] = metadata return device_facts
def get_devices(_sys_block_path='/sys/block', _dev_path='/dev', _mapper_path='/dev/mapper'): """ Captures all available devices from /sys/block/, including its partitions, along with interesting metadata like sectors, size, vendor, solid/rotational, etc... Returns a dictionary, where keys are the full paths to devices. ..note:: dmapper devices get their path updated to what they link from, if /dev/dm-0 is linked by /dev/mapper/ceph-data, then the latter gets used as the key. ..note:: loop devices, removable media, and logical volumes are never included. """ # Portions of this detection process are inspired by some of the fact # gathering done by Ansible in module_utils/facts/hardware/linux.py. The # processing of metadata and final outcome *is very different* and fully # imcompatible. There are ignored devices, and paths get resolved depending # on dm devices, loop, and removable media device_facts = {} block_devs = get_block_devs(_sys_block_path) dev_devs = get_dev_devs(_dev_path) mapper_devs = get_mapper_devs(_mapper_path) for block in block_devs: sysdir = os.path.join(_sys_block_path, block) metadata = {} # Ensure that the diskname is an absolute path and that it never points # to a /dev/dm-* device diskname = mapper_devs.get(block) or dev_devs.get(block) if not diskname: continue # If the mapper device is a logical volume it gets excluded if is_mapper_device(diskname): if lvm.is_lv(diskname): continue metadata['removable'] = get_file_contents( os.path.join(sysdir, 'removable')) # Is the device read-only ? metadata['ro'] = get_file_contents(os.path.join(sysdir, 'ro')) for key in [ 'vendor', 'model', 'rev', 'sas_address', 'sas_device_handle' ]: metadata[key] = get_file_contents(sysdir + "/device/" + key) for key in ['sectors', 'size']: metadata[key] = get_file_contents(os.path.join(sysdir, key), 0) for key, _file in [('support_discard', '/queue/discard_granularity')]: metadata[key] = get_file_contents(os.path.join(sysdir, _file)) metadata['partitions'] = get_partitions_facts(sysdir) for key in ['rotational', 'nr_requests']: metadata[key] = get_file_contents(sysdir + "/queue/" + key) metadata['scheduler_mode'] = "" scheduler = get_file_contents(sysdir + "/queue/scheduler") if scheduler is not None: m = re.match(r".*?(\[(.*)\])", scheduler) if m: metadata['scheduler_mode'] = m.group(2) if not metadata['sectors']: metadata['sectors'] = 0 size = metadata['sectors'] or metadata['size'] metadata['sectorsize'] = get_file_contents(sysdir + "/queue/logical_block_size") if not metadata['sectorsize']: metadata['sectorsize'] = get_file_contents( sysdir + "/queue/hw_sector_size", 512) metadata['human_readable_size'] = human_readable_size( float(size) * 512) metadata['size'] = float(size) * 512 metadata['path'] = diskname metadata['locked'] = is_locked_raw_device(metadata['path']) device_facts[diskname] = metadata return device_facts
def get_devices(_sys_block_path='/sys/block', _dev_path='/dev', _mapper_path='/dev/mapper'): """ Captures all available devices from /sys/block/, including its partitions, along with interesting metadata like sectors, size, vendor, solid/rotational, etc... Returns a dictionary, where keys are the full paths to devices. ..note:: dmapper devices get their path updated to what they link from, if /dev/dm-0 is linked by /dev/mapper/ceph-data, then the latter gets used as the key. ..note:: loop devices, removable media, and logical volumes are never included. """ # Portions of this detection process are inspired by some of the fact # gathering done by Ansible in module_utils/facts/hardware/linux.py. The # processing of metadata and final outcome *is very different* and fully # imcompatible. There are ignored devices, and paths get resolved depending # on dm devices, loop, and removable media device_facts = {} block_devs = get_block_devs(_sys_block_path) dev_devs = get_dev_devs(_dev_path) mapper_devs = get_mapper_devs(_mapper_path) for block in block_devs: sysdir = os.path.join(_sys_block_path, block) metadata = {} # Ensure that the diskname is an absolute path and that it never points # to a /dev/dm-* device diskname = mapper_devs.get(block) or dev_devs.get(block) if not diskname: continue # If the mapper device is a logical volume it gets excluded if is_mapper_device(diskname): if lvm.is_lv(diskname): continue metadata['removable'] = get_file_contents(os.path.join(sysdir, 'removable')) # Is the device read-only ? metadata['ro'] = get_file_contents(os.path.join(sysdir, 'ro')) for key in ['vendor', 'model', 'rev', 'sas_address', 'sas_device_handle']: metadata[key] = get_file_contents(sysdir + "/device/" + key) for key in ['sectors', 'size']: metadata[key] = get_file_contents(os.path.join(sysdir, key), 0) for key, _file in [('support_discard', '/queue/discard_granularity')]: metadata[key] = get_file_contents(os.path.join(sysdir, _file)) metadata['partitions'] = get_partitions_facts(sysdir) for key in ['rotational', 'nr_requests']: metadata[key] = get_file_contents(sysdir + "/queue/" + key) metadata['scheduler_mode'] = "" scheduler = get_file_contents(sysdir + "/queue/scheduler") if scheduler is not None: m = re.match(r".*?(\[(.*)\])", scheduler) if m: metadata['scheduler_mode'] = m.group(2) if not metadata['sectors']: metadata['sectors'] = 0 size = metadata['sectors'] or metadata['size'] metadata['sectorsize'] = get_file_contents(sysdir + "/queue/logical_block_size") if not metadata['sectorsize']: metadata['sectorsize'] = get_file_contents(sysdir + "/queue/hw_sector_size", 512) metadata['human_readable_size'] = human_readable_size(float(size) * 512) metadata['size'] = float(size) * 512 metadata['path'] = diskname metadata['locked'] = is_locked_raw_device(metadata['path']) for part_name, part_metadata in metadata['partitions'].items(): part_abspath = '/dev/%s' % part_name device_facts[part_abspath] = part_metadata device_facts[diskname] = metadata return device_facts