diff options
-rw-r--r-- | ansible.cfg | 10 | ||||
-rw-r--r-- | lib/action_plugins/openldap.py | 83 | ||||
-rw-r--r-- | lib/modules/openldap | 5 | ||||
-rw-r--r-- | roles/LDAP-provider/tasks/main.yml | 9 | ||||
-rw-r--r-- | roles/common-LDAP/tasks/main.yml | 27 | ||||
-rw-r--r-- | roles/common-LDAP/templates/etc/ldap/database.ldif.j2 | 2 |
6 files changed, 103 insertions, 33 deletions
diff --git a/ansible.cfg b/ansible.cfg index 10b8f7f..cfa03e5 100644 --- a/ansible.cfg +++ b/ansible.cfg @@ -73,38 +73,38 @@ remote_port = 22 # if "user:" is not set in a playbook. If not set, use the current Unix user # as the default #remote_user = root # if set, always use this private key file for authentication, same as if passing # --private-key to ansible or ansible-playbook #private_key_file=/path/to/file # format of string $ansible_managed available within Jinja2 templates, replacing # {file}, {host} and {uid} with template filename, host and owner respectively. # The resulting string is passed through strftime(3) so it may contain any # time-formatting specifiers. # # Example: ansible_managed = DONT TOUCH {file}: call {uid} at {host} for changes 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] # if uncommented, sets the ansible ssh arguments to the following. Leaving off ControlPersist # will result in poor performance, so use transport=paramiko on older platforms rather than # removing it ssh_args = -F ../virtualenv/.ssh/config -o ControlMaster=auto -o ControlPersist=60s -o ControlPath=/tmp/ansible-ssh-%h-%p-%r pipelining = True 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 <guilhem@fripost.org> +# +# 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 <http://www.gnu.org/licenses/>. + +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 @@ -334,40 +334,41 @@ def slapd_to_ldif(src, name): d.write( reSp.sub(line, ' ') ) s.close() d.close() return d.name def main(): module = AnsibleModule( argument_spec = dict( dbdirectory = dict( default=None ), ignoredn = dict( default=None ), state = dict( default="present", choices=["absent", "present"]), target = dict( default=None ), module = dict( default=None ), 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 ) params = module.params state = params['state'] dbdirectory = params['dbdirectory'] ignoredn = params['ignoredn'] target = params['target'] mod = params['module'] suffix = params['suffix'] form = params['format'] name = params['name'] if ignoredn is not None: ignoredn = ignoredn.split(':') changed = False try: if state == "absent": @@ -411,24 +412,24 @@ def main(): parser.parse() changed = parser.changed l.unbind_s() except subprocess.CalledProcessError, e: module.fail_json(rv=e.returncode, msg=e.output.rstrip()) except ldap.LDAPError, e: e = e.args[0] if 'info' in e.keys(): msg = e['info'] elif 'desc' in e.keys(): msg = e['desc'] else: msg = str(e) module.fail_json(msg=msg) except KeyError, e: module.fail_json(msg=str(e)) module.exit_json(changed=changed) +# import module snippets +from ansible.module_utils.basic import * -# this is magic, see lib/ansible/module_common.py -#<<INCLUDE_ANSIBLE_MODULE_COMMON>> 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 @@ -26,63 +26,54 @@ # than its suffix or cn=admin,... openldap: dbdirectory=/var/lib/ldap ignoredn=cn=admin state=absent - name: Create directory /var/lib/ldap/fripost file: path=/var/lib/ldap/fripost state=directory owner=openldap group=openldap mode=0700 - name: Copy /var/lib/ldap/fripost/DB_CONFIG copy: src=var/lib/ldap/fripost/DB_CONFIG dest=/var/lib/ldap/fripost/DB_CONFIG owner=openldap group=openldap mode=0600 register: r2 notify: # 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 }} owner=root group=root mode=0644 # It'd certainly be nicer if we didn't have to deploy amavis' schema # everywhere, but we need the 'objectClass' in our replicates, hence # they need to be aware of the 'amavisAccount' class. with_items: - fripost.ldif - amavis.schema 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) - meta: flush_handlers 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,22 +1,22 @@ # Fripost's LDAP database definition -# Copyright © 2013 Guilhem Moulin <guilhem@fripost.org> +# Copyright (c) 2013 Guilhem Moulin <guilhem@fripost.org> # # 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 <http://www.gnu.org/licenses/>. dn: olcDatabase=hdb,cn=config objectClass: olcDatabaseConfig objectClass: olcHdbConfig olcDbDirectory: /var/lib/ldap/fripost olcSuffix: o=mailHosting,dc=fripost,dc=org olcLastMod: TRUE |