From 0b71d123d2470060790722c69455b141ae67ba08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Tue, 15 Mar 2022 05:39:51 +0100 Subject: [PATCH] ldap_entry - Recursive deletion (#4355) * ldap_entry - Recursive deletion * Recursive deletion can be enabled with the `recursive` option. It is disabled by default. * When enabled, deletion is attempted by sending a single delete request with the Subtree Delete control. If that request fails with the `NOT_ALLOWED_ON_NONLEAF` error, try deleting the whole branch in reverse order using individual delete requests. * ldap_entry recursive deletion - Changelog fragment * ldap_entry - Refactored to avoid lint message * Update changelogs/fragments/4355-ldap-recursive-delete.yml Co-authored-by: Felix Fontein * ldap_entry - Add version_added to the recursive flag Co-authored-by: Felix Fontein * ldap_entry - Moved member assignment to a more suitable location Co-authored-by: Felix Fontein --- .../fragments/4355-ldap-recursive-delete.yml | 4 +++ plugins/modules/net_tools/ldap/ldap_entry.py | 31 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/4355-ldap-recursive-delete.yml diff --git a/changelogs/fragments/4355-ldap-recursive-delete.yml b/changelogs/fragments/4355-ldap-recursive-delete.yml new file mode 100644 index 0000000000..fea016975b --- /dev/null +++ b/changelogs/fragments/4355-ldap-recursive-delete.yml @@ -0,0 +1,4 @@ +--- +minor_changes: + - ldap_entry - add support for recursive deletion + (https://github.com/ansible-collections/community.general/issues/3613). diff --git a/plugins/modules/net_tools/ldap/ldap_entry.py b/plugins/modules/net_tools/ldap/ldap_entry.py index 2ef06b9693..24e121e521 100644 --- a/plugins/modules/net_tools/ldap/ldap_entry.py +++ b/plugins/modules/net_tools/ldap/ldap_entry.py @@ -49,6 +49,13 @@ options: choices: [present, absent] default: present type: str + recursive: + description: + - If I(state=delete), a flag indicating whether a single entry or the + whole branch must be deleted. + type: bool + default: false + version_added: 4.6.0 extends_documentation_fragment: - community.general.ldap.documentation @@ -110,6 +117,7 @@ from ansible_collections.community.general.plugins.module_utils.ldap import Ldap LDAP_IMP_ERR = None try: import ldap.modlist + import ldap.controls HAS_LDAP = True except ImportError: @@ -123,6 +131,7 @@ class LdapEntry(LdapGeneric): # Shortcuts self.state = self.module.params['state'] + self.recursive = self.module.params['recursive'] # Add the objectClass into the list of attributes self.module.params['attributes']['objectClass'] = ( @@ -158,12 +167,29 @@ class LdapEntry(LdapGeneric): return action def delete(self): - """ If self.dn exists, returns a callable that will delete it. """ + """ If self.dn exists, returns a callable that will delete either + the item itself if the recursive option is not set or the whole branch + if it is. """ def _delete(): self.connection.delete_s(self.dn) + def _delete_recursive(): + """ Attempt recurive deletion using the subtree-delete control. + If that fails, do it manually. """ + try: + subtree_delete = ldap.controls.ValueLessRequestControl('1.2.840.113556.1.4.805') + self.connection.delete_ext_s(self.dn, serverctrls=[subtree_delete]) + except ldap.NOT_ALLOWED_ON_NONLEAF: + search = self.connection.search_s(self.dn, ldap.SCOPE_SUBTREE, attrlist=('dn',)) + search.reverse() + for entry in search: + self.connection.delete_s(entry[0]) + if self._is_entry_present(): - action = _delete + if self.recursive: + action = _delete_recursive + else: + action = _delete else: action = None @@ -186,6 +212,7 @@ def main(): attributes=dict(default={}, type='dict'), objectClass=dict(type='list', elements='str'), state=dict(default='present', choices=['present', 'absent']), + recursive=dict(default=False, type='bool'), ), required_if=[('state', 'present', ['objectClass'])], supports_check_mode=True,