From f2d443462d05a2642676cd1d9e546e08168a7e1a Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Fri, 20 Dec 2024 17:45:41 +0100 Subject: [PATCH] Extending Ansible module ds389_plugins_info.py --- lib/ansible/ds389_plugins_info.py | 239 ++++++++++++++++++++++++------ plugins/filter/filter.py | 8 +- 2 files changed, 201 insertions(+), 46 deletions(-) diff --git a/lib/ansible/ds389_plugins_info.py b/lib/ansible/ds389_plugins_info.py index 1b7bbff..c036741 100644 --- a/lib/ansible/ds389_plugins_info.py +++ b/lib/ansible/ds389_plugins_info.py @@ -55,8 +55,6 @@ config: # Standard modules import re -import warnings -from subprocess import CalledProcessError from subprocess import run # Third party modules @@ -98,6 +96,8 @@ class Ds389PluginsInfo(object): self.get_memberof() self.get_referint() + self.get_root_dn_access() + self.get_account_policy() return self.result @@ -126,10 +126,8 @@ class Ds389PluginsInfo(object): [self.cmd, self.instance, 'plugin', 'memberof', 'show'], capture_output=True, encoding=self.encoding) if proc.stderr: - warnings.warn(proc.stderr) - try: - proc.check_returncode() - except CalledProcessError: + module.warn(proc.stderr) + if proc.returncode: return re_attr = re.compile(r'^memberOfAttr:\s+(.*)', re.IGNORECASE) @@ -140,8 +138,10 @@ class Ds389PluginsInfo(object): re_exclude = re.compile(r'^memberOfEntryScopeExcludeSubtree:\s+(.*)', re.IGNORECASE) re_autoaddoc = re.compile(r'^memberOfAutoAddOC:\s+(.*)', re.IGNORECASE) - if 'memberof' not in self.result: - self.result['memberof'] = {} + key = 'memberof' + + if key not in self.result: + self.result[key] = {} for line in proc.stdout.splitlines(): line = line.strip() @@ -150,73 +150,73 @@ class Ds389PluginsInfo(object): m = self.re_cn.match(line) if m: - self.result['memberof']['cn'] = m.group(1) + self.result[key]['cn'] = m.group(1) continue m = self.re_plugin_version.match(line) if m: - self.result['memberof']['plugin_version'] = m.group(1) + self.result[key]['plugin_version'] = m.group(1) continue m = self.re_enabled.match(line) if m: - self.result['memberof']['enabled'] = self.mangle_value(m.group(1)) + self.result[key]['enabled'] = self.mangle_value(m.group(1)) continue m = re_attr.match(line) if m: - self.result['memberof']['attr'] = m.group(1) + self.result[key]['attr'] = m.group(1) continue m = re_groupattr.match(line) if m: - if 'groupattr' not in self.result['memberof']: - self.result['memberof']['groupattr'] = [] - self.result['memberof']['groupattr'].append(m.group(1)) + if 'groupattr' not in self.result[key]: + self.result[key]['groupattr'] = [] + self.result[key]['groupattr'].append(m.group(1)) continue m = re_allbackends.match(line) if m: - self.result['memberof']['allbackends'] = self.mangle_value(m.group(1)) + self.result[key]['allbackends'] = self.mangle_value(m.group(1)) continue m = re_skipnested.match(line) if m: - self.result['memberof']['skipnested'] = self.mangle_value(m.group(1)) + self.result[key]['skipnested'] = self.mangle_value(m.group(1)) continue m = re_scope.match(line) if m: - if 'scope' not in self.result['memberof']: - self.result['memberof']['scope'] = [] - self.result['memberof']['scope'].append(m.group(1)) + if 'scope' not in self.result[key]: + self.result[key]['scope'] = [] + self.result[key]['scope'].append(m.group(1)) continue m = re_exclude.match(line) if m: - if 'exclude' not in self.result['memberof']: - self.result['memberof']['exclude'] = [] - self.result['memberof']['exclude'].append(m.group(1)) + if 'exclude' not in self.result[key]: + self.result[key]['exclude'] = [] + self.result[key]['exclude'].append(m.group(1)) continue m = re_autoaddoc.match(line) if m: - self.result['memberof']['auto_add_oc'] = m.group(1) + self.result[key]['auto_add_oc'] = m.group(1) continue # -------------------------------------------------------------------------- def get_referint(self): - """Get config of mreferential-integrity plugin.""" + """Get config of referential-integrity plugin.""" proc = run( [self.cmd, self.instance, 'plugin', 'referential-integrity', 'show'], capture_output=True, encoding=self.encoding) if proc.stderr: - warnings.warn(proc.stderr) - try: - proc.check_returncode() - except CalledProcessError: + module.warn(proc.stderr) + if proc.returncode: return + key = 'referint' + re_upate_delay = re.compile(r'^referint-update-delay:\s+(.*)', re.IGNORECASE) re_membership_attr = re.compile(r'^referint-membership-attr:\s+(.*)', re.IGNORECASE) re_entry_scope = re.compile(r'^nsslapd-pluginEntryScope:\s+(.*)', re.IGNORECASE) @@ -225,8 +225,8 @@ class Ds389PluginsInfo(object): re_container_scope = re.compile(r'^mnsslapd-pluginContainerScope:\s+(.*)', re.IGNORECASE) re_logfile = re.compile(r'^referint-logfile:\s+(.*)', re.IGNORECASE) - if 'referint' not in self.result: - self.result['referint'] = {} + if key not in self.result: + self.result[key] = {} for line in proc.stdout.splitlines(): line = line.strip() @@ -235,51 +235,206 @@ class Ds389PluginsInfo(object): m = self.re_cn.match(line) if m: - self.result['referint']['cn'] = m.group(1) + self.result[key]['cn'] = m.group(1) continue m = self.re_plugin_version.match(line) if m: - self.result['referint']['plugin_version'] = m.group(1) + self.result[key]['plugin_version'] = m.group(1) continue m = self.re_enabled.match(line) if m: - self.result['referint']['enabled'] = self.mangle_value(m.group(1)) + self.result[key]['enabled'] = self.mangle_value(m.group(1)) continue m = re_membership_attr.match(line) if m: - if 'membership_attr' not in self.result['referint']: - self.result['referint']['membership_attr'] = [] - self.result['referint']['membership_attr'].append(m.group(1)) + if 'membership_attr' not in self.result[key]: + self.result[key]['membership_attr'] = [] + self.result[key]['membership_attr'].append(m.group(1)) continue m = re_upate_delay.match(line) if m: - self.result['referint']['update_delay'] = self.mangle_value(m.group(1)) + self.result[key]['update_delay'] = self.mangle_value(m.group(1)) continue m = re_entry_scope.match(line) if m: - self.result['referint']['entry_scope'] = m.group(1) + self.result[key]['entry_scope'] = m.group(1) continue m = re_exclude_entry_scope.match(line) if m: - self.result['referint']['exclude_entry_scope'] = m.group(1) + self.result[key]['exclude_entry_scope'] = m.group(1) continue m = re_container_scope.match(line) if m: - self.result['referint']['container_scope'] = m.group(1) + self.result[key]['container_scope'] = m.group(1) continue m = re_logfile.match(line) if m: - self.result['referint']['logfile'] = m.group(1) + self.result[key]['logfile'] = m.group(1) + continue + + # -------------------------------------------------------------------------- + def get_root_dn_access(self): + """Get config of the plugin managing the access of the root_dn.""" + proc = run( + [self.cmd, self.instance, 'plugin', 'root-dn', 'show'], + capture_output=True, encoding=self.encoding) + if proc.stderr: + module.warn(proc.stderr) + if proc.returncode: + return + + key = 'root_dn' + + list_attribs = { + 'allow_host': re.compile(r'^rootdn-allow-host:\s+(.*)', re.IGNORECASE), + 'deny_host': re.compile(r'^rootdn-deny-host:\s+(.*)', re.IGNORECASE), + 'allow_ip': re.compile(r'^rootdn-allow-ip:\s+(.*)', re.IGNORECASE), + 'deny_ip': re.compile(r'^rootdn-deny-ip:\s+(.*)', re.IGNORECASE), + } + + string_attribs = { + 'open_time': re.compile(r'^rootdn-open-time:\s+(.*)', re.IGNORECASE), + 'close_time': re.compile(r'^rootdn-close-time:\s+(.*)', re.IGNORECASE), + 'days_allowed': re.compile(r'^rootdn-days-allowed:\s+(.*)', re.IGNORECASE), + } + + if key not in self.result: + self.result[key] = {} + + for line in proc.stdout.splitlines(): + line = line.strip() + if not line: + continue + + m = self.re_cn.match(line) + if m: + self.result[key]['cn'] = m.group(1) + continue + + m = self.re_plugin_version.match(line) + if m: + self.result[key]['plugin_version'] = m.group(1) continue + m = self.re_enabled.match(line) + if m: + self.result[key]['enabled'] = self.mangle_value(m.group(1)) + continue + + for attrib in list_attribs: + regex = list_attribs[attrib] + m = regex.match(line) + if m: + if attrib not in self.result: + self.result[key][attrib] = [] + self.result[key][attrib].append(m.group(1)) + break + + for attrib in string_attribs: + regex = string_attribs[attrib] + m = regex.match(line) + if m: + self.result[key][attrib] = m.group(1) + + # -------------------------------------------------------------------------- + def get_account_policy(self): + """Get config of the account-policy plugin.""" + proc = run( + [self.cmd, self.instance, 'plugin', 'account-policy', 'show'], + capture_output=True, encoding=self.encoding) + if proc.stderr: + module.warn(proc.stderr) + if proc.returncode: + return + + key = 'account_policy' + + mangle_attribs = { + 'always_record_login': re.compile(r'^alwaysRecordLogin:\s+(.*)', re.IGNORECASE), + 'check_all_state_attrs': re.compile(r'^checkAllStateAttrs:\s+(.*)', re.IGNORECASE), + 'login_history_size': re.compile(r'^lastLoginHistSize:\s+(.*)', re.IGNORECASE), + } + + string_attribs = { + 'alt_state_attr': re.compile(r'^altStateAttrName:\s+(.*)', re.IGNORECASE), + 'always_record_login_attr': re.compile( + r'^alwaysRecordLoginAttr:\s+(.*)', re.IGNORECASE), + 'limit_attr': re.compile(r'^limitAttrName:\s+(.*)', re.IGNORECASE), + 'spec_attr': re.compile(r'^specAttrName:\s+(.*)', re.IGNORECASE), + 'state_attr': re.compile(r'^stateAttrName:\s+(.*)', re.IGNORECASE), + } + + re_config_entry = re.compile(r'^nsslapd-pluginarg\d+:\s+(.*)', re.IGNORECASE) + config_entry = None + + if key not in self.result: + self.result[key] = {} + + for line in proc.stdout.splitlines(): + line = line.strip() + if not line: + continue + + m = self.re_cn.match(line) + if m: + self.result[key]['cn'] = m.group(1) + continue + + m = self.re_plugin_version.match(line) + if m: + self.result[key]['plugin_version'] = m.group(1) + continue + + m = self.re_enabled.match(line) + if m: + self.result[key]['enabled'] = self.mangle_value(m.group(1)) + continue + + m = re_config_entry.match(line) + if m: + config_entry = m.group(1) + self.result[key]['config_entry'] = config_entry + continue + + if not config_entry: + return + + proc = run([ + self.cmd, self.instance, 'plugin', 'account-policy', 'config-entry', + 'show', config_entry], capture_output=True, encoding=self.encoding) + + if proc.stderr: + module.warn(proc.stderr) + if proc.returncode: + return + + for line in proc.stdout.splitlines(): + line = line.strip() + if not line: + continue + + for attrib in mangle_attribs: + regex = mangle_attribs[attrib] + m = regex.match(line) + if m: + self.result[key][attrib] = self.mangle_value(m.group(1)) + break + + for attrib in string_attribs: + regex = string_attribs[attrib] + m = regex.match(line) + if m: + self.result[key][attrib] = self.mangle_value(m.group(1)) + break + # ############################################################################## def main(): diff --git a/plugins/filter/filter.py b/plugins/filter/filter.py index 6b9fed9..6a9eba4 100644 --- a/plugins/filter/filter.py +++ b/plugins/filter/filter.py @@ -21,10 +21,10 @@ except ImportError: class FilterModule(object): """A filter module object.""" - re_key = re.compile(r'nsslapd-', re.IGNORECASE) # noqa: W605 - re_sep = re.compile(r':\s+') # noqa: W605 - re_int = re.compile('^[+-]?\d+$') # noqa: W605 - re_float = re.compile('^[+-]?\d+\.\d*$') # noqa: W605 + re_key = re.compile(r'nsslapd-', re.IGNORECASE) + re_sep = re.compile(r':\s+') + re_int = re.compile(r'^[+-]?\d+$') + re_float = re.compile(r'^[+-]?\d+\.\d*$') # ------------------ def filters(self): -- 2.39.5