Source code for insights.parsers.lvdisplay

"""
LVDisplay - command ``/sbin/lvdisplay``
=======================================

The normal lvdisplay content looks like this::

  Adding lvsapp01ap01:0 as an user of lvsapp01ap01_mlog
  --- Volume group ---
  VG Name               vgp01app
  ...
  VG Size               399.98 GiB
  VG UUID               JVgCxE-UY84-C0Gk-8Cmn-UGXu-UHo0-9Qa4Re
  --- Logical volume ---
  global/lvdisplay_shows_full_device_path not found in config: defaulting to 0
  LV Path                /dev/vgp01app/lvsapp01ap01-old
  LV Name                lvsapp01ap01-old
  ...
  VG Name                vgp01app
  --- Logical volume ---
  global/lvdisplay_shows_full_device_path not found in config: defaulting to 0
  LV Path                /dev/vgp01app/lvsapp01ap02
  LV Name                lvsapp01ap02
  ...
  VG Name                vgp01app

The data is compiled into two keys in the ``data`` attribute:

* ``Logical volume``: a list of logical volume dictionaries.
* ``Volume group``: a list of volume group dictionaries.

The keys in each dictionary correspond to the headings found in the
output - for example, the keys in each ``Volume group`` list entry will
include ``VG Name``, ``VG Size``, etc.

In addition, the ``debug`` key in both the ``data`` attribute dictionary
and the ``Logical volume`` and ``Volume group`` dictionaries stores any
debug or warning messages found while parsing the output for that section.

Logical volumes are also available as a dictionary in the ``lvs`` property
and volume groups in the ``vgs`` property, both arranged by name.  Both
contain the same information as the associated list entry in the ``volumes``
dictionary.

Examples:

    >>> lvs = shared(LvDisplay)
    >>> 'volumes' in lvs # direct access via LegacyItemAccess
    True
    >>> 'debug' in lvs.data['volumes'] # access via data property
    True
    >>> for lv in lvs.data['volumes']['Logical volume']:
    ---     print lv['LV Name']
    ---
    lvsapp01ap01-old
    lvsapp01ap02
    >>> lvs.lvs['lvsapp01ap02']['VG Name'] # access to LVs by name
    'vgp01app'
    >>> lvs.vgs['vgp01app']['VG Size'] # access to VGs by name
    '399.98 GiB'

"""

from .. import parser, LegacyItemAccess, CommandParser
from collections import defaultdict
import re
from insights.specs import Specs


[docs] @parser(Specs.lvdisplay) class LvDisplay(CommandParser, LegacyItemAccess): """ Read the output of ``/sbin/lvdisplay``. Attributes: data(dict): The full data parsed from the output of lvdisplay. lvs(dict): A dictionary of logical volumes by name. vgs(dict): A dictionary of volume groups by name. """
[docs] def parse_content(self, content): self.data = {} segment = [] segment_type = '' self.data['debug'] = [] self.data['volumes'] = defaultdict(list) for line in content: split_line = line.split() if segment and len(split_line) >= 2 and split_line[0] == '---' and split_line[-1] == '---': self.add_segment(segment_type, segment) segment_type = " ".join(split_line[1:len(split_line) - 1]) segment = [] else: segment.append(line) if segment: # last segment self.add_segment(segment_type, segment) self.data['volumes'] = dict(self.data['volumes']) # Add lvs and vgs properties with dicts from the data collected if 'Volume group' in self.data['volumes']: self.vgs = {} for vg in self.data['volumes']['Volume group']: self.vgs[vg['VG Name']] = vg if 'Logical volume' in self.data['volumes']: self.lvs = {} for lv in self.data['volumes']['Logical volume']: self.lvs[lv['LV Name']] = lv
def add_segment(self, segment_type, segment): schema = () for line in segment: if line.lstrip().startswith('VG Name'): indexes = [(m.start(), m.end()) for m in re.finditer(r"\ +", line)] schema = (indexes[0][1], indexes[2][1]) break if not schema: self.data['debug'].extend(segment) else: self.data['volumes'][segment_type].append(self.parse_segment(segment, schema)) def parse_segment(self, lines, schema): segment = {} debug = [] for line in lines: name = line[schema[0]:schema[1]] if name.startswith(' '): debug.append(line[schema[0]:]) else: value = line[schema[1]:].strip() name = name.strip() if not name and not value: continue segment[name] = value segment['debug'] = debug return segment