def probe(context=None, report=False): """Initiate an mdadm assemble to awaken existing MDADM devices. For each md block device, extract required information needed to describe the array for recreation or reuse as needed. mdadm tooling provides information about the raid type, the members, the size, the name, uuids, metadata version. """ mdadm_assemble() # ignore passed context, must read udev after assembling mdadm devices context = pyudev.Context() raids = {} for device in context.list_devices(subsystem='block'): if 'MD_NAME' in device: devname = device['DEVNAME'] attrs = udev_get_attributes(device) attrs['size'] = str(read_sys_block_size(devname)) devices, spares = get_mdadm_array_members(devname, device) cfg = dict(device) cfg.update({'raidlevel': device['MD_LEVEL'], 'devices': devices, 'spare_devices': spares}) raids[devname] = cfg return raids
def probe(self): storage = {} for device in self.context.list_devices(subsystem='block'): if device['MAJOR'] not in ["1", "7"]: attrs = udev_get_attributes(device) # update the size attr as it may only be the number # of blocks rather than size in bytes. attrs['size'] = \ str(self._get_device_size(device['DEVNAME'])) storage[device['DEVNAME']] = dict(device) storage[device['DEVNAME']].update({'attrs': attrs}) self.results = storage return storage
def link_change(self, action, data): log.debug('link_change %s %s', action, data) for k, v in data.items(): if isinstance(v, bytes): data[k] = v.decode('utf-8', 'replace') ifindex = data['ifindex'] if action == 'DEL': if ifindex in self._links: del self._links[ifindex] self.receiver.del_link(ifindex) return if action == 'CHANGE': if ifindex in self._links: dev = self._links[ifindex] # Trigger a scan when a wlan device goes up # Not sure if this is required as devices seem to scan as soon # as they go up? (in which case this fails with EBUSY, so it's # just spam in the logs). if dev.type == 'wlan': if (not (dev.flags & IFF_UP)) and (data['flags'] & IFF_UP): try: self.trigger_scan(ifindex) except RuntimeError: log.exception('on-up trigger_scan failed') dev.netlink_data = data # If a device appears and is immediately renamed, the # initial _compute_type can fail to find the sysfs # directory. Have another go now. if dev.type is None: dev.type = _compute_type(dev.name) dev.bond = _get_bonding(dev.name, dev.netlink_data['flags']) self.receiver.update_link(ifindex) return udev_devices = list(self.context.list_devices(IFINDEX=str(ifindex))) if len(udev_devices) == 0: # Has disappeared already? return udev_device = udev_devices[0] udev_data = dict(udev_device) udev_data['attrs'] = udev_get_attributes(udev_device) link = Link.from_probe_data(data, udev_data) self._links[ifindex] = link self.receiver.new_link(ifindex, link)
def blockdev_probe(context=None): """ Non-class method for extracting relevant block devices from pyudev.Context(). """ def _extract_partition_table(devname): cmd = ['sfdisk', '--bytes', '--json', devname] try: result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) output = result.stdout.decode('utf-8') except subprocess.CalledProcessError as e: log.error('Failed to probe partition table on %s:%s', devname, e) return None if not output: return None ptable = {} try: ptable = json.loads(output) except json.decoder.JSONDecodeError: log.exception('Failed to load sfdisk json output:') return ptable if not context: context = pyudev.Context() blockdev = {} for device in sane_block_devices(context): if device['MAJOR'] not in ["1", "7"]: attrs = udev_get_attributes(device) # update the size attr as it may only be the number # of blocks rather than size in bytes. attrs['size'] = \ str(read_sys_block_size_bytes(device['DEVNAME'])) blockdev[device['DEVNAME']] = dict(device) blockdev[device['DEVNAME']].update({'attrs': attrs}) # include partition table info if present ptable = _extract_partition_table(device['DEVNAME']) if ptable: blockdev[device['DEVNAME']].update(ptable) return blockdev
def link_change(self, action, data): log.debug('link_change %s %s', action, data) for k, v in data.items(): if isinstance(data, bytes): data[k] = data.decode('utf-8', 'replace') ifindex = data['ifindex'] if action == 'DEL': if ifindex in self.links: del self.links[ifindex] self.del_link(ifindex) return if action == 'CHANGE': if ifindex in self.links: dev = self.links[ifindex] # Trigger a scan when a wlan device goes up # Not sure if this is required as devices seem to scan as soon # as they go up? (in which case this fails with EBUSY, so it's # just spam in the logs). if dev.type == 'wlan' and (not (dev.flags & IFF_UP)) and ( data['flags'] & IFF_UP): try: self.wlan_listener.trigger_scan(ifindex) except RuntimeError: log.exception('on-up trigger_scan failed') dev.update_from_netlink_data(data) self.update_link(ifindex) return udev_devices = list(self.context.list_devices(IFINDEX=str(ifindex))) if len(udev_devices) == 0: # Has disappeared already? return udev_device = udev_devices[0] udev_data = dict(udev_device) udev_data['attrs'] = udev_get_attributes(udev_device) link = NetworkInfo(data, udev_data) self.links[data['ifindex']] = link self.new_link(ifindex, link)