Source code for insights.parsers.ls

"""
LS Parsers - command ``ls``
===========================

Parsers provided in this module includes:

LSla - command ``ls -la <dirs>``
--------------------------------

LSlaFiltered - command ``ls -la <dirs> | grep -F <keywords>``
-------------------------------------------------------------

LSlan - command ``ls -lan <dirs>``
----------------------------------

LSlanFiltered - command ``ls -lan <dirs> | grep -F <keywords>``
---------------------------------------------------------------

LSlanL - command ``ls -lanL <dirs>``
------------------------------------

LSlanR - command ``ls -lanR <dirs>``
------------------------------------

LSlanRL - command ``ls -lanRL <dirs>``
--------------------------------------

LSlaRZ - command ``ls -lanRZ <dirs>``
-------------------------------------

LSlaZ - command ``ls -lanZ <dirs>``
-----------------------------------
"""
from insights.core import ls_parser, Parser
from insights.core.filters import add_filter
from insights.core.plugins import parser
from insights.specs import Specs
from insights.util.file_permissions import FilePermissions

# Required basic filters for `LS` specs that the content needs to be filtered
add_filter(Specs.ls_la_filtered, ['total '])
add_filter(Specs.ls_lan_filtered, ['total '])

# Required directories to collect for `LSlanR` specs, to:
# 1. keep compatible with sosreport archives
# 2. Ensure that the related applications to work properly:
#    - archive data extraction  (cee-data-engineering)
#    - insights-facts  (cee-data-engineering)
add_filter(Specs.ls_lanR_dirs, ['/boot', '/dev', '/sys/firmware'])


[docs] class FileListing(Parser, dict): """ Reads a series of concatenated directory listings and turns them into a dictionary of entities by name. Stores all the information for each directory entry for every entry that can be parsed, containing:: - type (one of [bcdlps-]) - permission string including ACL character - number of links - owner and group (as given in the listing) - size, or major and minor number for block and character devices - date (in the format given in the listing) - name - name of linked file, if a symlink In addition, the raw line is always stored, even if the line doesn't look like a directory entry. Also provides a number of other conveniences, such as:: - lists of regular and special files and subdirectory names for each directory, in the order found in the listing - total blocks allocated to all the entities in this directory Parses the SELinux information if present in the listing. SELinux directory listings contain:: - the type of file - the permissions block - the owner and group as given in the directory listing - the SELinux user, role, type and MLS - the name, and link destination if it's a symlink .. note:: The :class:`FileListing` Parser parses the content collected by diffirent ``ls_*`` specs. The ``ls_*`` specs collect the corresponding ``ls`` command output according to the filters defined by the relevant ``ls_*_dirs`` specs. For the ``ls_*_dirs`` specs, only absolute directory path is acceptable, path to file or relative path is not acceptable. For details, see the following example. Sample output:: /boot: total 187380 dr-xr-xr-x. 3 0 0 4096 Mar 4 16:19 . dr-xr-xr-x. 19 0 0 4096 Jul 14 09:10 .. -rw-r--r--. 1 0 0 123891 Aug 25 2015 config-3.10.0-229.14.1.el7.x86_64 /etc/sysconfig: total 96 drwxr-xr-x. 7 0 0 4096 Jul 6 23:41 . drwxr-xr-x. 77 0 0 8192 Jul 13 03:55 .. drwxr-xr-x. 2 0 0 41 Jul 6 23:32 cbq drwxr-xr-x. 2 0 0 6 Sep 16 2015 console -rw-------. 1 0 0 1390 Mar 4 2014 ebtables-config -rw-r--r--. 1 0 0 72 Sep 15 2015 firewalld lrwxrwxrwx. 1 0 0 17 Jul 6 23:32 grub -> /etc/default/grub Examples: >>> from insights.core.filters import add_filter >>> from insights.specs import Specs >>> add_filter(Specs.ls_lan_dirs, ['/boot', '/etc/sysconfig']) >>> type(ls_lan) <class 'insights.parsers.ls.FileListing'> >>> "/etc" in ls_lan False >>> "/etc/sysconfig" in ls_lan True >>> len(ls_lan.files_of('/etc/sysconfig')) 3 >>> ls_lan.files_of("/etc/sysconfig") ['ebtables-config', 'firewalld', 'grub'] >>> ls_lan.dirs_of("/etc/sysconfig") ['.', '..', 'cbq', 'console'] >>> ls_lan.specials_of("/etc/sysconfig") [] >>> ls_lan.total_of("/etc/sysconfig") 96 >>> ls_lan.dir_entry('/etc/sysconfig', 'grub') == {'group': '0', 'name': 'grub', 'links': 1, 'perms': 'rwxrwxrwx.', 'raw_entry': 'lrwxrwxrwx. 1 0 0 17 Jul 6 23:32 grub -> /etc/default/grub', 'owner': '0', 'link': '/etc/default/grub', 'date': 'Jul 6 23:32', 'type': 'l', 'dir': '/etc/sysconfig', 'size': 17} True >>> sorted(ls_lan.listing_of("/etc/sysconfig").keys()) == sorted(['console', 'grub', '..', 'firewalld', '.', 'cbq', 'ebtables-config']) True >>> sorted(ls_lan.listing_of("/etc/sysconfig")['console'].keys()) == sorted(['group', 'name', 'links', 'perms', 'raw_entry', 'owner', 'date', 'type', 'dir', 'size']) True >>> ls_lan.listing_of("/etc/sysconfig")['console']['type'] 'd' >>> ls_lan.listing_of("/etc/sysconfig")['console']['perms'] 'rwxr-xr-x.' >>> ls_lan.dir_contains("/etc/sysconfig", "console") True >>> ls_lan.dir_entry("/etc/sysconfig", "console") == {'group': '0', 'name': 'console', 'links': 2, 'perms': 'rwxr-xr-x.', 'raw_entry': 'drwxr-xr-x. 2 0 0 6 Sep 16 2015 console', 'owner': '0', 'date': 'Sep 16 2015', 'type': 'd', 'dir': '/etc/sysconfig', 'size': 6} True >>> ls_lan.dir_entry("/etc/sysconfig", "grub")['type'] 'l' >>> ls_lan.dir_entry("/etc/sysconfig", "grub")['link'] '/etc/default/grub' >>> "/boot" in ls_lan True >>> ls_lan.files_of('/boot') ['config-3.10.0-229.14.1.el7.x86_64'] >>> fp = ls_lan.permissions_of('/boot', 'config-3.10.0-229.14.1.el7.x86_64') >>> fp.owner '0' >>> fp.group '0' >>> fp.perms_owner 'rw-' """ __root_path = None """ The root path of the dir when there is only one list target. It only works for the following specs/parsers that are compatible for sos-archives. - :class:`insights.parsers.ls_boot.LsBoot` - :class:`insights.parsers.ls_dev.LsDev` - :class:`insights.parsers.ls_sys_firmware.LsSysFirmware` None by default, for the new ```ls_*``` datasource specs """
[docs] def parse_content(self, content): """ Called automatically to process the directory listing(s) contained in the content. """ self.update(ls_parser.parse(content, self.__root_path))
[docs] def files_of(self, directory): """ The list of non-special files (i.e. not block or character files) in the given directory. """ if directory in self: return self[directory]['files'] return []
[docs] def dirs_of(self, directory): """ The list of subdirectories in the given directory. """ if directory in self: return self[directory]['dirs'] return []
[docs] def specials_of(self, directory): """ The list of block and character special files in the given directory. """ if directory in self: return self[directory]['specials'] return []
[docs] def total_of(self, directory): """ The total blocks of storage consumed by entries in this directory. """ if directory in self: return self[directory]['total'] return 0
[docs] def listing_of(self, directory): """ The listing of this directory, in a dictionary by entry name. All entries contain the original line as is in the 'raw_entry' key. Entries that can be parsed then have fields as described in the class description above. """ if directory in self: return self[directory]['entries'] return []
[docs] def dir_contains(self, directory, name): """ Does this directory contain this entry name? """ if directory in self: return name in self[directory]['entries'] return False
[docs] def dir_entry(self, directory, name): """ The parsed data for the given entry name in the given directory. """ if directory in self: return self[directory]['entries'][name] return {}
[docs] def path_entry(self, path): """ The parsed data given a path, which is separated into its directory and entry name. """ if path[0] != '/': return None path_parts = path.split('/') # Note that here the first element will be '' because it's before the # first separator. That's OK, the join puts it back together. directory = '/'.join(path_parts[:-1]) if directory not in self: return None name = path_parts[-1] if name not in self[directory]['entries']: return None return self[directory]['entries'][name]
[docs] def permissions_of(self, directory, target): """ Returns a FilePermissions object, if found. Parameters: directory(string): Full path without trailing slash where to search. target (string): Name of the directory or file to get FilePermissions for. Returns: FilePermissions: If found or None if not found. """ if directory in self: d = self[directory]['entries'] if target in d: return FilePermissions(d[target]['raw_entry'])
[docs] @parser(Specs.ls_la) class LSla(FileListing): """ Parses output of ``ls -la <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_la_filtered) class LSlaFiltered(FileListing): """ Parses output of ``ls -la <dirs> | grep -F <keywords>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_lan) class LSlan(FileListing): """ Parses output of ``ls -lan <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_lan_filtered) class LSlanFiltered(FileListing): """ Parses output of ``ls -lan <dirs> | grep -F <keywords>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_lanL) class LSlanL(FileListing): """ Parses output of ``ls -lanR <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_lanR) class LSlanR(FileListing): """ Parses output of ``ls -lanR <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_lanRL) class LSlanRL(FileListing): """ Parses output of ``ls -lanRL <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_laRZ) class LSlaRZ(FileListing): """ Parses output of ``ls -laRZ <dirs>`` command. See :py:class:`FileListing` for more information. """ pass
[docs] @parser(Specs.ls_laZ) class LSlaZ(FileListing): """ Parses output of ``ls -laZ <dirs>`` command. See :py:class:`FileListing` for more information. """ pass