+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@summary: Ansible filter module of filter 'compare_lc_list'.
+
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@copyright: © 2024 by Frank Brehm, Berlin
+"""
+
import re
# =============================================================================
class FilterModule(object):
+ """A filter module object."""
- re_key = re.compile(r'nsslapd-', re.IGNORECASE)
- re_sep = re.compile(r':\s+')
- re_int = re.compile('^[+-]?\d+$')
- re_float = re.compile('^[+-]?\d+\.\d*$')
+ 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
# ------------------
def filters(self):
- return {'cfg_389ds_to_dict': self.cfg_389ds_to_dict }
+ """Return all usable filter methods from this class."""
+ return {'cfg_389ds_to_dict': self.cfg_389ds_to_dict}
# ------------------
def cfg_389ds_to_dict(self, the_list):
+ """
+ Translate a list of strings of the form 'key: value' into a dictionary.
+
+ In case of multiple values with the same key, they are assigned as a list to the key.
+ If a key is starting with 'nsslapd-', this will removed from the key.
+ The values are mangled with the method mangle_value().
+ """
result = {}
for line in the_list:
# ------------------
def mangle_value(self, value):
-
+ """Tape cast the given value to a boolean, integer of float value, if it is looking so."""
if self.re_int.match(value):
return int(value)
if self.re_float.match(value):
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@summary: Ansible filter module of filter 'compare_lc_list'.
+
+@author: Frank Brehm
+@contact: frank@brehm-online.com
+@copyright: © 2024 by Frank Brehm, Berlin
+"""
+
+try:
+ from collections.abc import Sequence
+except ImportError:
+ from collections import Sequence
+
+# =============================================================================
+class FilterModule(object):
+ """A filter module object."""
+
+ # ------------------
+ def filters(self):
+ """Return all usable filter methods from this class."""
+ return {
+ 'compare_lc_list': self.compare_lc_list,
+ 'bool_to_on_off': self.bool_to_on_off,
+ }
+
+ # ------------------
+ def compare_lc_list(self, list_one, list_two):
+ """Compare two lists with case-insensitive and position independend items."""
+ if not isinstance(list_one, Sequence) or hasattr(list_one, 'strip'):
+ list_one = [list_one]
+
+ if not isinstance(list_two, Sequence) or hasattr(list_two, 'strip'):
+ list_two = [list_two]
+
+ if len(list_one) != len(list_two):
+ return False
+
+ list_one_lc = []
+ for item in list_one:
+ list_one_lc.append(str(item).lower())
+ list_one_lc.sort()
+
+ list_two_lc = []
+ for item in list_two:
+ list_two_lc.append(str(item).lower())
+ list_one_lc.sort()
+
+ if list_one_lc == list_two_lc:
+ return True
+
+ return False
+
+ # ------------------
+ def bool_to_on_off(self, value):
+ """Translate the given value to on or off respective."""
+ if value:
+ return 'on'
+ return 'off'
+
+
+# =============================================================================
+
+# vim: ts=4 et list
include_role:
name: '389ds-config-logging'
+ - name: "Configure all necessay plugins of the 389ds LDAP server."
+ include_role:
+ name: 389ds-config-plugins
# vim: filetype=yaml
--- /dev/null
+---
+
+- name: "Configuring the 389ds memberOf-Plugin."
+ include_tasks: 'memberof.yaml'
+ when: (ds389_plugin_memberof_config | bool) == true
+
+# vim: filetype=yaml
--- /dev/null
+---
+
+- name: 'Get the current configuration of the memberOf-Plugin.'
+ ansible.builtin.shell: "dsconf {{ slapd_instance | quote }} plugin memberof show | grep -P -i '^(memberof|nsslapd-pluginEnabled)' | sed -e 's/^memberof//i' -e 's/nsslapd-plugin//i' | tr '[:upper:]' '[:lower:]' | sort || true"
+ register: plugin_memberof
+ changed_when: false
+ check_mode: false
+
+- name: 'Show raw memberof attribute config.'
+ debug:
+ var: plugin_memberof
+ verbosity: 3
+
+- name: "Set variable plugin_memberof_config"
+ set_fact:
+ plugin_memberof_config: "{{ plugin_memberof.stdout_lines | cfg_389ds_to_dict }}"
+
+- name: "Show config hash:"
+ debug:
+ var: plugin_memberof_config
+ verbosity: 0
+
+- name: 'Predefine variable exec_set to false'
+ set_fact:
+ exec_set: false
+
+- name: 'Check for attr.'
+ set_fact:
+ exec_set: true
+ when: '"attr" not in plugin_memberof_config or plugin_memberof_config["attr"] != ( ds389_plugin_memberof_attr | lower )'
+
+- name: 'Check for groupattrs not set.'
+ set_fact:
+ exec_set: true
+ when: '"groupattr" not in plugin_memberof_config'
+
+- name: 'Check for groupattrs.'
+ set_fact:
+ exec_set: true
+ when: '"groupattr" in plugin_memberof_config and (plugin_memberof_config["groupattr"] | compare_lc_list(ds389_plugin_memberof_groupattrs) != true)'
+
+- name: 'Check for allbackends.'
+ set_fact:
+ exec_set: true
+ when: '"allbackends" not in plugin_memberof_config or plugin_memberof_config["allbackends"] != ds389_plugin_memberof_allbackends'
+
+- name: 'Check for skipnested.'
+ set_fact:
+ exec_set: true
+ when: '"skipnested" not in plugin_memberof_config or plugin_memberof_config["skipnested"] != ds389_plugin_memberof_skipnested'
+
+- name: "Has the memberOf-Plugin to be configured:"
+ debug:
+ var: exec_set
+
+- name: "Configure the memberof plugin, if necessary."
+ when: exec_set == true
+ block:
+
+ - name: "Init var plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "dsconf {{ slapd_instance | quote }} plugin memberof set"
+
+ - name: "Add attr to plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "{{ plugin_memberof_cmd }} --attr {{ ds389_plugin_memberof_attr }}"
+
+ - name: "Add groupattrs to plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "{{ plugin_memberof_cmd }} --groupattr {{ ds389_plugin_memberof_groupattrs | join(' ') }}"
+
+ - name: "Add allbackends to plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "{{ plugin_memberof_cmd }} --allbackends {{ ds389_plugin_memberof_allbackends | bool_to_on_off }}"
+
+ - name: "Add skipnested to plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "{{ plugin_memberof_cmd }} --skipnested {{ ds389_plugin_memberof_skipnested | bool_to_on_off }}"
+
+ - name: "Add suffixes as scope."
+ when: "ds389_plugin_memberof_scopes | length < 1"
+ block:
+
+ - name: "Retrieve all backends"
+ ansible.builtin.shell: "dsconf '{{ slapd_instance }}' backend suffix list"
+ register: get_backend_suffixes
+ changed_when: false
+ check_mode: false
+
+ - name: "Set scopes from suffixes list"
+ no_log: true
+ set_fact:
+ scopes: "{{ get_backend_suffixes.stdout_lines | map('regex_replace', '\\s+\\(.+\\)\\s*$', '') | list }}"
+
+ - name: "Add scopes from config."
+ when: "ds389_plugin_memberof_scopes | length >= 1"
+ block:
+
+ - name: "Set scopes from config."
+ set_fact:
+ scopes: "{{ ds389_plugin_memberof_scopes }}"
+
+ - name: "Add scopes to plugin_memberof_cmd."
+ set_fact:
+ plugin_memberof_cmd: "{{ plugin_memberof_cmd }} --scope {{ scopes | map('quote') | join(' ') }}"
+
+ - name: "Show the command to execute:"
+ debug:
+ var: plugin_memberof_cmd
+ verbosity: 0
+
+ - name: "Finally configure the memberof plugin."
+ ansible.builtin.shell: "{{ plugin_memberof_cmd }}"
+
+
+# vim: filetype=yaml
--- /dev/null
+---
+
+ds389_plugin_memberof_config: true
+ds389_plugin_memberof_attr: 'memberOf'
+ds389_plugin_memberof_groupattrs:
+ - 'member'
+ - 'uniqueMember'
+ds389_plugin_memberof_allbackends: true
+ds389_plugin_memberof_skipnested: false
+
+# Later do eval, how to maintain
+ds389_plugin_memberof_scopes: []
+ds389_plugin_memberof_escapes: []
+ds389_plugin_memberof_auto_add_oc: ~
+
+
+# vim: filetype=yaml