Source code for insights.parsers.multipath_v4_ll

"""
MultipathDevices - command ``multipath -v4 -ll``
================================================

This function converts the output of the ``multipath -v4 -ll`` command and
stores the data around each multipath device given.

Examples:
    >>> type(mpaths)
    <class 'insights.parsers.multipath_v4_ll.MultipathDevices'>
    >>> len(mpaths)  # Can treat the object as a list to iterate through
    3
    >>> mpaths[0]['alias']
    'mpathg'
    >>> mpaths[0]['size']
    '54T'
    >>> mpaths[0]['dm_name']
    'dm-2'
    >>> mpaths[0]['wwid']
    '36f01faf000da360b0000033c528fea6d'
    >>> groups = mpaths[0]['path_group']  # List of path groups for this device
    >>> groups[0]['status']
    'active'
    >>> len(groups[0]['path'])
    4
    >>> path0 = groups[0]['path'][0]  # Each path group has an array of paths
    >>> path0[1]  # Paths are stored as a list of items
    'sdc'
    >>> path0[-1]
    'running'
    >>> mpaths.dms  # List of device names found
    ['dm-2', 'dm-4', 'dm-5']
    >>> mpaths.by_dm['dm-2']['alias']  # Access by device name
    'mpathg'
    >>> mpaths.aliases  # Aliases found (again, in order)
    ['mpathg', 'mpathe']
    >>> mpaths.by_alias['mpathg']['dm_name']  # Access by alias
    'dm-2'
    >>> mpaths.by_wwid['36f01faf000da360b0000033c528fea6d']['dm_name']
    'dm-2'
"""

import re
import shlex
from insights import parser, CommandParser
from insights.specs import Specs


[docs] @parser(Specs.multipath__v4__ll) class MultipathDevices(CommandParser): """ ``multipath_-v4_ll`` command output Example input:: ===== paths list ===== uuid hcil dev dev_t pri dm_st chk_st vend/prod/rev dev_st 0:0:0:0 sda 8:0 -1 undef ready VMware,Virtual disk running 3:0:0:1 sdb 8:16 -1 undef ready IET,VIRTUAL-DISK running 4:0:0:1 sdc 8:32 -1 undef ready IET,VIRTUAL-DISK running Oct 28 14:02:44 | *word = 0, len = 1 Oct 28 14:02:44 | *word = E, len = 1 Oct 28 14:02:44 | *word = 1, len = 1 Oct 28 14:02:44 | *word = 0, len = 1 Oct 28 14:02:44 | *word = A, len = 1 Oct 28 14:02:44 | *word = 0, len = 1 mpathg (36f01faf000da360b0000033c528fea6d) dm-2 DELL,MD36xxi size=54T features='3 queue_if_no_path pg_init_retries 50' hwhandler='1 rdac' wp=rw |-+- policy='round-robin 0' prio=0 status=active | |- 12:0:0:1 sdc 8:32 active ready running | |- 11:0:0:1 sdi 8:128 active ready running | |- 15:0:0:1 sdo 8:224 active ready running | `- 17:0:0:1 sdv 65:80 active ready running `-+- policy='round-robin 0' prio=0 status=enabled |- 13:0:0:1 sdf 8:80 active ready running |- 14:0:0:1 sdl 8:176 active ready running |- 16:0:0:1 sdr 65:16 active ready running `- 18:0:0:1 sdx 65:112 active ready running mpathe (36f01faf000da3761000004323aa6fbce) dm-4 DELL,MD36xxi size=54T features='3 queue_if_no_path pg_init_retries 55' hwhandler='1 rdac' wp=rw |-+- policy='round-robin 0' prio=0 status=active | |- 13:0:0:2 sdg 8:96 active faulty running | |- 14:0:0:2 sdm 8:192 active faulty running | |- 16:0:0:2 sds 65:32 active faulty running | `- 18:0:0:2 sdy 65:128 active faulty running `-+- policy='round-robin 0' prio=0 status=enabled |- 12:0:0:2 sdd 8:48 active faulty running |- 11:0:0:2 sdj 8:144 active faulty running |- 15:0:0:2 sdp 8:240 active faulty running `- 17:0:0:2 sdw 65:96 active faulty running 36001405b1629f80d52a4c898f8856e43 dm-5 LIO-ORG ,block0_sdb size=2.0G features='0' hwhandler='0' wp=rw |-+- policy='service-time 0' prio=1 status=active | `- 3:0:0:0 sdc 8:32 active ready running `-+- policy='service-time 0' prio=1 status=enabled `- 4:0:0:0 sdb 8:16 active ready running Example data structure produced:: devices = [ { "alias": "mpathg", "wwid": "36f01faf000da360b0000033c528fea6d", "dm_name": "dm-2", "venprod": "DELL,MD36xxi", "size": "54T", "features": "3 queue_if_no_path pg_init_retries 50", "hwhandler": "1 rdac", "wp": "rw", "path_group": [ { "policy": "round-robin 0", "prio": "0" "status": "active" "path": [ ['12:0:0:1', 'sdc', '8:32', 'active', 'ready', 'running'], ['11:0:0:1', 'sdi', '8:128', 'active', 'ready', 'running'], ['15:0:0:1', 'sdo', '8:224', 'active', 'ready', 'running'], ['17:0:0:1', 'sdv', '65:80', 'active', 'ready', 'running'] ] }, { "policy": "round-robin 0", "prio": "0" "status": "enabled" "path": [ ['13:0:0:1', 'sdf', '8:80', 'active', 'ready', 'running'], ['14:0:0:1', 'sdl', '8:176', 'active', 'ready', 'running'], ['16:0:0:1', 'sdr', '65:16', 'active', 'ready', 'running'], ['18:0:0:1', 'sdx', '65:112','active', 'ready', 'running'] ] } ] },... ] raw_info_lines = [ "===== paths list =====", "uuid hcil dev dev_t pri dm_st chk_st vend/prod/rev dev_st", " 0:0:0:0 sda 8:0 -1 undef ready VMware,Virtual disk running", " 3:0:0:1 sdb 8:16 -1 undef ready IET,VIRTUAL-DISK running", " 4:0:0:1 sdc 8:32 -1 undef ready IET,VIRTUAL-DISK running", "Oct 28 14:02:44 | *word = 0, len = 1", ... ] Attributes: devices (list): List of devices found, in order dms (list): Device mapper names of each device, in order found aliases (list): Alias of each device, in order found wwids (list): World Wide ID by_dm (dict): Access to each device by device mapper name by_alias (dict): Access to each device by alias by_wwid (dict): Access to each device by World Wide ID raw_info_lines(list): List of raw info lines found, in order """
[docs] def parse_content(self, content): self.devices = [] self.raw_info_lines = [] mpath_dev_all = [] mpath_dev = {} path_info = [] path_group = [] path_group_attr = {} MPATH_WWID_REG = re.compile(r'\(?([A-Za-z0-9_\s]+)\)?\s+dm-') PROPERTY_SQBRKT_REG = re.compile(r"\[(?P<key>\w+)=(?P<value>[^\]]+)\]") PATHGROUP_POLICY_STR = \ r"(?:policy=')?(?P<policy>(?:round-robin|queue-length|service-time) \d)" + \ r"(?:' | \[)prio=(?P<priority>\d+)(?:\]\[| status=)" + \ r"(?P<status>\w+)(?:\]|)" PATHGROUP_POLICY_REG = re.compile(PATHGROUP_POLICY_STR) HCTL_REG = re.compile(r'(?:[`|]-(?:\+-)?|\\_) (\d+:){3}\d+') for line in content: m = MPATH_WWID_REG.search(line) if m: # Save previous path group info if we have any: # Now that we've got a valid path, append the group data if we # haven't already if path_info: path_group_attr['path'] = path_info path_group.append(path_group_attr) # Must reset path group info to not carry on into new device path_group_attr = {} path_info = [] mpath_dev['path_group'] = path_group mpath_dev_all.append(mpath_dev) mpath_dev = {} path_group = [] wwid = m.group(1) no_alias = line.startswith(wwid) (dm, venprod) = re.findall(r".*(dm-\S+)\s+(.*)", line)[0] if not no_alias: (dm, venprod) = re.findall(r"\w+\s+\(.*\)\s+(dm-\S+)\s+(.*)", line)[0] mpath_dev['alias'] = line.split()[0] mpath_dev['wwid'] = wwid mpath_dev['dm_name'] = dm mpath_dev['venprod'] = venprod elif 'size=' in line: if '][' in line: # Old RHEL 5 format: for (k, v) in PROPERTY_SQBRKT_REG.findall(line): mpath_dev[k] = v # Handle un-named write policy attribute on the end: mpath_dev['wp'] = line[-3:-1] else: # Newer RHEL 6 format: attr_line = shlex.split(line) for item in attr_line: (k, v) = item.split('=', 1) mpath_dev[k] = v elif PATHGROUP_POLICY_REG.search(line): m = PATHGROUP_POLICY_REG.search(line) # New path info - save the previous if we have one: if path_info: path_group_attr['path'] = path_info path_group.append(path_group_attr) path_group_attr = {} path_info = [] path_group_attr['policy'] = m.group('policy') path_group_attr['prio'] = m.group('priority') path_group_attr['status'] = m.group('status') elif HCTL_REG.search(line): colon_index = line.index(":") # Dodgy hack to convert RHEL 5 attributes in square brackets into # spaced out words to combine into the list line = line.replace('[', ' ').replace(']', ' ') path_info.append(line[colon_index - 2:].split()) else: self.raw_info_lines.append(line) # final save of outstanding path and path group data: if path_info: path_group_attr['path'] = path_info path_group.append(path_group_attr) if path_group: mpath_dev['path_group'] = path_group mpath_dev_all.append(mpath_dev) self.devices = mpath_dev_all # Create some extra accessor properties self.dms = [path['dm_name'] for path in self.devices if 'dm_name' in path] self.by_dm = dict((path['dm_name'], path) for path in self.devices if 'dm_name' in path) self.aliases = [path['alias'] for path in self.devices if 'alias' in path] self.by_alias = dict((path['alias'], path) for path in self.devices if 'alias' in path) self.wwids = [path['wwid'] for path in self.devices if 'wwid' in path] self.by_wwid = dict((path['wwid'], path) for path in self.devices if 'wwid' in path)
def __len__(self): """ The length of the devices list """ return len(self.devices) def __iter__(self): """ Iterate through the devices list """ for device in self.devices: yield device def __getitem__(self, idx): """ Fetch a device by index in devices list """ return self.devices[idx]