Source code for insights.parsers.vgdisplay

"""
VgDisplay - command ``vgdisplay``
=================================

"""

from .. import parser, CommandParser

import re
from insights.specs import Specs


[docs] @parser(Specs.vgdisplay) class VgDisplay(CommandParser): """ Parse the output of the ``vgdisplay -vv`` or ``vgdisplay`` commands. The ``vg_list`` property is the main access to the list of volume groups in the command output. Each volume group is stored as a dictionary of keys and values drawn from the property list of the volume group. The volume group's logical and physical volumes are stored in the 'Logical Volumes' and 'Physical Volumes' sub-keys, respectively. Sample command output of ``vgdisplay -vv`` (pruned for clarity):: Couldn't find device with uuid VVLmw8-e2AA-ECfW-wDPl-Vnaa-0wW1-utv7tV. --- Volume group --- VG Name RHEL7CSB System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 13 ... --- Logical volume --- LV Path /dev/RHEL7CSB/Root LV Name Root VG Name RHEL7CSB LV Size 29.30 GiB ... --- Physical volumes --- PV Name /dev/mapper/luks-96c66446-77fd-4431-9508-f6912bd84194 PV UUID EfWV9V-03CX-E6zc-JkMw-yQae-wdzp-Je1KUn PV Status allocatable Total PE / Free PE 118466 / 4036 Volume groups are kept in the ``vg_list`` property in the order they were found in the file. Lines containing 'Couldn't find device with uuid' and 'missing physical volume' are stored in a ``debug_info`` property. Examples: >>> vg_info = shared[VgDisplay] >>> len(vg_info.vg_list) 1 >>> vgdata = vg_info.vg_list[0] >>> vgdata['VG Name'] 'RHEL7CSB' >>> vgdata['VG Size'] '462.76 GiB' >>> 'Logical Volumes' in vgdata True >>> lvs = vgdata['Logical Volumes'] >>> type(lvs) dict >>> lvs.keys() # Note - keyed by device name ['/dev/RHEL7CSB/Root'] >>> lvs['/dev/RHEL7CSB/Root']['LV Name'] 'Root' >>> lvs['/dev/RHEL7CSB/Root']['LV Size'] '29.30 GiB' >>> 'Physical Volumes' in vgdata True >>> vgdata['Physical Volumes'].keys() ['/dev/mapper/luks-96c66446-77fd-4431-9508-f6912bd84194'] >>> vgdata['Physical Volumes']['/dev/mapper/luks-96c66446-77fd-4431-9508-f6912bd84194']['PV UUID'] 'EfWV9V-03CX-E6zc-JkMw-yQae-wdzp-Je1KUn' >>> vg_info.debug_info ["Couldn't find device with uuid VVLmw8-e2AA-ECfW-wDPl-Vnaa-0wW1-utv7tV."] """ _FILTER_INFO = [ "Couldn't find device with uuid", "physical volumes missing", ]
[docs] def parse_content(self, content): self.vg_list = [] self.debug_info = [] # Each section starts with a '(VG|LV|PV) Name' header. This then # sets the amount of space between the start of the key and the start # of the value. Unfortunately, there may be only one space between # the key and the value and there are spaces in the key, so it's # impossible to tell where the key stops and the value ends on space # alone. However, the header sets the left-most column the value # starts at, so once we pick up the header we ignore the regex match # and get the key and value as substrings. header_re = re.compile(r'^(?P<key>VG Name|LV Path|PV Name)\s+(?P<val>\S.*)$') # To save different handling, we use this to refer to the current # dictionary we're storing data in, whether it be a VG, LV or PV. current_data_store = None value_start_column = 0 # Each section of key-value data starts with the header as above and # ends with a blank line. This prevents parsing of random error # and information messages as key-value pairs. in_keyval_section = False for line in content: line = line.strip() if any(debug in line for debug in self._FILTER_INFO): if line not in self.debug_info: self.debug_info.append(line) in_keyval_section = False match = header_re.match(line) # Headers mark the start of a keyval section, but they do match # inside, so only match if outside a keyval section. if not in_keyval_section and match: in_keyval_section = True key, value = match.group('key', 'val') # Determine column for start of value - remember, this string # is now stripped so this may look different from your examples value_start_column = line.index(value) if key == "VG Name": # New Volume Group - new vg_info_dict entry self.vg_list.append({ # Logical and Physical volumes stored by name / device 'Logical Volumes': {}, 'Physical Volumes': {}, 'VG Name': value, }) current_data_store = self.vg_list[-1] elif key == 'LV Path': # New Logical Volume - append to 'Logical Volumes' current_data_store = { key: value, } self.vg_list[-1]['Logical Volumes'][value] = current_data_store else: # elif key == 'PV Name': # New Physical Volume - append to 'Physical Volumes' current_data_store = { key: value, } self.vg_list[-1]['Physical Volumes'][value] = current_data_store elif line == '': # Blank line = new section, stop expecting keys and values in_keyval_section = False elif in_keyval_section and len(line) > value_start_column: # Extract key and value by substring key = line[:value_start_column].strip() value = line[value_start_column:].strip() # Finally, add this key/val pair to the current data store. current_data_store[key] = value