From 1e68d980a0587bb1afea3685d0a46fce86135cb9 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 6 Jul 2014 19:55:58 +0200 Subject: Enable zero-copy updates to the LDAP directory. --- ansible.cfg | 10 +-- lib/action_plugins/openldap.py | 83 ++++++++++++++++++++++ lib/modules/openldap | 5 +- roles/LDAP-provider/tasks/main.yml | 9 +-- roles/common-LDAP/tasks/main.yml | 27 +++---- .../templates/etc/ldap/database.ldif.j2 | 2 +- 6 files changed, 103 insertions(+), 33 deletions(-) create mode 100644 lib/action_plugins/openldap.py diff --git a/ansible.cfg b/ansible.cfg index 10b8f7f..cfa03e5 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -90,11 +90,11 @@ ansible_managed = Ansible Managed: modified on %Y-%m-%d %H:%M:%S by {uid}@{host} # additional plugin paths for non-core plugins -action_plugins = /usr/share/ansible_plugins/action_plugins -callback_plugins = /usr/share/ansible_plugins/callback_plugins -connection_plugins = /usr/share/ansible_plugins/connection_plugins -lookup_plugins = /usr/share/ansible_plugins/lookup_plugins -vars_plugins = /usr/share/ansible_plugins/vars_plugins +action_plugins = ./lib/action_plugins +callback_plugins = ./lib/callback_plugins +connection_plugins = ./lib/connection_plugins +lookup_plugins = ./lib/lookup_plugins +vars_plugins = ./lib/vars_plugins [ssh_connection] diff --git a/lib/action_plugins/openldap.py b/lib/action_plugins/openldap.py new file mode 100644 index 0000000..ee8a991 --- /dev/null +++ b/lib/action_plugins/openldap.py @@ -0,0 +1,83 @@ +# Manage OpenLDAP databases +# Copyright (c) 2014 Guilhem Moulin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import pipes +import tempfile + +from ansible.utils import template +from ansible import utils +from ansible.runner.return_data import ReturnData + +class ActionModule(object): + TRANSFERS_FILES = True + + def __init__(self, runner): + self.runner = runner + + def run(self, conn, tmp, module_name, module_args, inject, complex_args=None, **kwargs): + ''' handler for file transfer operations ''' + + # load up options + options = {} + if complex_args: + options.update(complex_args) + options.update(utils.parse_kv(module_args)) + + target = options.get('target', None) + local = options.get('local', 'no') + + if local not in [ 'no', 'file', 'template' ]: + result = dict(failed=True, msg="local must be in ['no','file','template']") + return ReturnData(conn=conn, comm_ok=False, result=result) + + if local != 'no' and target is None: + result = dict(failed=True, msg="target is required in local mode") + return ReturnData(conn=conn, comm_ok=False, result=result) + + if local == 'no': + # run the module remotely + return self.runner._execute_module(conn, tmp, 'openldap', module_args, inject=inject, complex_args=complex_args) + elif '_original_file' in inject: + target = utils.path_dwim_relative(inject['_original_file'], local+'s', target, self.runner.basedir) + else: + # the source is local, so expand it here + target = os.path.expanduser(target) + + options['local'] = 'no' + options['target'] = os.path.join(tmp, os.path.basename(target)) + if local == 'template': + # template the source data locally and transfer it + try: + s = template.template_from_file(self.runner.basedir, target, inject, vault_password=self.runner.vault_pass) + tmpfile = tempfile.NamedTemporaryFile(delete=False) + tmpfile.write(s) + tmpfile.close() + target = tmpfile.name + except Exception, e: + result = dict(failed=True, msg=str(e)) + return ReturnData(conn=conn, comm_ok=False, result=result) + conn.put_file(tmpfile.name, options['target']) + os.unlink(tmpfile.name) + + elif local == 'file': + conn.put_file(target, options['target']) + + # run the script remotely with the new (temporary) filename + module_args = "" + for o in options: + module_args = "%s %s=%s" % (module_args, o, pipes.quote(options[o])) + return self.runner._execute_module(conn, tmp, 'openldap', module_args, inject=inject) diff --git a/lib/modules/openldap b/lib/modules/openldap index 7293b23..3f6ea39 100644 --- a/lib/modules/openldap +++ b/lib/modules/openldap @@ -351,6 +351,7 @@ def main(): suffix = dict( default=None ), format = dict( default="ldif", choices=["ldif","slapd.conf"] ), name = dict( default=None ), + local = dict( default="no", choices=["no","file","template"] ), ), supports_check_mode=True ) @@ -428,7 +429,7 @@ def main(): module.exit_json(changed=changed) +# import module snippets +from ansible.module_utils.basic import * -# this is magic, see lib/ansible/module_common.py -#<> main() diff --git a/roles/LDAP-provider/tasks/main.yml b/roles/LDAP-provider/tasks/main.yml index 64c8e30..fc9ed62 100644 --- a/roles/LDAP-provider/tasks/main.yml +++ b/roles/LDAP-provider/tasks/main.yml @@ -1,12 +1,7 @@ -- name: Copy the syncprov overlay configuration - copy: src=etc/ldap/syncprov.ldif - dest=/etc/ldap/fripost/syncprov.ldif - owner=root group=root - mode=0644 - - name: Load and configure the syncprov overlay openldap: module=syncprov state=present suffix=o=mailHosting,dc=fripost,dc=org - target=/etc/ldap/fripost/syncprov.ldif + target=etc/ldap/syncprov.ldif + local=file # TODO: authz constraint diff --git a/roles/common-LDAP/tasks/main.yml b/roles/common-LDAP/tasks/main.yml index 3ef02e8..5aa8a2e 100644 --- a/roles/common-LDAP/tasks/main.yml +++ b/roles/common-LDAP/tasks/main.yml @@ -43,18 +43,6 @@ # Not sure if required - Restart slapd -- name: Create directory /etc/ldap/fripost - file: path=/etc/ldap/fripost - state=directory - owner=root group=root - mode=0755 - -- name: Copy fripost database definition - template: src=etc/ldap/database.ldif.j2 - dest=/etc/ldap/fripost/database.ldif - owner=root group=root - mode=0600 - - name: Copy fripost & amavis' schema copy: src=etc/ldap/schema/{{ item }} dest=/etc/ldap/schema/{{ item }} @@ -69,18 +57,21 @@ tags: - amavis -- name: Load fripost's schema and configure the database - openldap: target=/etc/ldap/{{ item }} state=present - with_items: - - schema/fripost.ldif - - fripost/database.ldif - - name: Load amavis' schema openldap: target=/etc/ldap/schema/amavis.schema state=present format=slapd.conf name=amavis tags: - ldap +- name: Load Fripost' schema + openldap: target=/etc/ldap/schema/fripost.ldif state=present + tags: + - ldap + +- name: Configure the LDAP database + openldap: target=etc/ldap/database.ldif.j2 local=template + state=present + - name: Start slapd service: name=slapd state=started when: not (r1.changed or r2.changed) diff --git a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 index cde9069..af31836 100644 --- a/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 +++ b/roles/common-LDAP/templates/etc/ldap/database.ldif.j2 @@ -1,5 +1,5 @@ # Fripost's LDAP database definition -# Copyright © 2013 Guilhem Moulin +# Copyright (c) 2013 Guilhem Moulin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -- cgit v1.2.3