From 27a3a90fc8db7a92a8b7e4da452e74af14872507 Mon Sep 17 00:00:00 2001 From: Fran Fitzpatrick Date: Tue, 17 Jul 2018 05:57:54 -0500 Subject: [PATCH] FreeIPA: new module ipa_config (#42279) * Adds new ipa_config module * Modify _post_json to handle config_show/config_mod * Doc: Add periods * More documentation * Added aliases --- lib/ansible/module_utils/ipa.py | 10 +- .../modules/identity/ipa/ipa_config.py | 139 ++++++++++++++++++ 2 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 lib/ansible/modules/identity/ipa/ipa_config.py diff --git a/lib/ansible/module_utils/ipa.py b/lib/ansible/module_utils/ipa.py index 23b7c5e70a..da4a6d4806 100644 --- a/lib/ansible/module_utils/ipa.py +++ b/lib/ansible/module_utils/ipa.py @@ -97,10 +97,14 @@ class IPAClient(object): item = {} url = '%s/session/json' % self.get_base_url() data = dict(method=method) - if method != 'ping': - data['params'] = [[name], item] - else: + + # TODO: We should probably handle this a little better. + if method in ('ping', 'config_show'): data['params'] = [[], {}] + elif method == 'config_mod': + data['params'] = [[], item] + else: + data['params'] = [[name], item] try: resp, info = fetch_url(module=self.module, url=url, data=to_bytes(json.dumps(data)), headers=self.headers) diff --git a/lib/ansible/modules/identity/ipa/ipa_config.py b/lib/ansible/modules/identity/ipa/ipa_config.py new file mode 100644 index 0000000000..f28239159c --- /dev/null +++ b/lib/ansible/modules/identity/ipa/ipa_config.py @@ -0,0 +1,139 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2018, Fran Fitzpatrick +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: ipa_config +author: Fran Fitzpatrick (@fxfitz) +short_description: Manage Global FreeIPA Configuration Settings +description: +- Modify global configuration settings of a FreeIPA Server. +options: + ipadefaultloginshell: + description: Default shell for new users. + aliases: ["loginshell"] + ipadefaultemaildomain: + description: Default e-mail domain for new users. + aliases: ["emaildomain"] +extends_documentation_fragment: ipa.documentation +version_added: "2.7" +''' + +EXAMPLES = ''' +# Ensure the default login shell is bash. +- ipa_config: + ipadefaultloginshell: /bin/bash + ipa_host: localhost + ipa_user: admin + ipa_pass: supersecret + +# Ensure the default e-mail domain is ansible.com. +- ipa_config: + ipadefaultemaildomain: ansible.com + ipa_host: localhost + ipa_user: admin + ipa_pass: supersecret +''' + +RETURN = ''' +config: + description: Configuration as returned by IPA API. + returned: always + type: dict +''' + +import traceback + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ipa import IPAClient, ipa_argument_spec +from ansible.module_utils._text import to_native + + +class ConfigIPAClient(IPAClient): + def __init__(self, module, host, port, protocol): + super(ConfigIPAClient, self).__init__(module, host, port, protocol) + + def config_show(self): + return self._post_json(method='config_show', name=None) + + def config_mod(self, name, item): + return self._post_json(method='config_mod', name=name, item=item) + + +def get_config_dict(ipadefaultloginshell=None, ipadefaultemaildomain=None): + config = {} + if ipadefaultloginshell is not None: + config['ipadefaultloginshell'] = ipadefaultloginshell + if ipadefaultemaildomain is not None: + config['ipadefaultemaildomain'] = ipadefaultemaildomain + + return config + + +def get_config_diff(client, ipa_config, module_config): + return client.get_diff(ipa_data=ipa_config, module_data=module_config) + + +def ensure(module, client): + module_config = get_config_dict( + ipadefaultloginshell=module.params.get('ipadefaultloginshell'), + ipadefaultemaildomain=module.params.get('ipadefaultemaildomain'), + ) + ipa_config = client.config_show() + diff = get_config_diff(client, ipa_config, module_config) + + changed = False + new_config = {} + for module_key in diff: + if module_config.get(module_key) != ipa_config.get(module_key, None): + changed = True + new_config.update({module_key: module_config.get(module_key)}) + + if changed and not module.check_mode: + client.config_mod(name=None, item=new_config) + + return changed, client.config_show() + + +def main(): + argument_spec = ipa_argument_spec() + argument_spec.update( + ipadefaultloginshell=dict(type='str', aliases=['loginshell']), + ipadefaultemaildomain=dict(type='str', aliases=['emaildomain']), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + client = ConfigIPAClient( + module=module, + host=module.params['ipa_host'], + port=module.params['ipa_port'], + protocol=module.params['ipa_prot'] + ) + + try: + client.login( + username=module.params['ipa_user'], + password=module.params['ipa_pass'] + ) + changed, user = ensure(module, client) + module.exit_json(changed=changed, user=user) + except Exception as e: + module.fail_json(msg=to_native(e), exception=traceback.format_exc()) + + +if __name__ == '__main__': + main()