From 56b1368441fce0f711ec12254aa0945450f122d6 Mon Sep 17 00:00:00 2001
From: chrisp <chris@chrisprocter.co.uk>
Date: Thu, 19 Dec 2019 20:57:24 +0000
Subject: [PATCH] There is a new config management module placed in the plugins
 folder:

  plugins/modules/ipaconfig.py

The config module allows the user change global config settings.

The config module is as compatible as possible to the Ansible upstream
ipa_config module, but adds many extra variables.

Here is the documentation for the module:

  README-config.md
---
 README-config.md             | 145 +++++++++++
 plugins/modules/ipaconfig.py | 460 +++++++++++++++++++++++++++++++++++
 tests/config/test_config.yml | 143 +++++++++++
 3 files changed, 748 insertions(+)
 create mode 100644 README-config.md
 create mode 100644 plugins/modules/ipaconfig.py
 create mode 100644 tests/config/test_config.yml

diff --git a/README-config.md b/README-config.md
new file mode 100644
index 00000000..608df548
--- /dev/null
+++ b/README-config.md
@@ -0,0 +1,145 @@
+Config module
+===========
+
+Description
+-----------
+
+The config module allows the setting of global config parameters within IPA. If no parameters are specified it returns the list of all current parameters.
+
+The config module is as compatible as possible to the Ansible upstream `ipa_config` module, but adds many additional parameters
+
+
+Features
+--------
+* IPA server configuration management
+
+
+Supported FreeIPA Versions
+--------------------------
+
+FreeIPA versions 4.4.0 and up are supported by the ipaconfig module.
+
+
+Requirements
+------------
+
+**Controller**
+* Ansible version: 2.8+
+
+**Node**
+* Supported FreeIPA version (see above)
+
+
+Usage
+=====
+
+Example inventory file
+
+```ini
+[ipaserver]
+ipaserver.test.local
+```
+
+
+Example playbook to read config options:
+
+```yaml
+---
+- name: Playbook to handle global config options
+  hosts: ipaserver
+  become: true
+  tasks:
+    - name: return current values of the global configuration options
+      ipaconfig:
+        ipaadmin_password: password
+      register: result
+    - name: display default login shell
+      debug:
+        msg: '{{result.config.defaultlogin }}'
+
+    - name: ensure defaultloginshell and maxusernamelength are set as required
+      ipaconfig:
+        ipaadmin_password: password
+        defaultlogin: /bin/bash
+        maxusername: 64
+```
+
+```yaml
+---
+- name: Playbook to ensure some config options are set
+  hosts: ipaserver
+  become: true
+  tasks:
+    - name: set defaultlogin and maxusername
+      ipaconfig:
+        ipaadmin_password: password
+        defaultlogin: /bin/bash
+        maxusername: 64
+```
+
+
+Variables
+=========
+
+ipauser
+-------
+
+**General Variables:**
+
+Variable | Description | Required
+-------- | ----------- | --------
+`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
+`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
+`maxusername` \| `ipamaxusernamelength` |  Set the maximum username length (1 to 255) | false
+`homedirectory` \| `ipahomesrootdir` |  Set the default location of home directories | false
+`defaultshell` \| `ipadefaultloginshell` |  Set the default shell for new users | false
+`defaultgroup` \| `ipadefaultprimarygroup` |  Set the default group for new users | false
+`emaildomain`\| `ipadefaultemaildomain`  |  Set the default e-mail domain | false
+`searchtimelimit` \| `ipasearchtimelimit` |  Set maximum amount of time (seconds) for a search -1 to 2147483647 (-1 or 0 is unlimited) | false
+`searchrecordslimit` \| `ipasearchrecordslimit` |  Set maximum number of records to search -1 to 2147483647 (-1 or 0 is unlimited) | false
+`usersearch` \| `ipausersearchfields` |  Set list of fields to search when searching for users | false
+`groupsearch` \| `ipagroupsearchfields` |  Set list of fields to search in when searching for groups | false
+`enable_migration` \| `ipamigrationenabled` |  Enable migration mode (choices: True, False ) | false
+`groupobjectclasses` \| `ipagroupobjectclasses` |  Set default group objectclasses (list) | false
+`userobjectclasses` \| `ipauserobjectclasses` |  Set default user objectclasses (list) | false
+`pwdexpnotify` \| `ipapwdexpadvnotify` |  Set number of days's notice of impending password expiration (0 to 2147483647) | false
+`configstring` \| `ipaconfigstring` |  Set extra hashes to generate in password plug-in (choices:`AllowNThash`, `KDC:Disable Last Success`, `KDC:Disable Lockout`, `KDC:Disable Default Preauth for SPNs`) | false
+`selinuxusermaporder` \| `ipaselinuxusermaporder`| Set ordered list in increasing priority of SELinux users | false
+`selinuxusermapdefault`\| `ipaselinuxusermapdefault` |  Set default SELinux user when no match is found in SELinux map rule | false
+`pac_type` \| `ipakrbauthzdata` |  set default types of PAC supported for services (choices: `MS-PAC`, `PAD`, `nfs:NONE`)
+`user_auth_type` \| `ipauserauthtype` |  set default types of supported user authentication (choices: `password`, `radius`, `otp`, `disabled`) | false
+`domain_resolution_order` \| `ipadomainresolutionorder` | Set list of domains used for short name qualification | false
+
+
+Return Values
+=============
+
+Variable | Description | Returned When
+-------- | ----------- | -------------
+`config` | config dict <br />Fields: | No values to configure are specified
+&nbsp; | `homedirectory` | &nbsp;
+&nbsp; | `defaultshell` | &nbsp;
+&nbsp; | `defaultgroup` | &nbsp;
+&nbsp; | `emaildomain` | &nbsp;
+&nbsp; | `searchtimelimit` | &nbsp;
+&nbsp; | `searchrecordslimit` | &nbsp;
+&nbsp; | `usersearch` | &nbsp;
+&nbsp; | `groupsearch` | &nbsp;
+&nbsp; | `enable_migration` | &nbsp;
+&nbsp; | `groupobjectclasses` | &nbsp;
+&nbsp; | `userobjectclasses` | &nbsp;
+&nbsp; | `pwdexpnotify` | &nbsp;
+&nbsp; | `configstring` | &nbsp;
+&nbsp; | `selinuxusermaporder` | &nbsp;
+&nbsp; | `selinuxusermapdefault` | &nbsp;
+&nbsp; | `pac_type` | &nbsp;
+&nbsp; | `user_auth_type` | &nbsp;
+&nbsp; | `domain_resolution_order` | &nbsp;
+
+
+All returned fields take the same form as their namesake input parameters 
+
+Authors
+=======
+
+Chris Procter
diff --git a/plugins/modules/ipaconfig.py b/plugins/modules/ipaconfig.py
new file mode 100644
index 00000000..d4383adc
--- /dev/null
+++ b/plugins/modules/ipaconfig.py
@@ -0,0 +1,460 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Authors:
+#   Chris Procter <cprocter@redhat.com>
+#
+# Copyright (C) 2020 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# 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/>.
+
+ANSIBLE_METADATA = {
+    "metadata_version": "1.0",
+    "supported_by": "community",
+    "status": ["preview"],
+}
+
+
+DOCUMENTATION = '''
+---
+module: ipa_config
+author: chris procter
+short_description: Modify IPA global config options
+description:
+- Modify IPA global config options
+options:
+    ipaadmin_principal:
+        description: The admin principal
+        default: admin
+    ipaadmin_password:
+        description: The admin password
+        required: false
+    maxusername:
+        description: Set the maximum username length between 1-255
+        required: false
+        aliases: ['ipamaxusernamelength']
+    homedirectory:
+        description: Set the default location of home directories
+        required: false
+        aliases: ['ipahomesrootdir']
+    defaultshell:
+        description: Set the default shell for new users
+        required: false
+        aliases: ['ipadefaultloginshell', 'loginshell']
+    defaultgroup:
+        description: Set the default group for new users
+        required: false
+        aliases: ['ipadefaultprimarygroup']
+    emaildomain:
+        description: Set the default e-mail domain
+        required: false
+        aliases: ['ipadefaultemaildomain']
+    searchtimelimit:
+        description:
+        - Set maximum amount of time (seconds) for a search
+        - values -1 to 2147483647 (-1 or 0 is unlimited)
+        required: false
+        aliases: ['ipasearchtimelimit']
+    searchrecordslimit:
+        description:
+        - Set maximum number of records to search
+        - values -1 to 2147483647 (-1 or 0 is unlimited)
+        required: false
+        aliases: ['ipasearchrecordslimit']
+    usersearch:
+        description:
+        - Set comma-separated list of fields to search for user search
+        required: false
+        aliases: ['ipausersearchfields']
+    groupsearch:
+        description:
+        - Set comma-separated list of fields to search for group search
+        required: false
+        aliases: ['ipagroupsearchfields']
+    enable_migration:
+        description: Enable migration mode
+        type: bool
+        required: false
+        aliases: ['enable-migration','ipamigrationenabled']
+    groupobjectclasses:
+        description: Set default group objectclasses (comma-separated list)
+        required: false
+        type: list
+        aliases: ['ipagroupobjectclasses']
+    userobjectclasses:
+        description: Set default user objectclasses (comma-separated list)
+        required: false
+        type: list
+        aliases: ['ipauserobjectclasses']
+    pwdexpnotify:
+        description:
+        - Set number of days's notice of impending password expiration
+        - values 0 to 2147483647
+        required: false
+        aliases: ['ipapwdexpadvnotify']
+    configstring:
+        description: Set extra hashes to generate in password plug-in
+        required: false
+        type: list
+        choices:
+        - "AllowNThash"
+        - "KDC:Disable Last Success"
+        - "KDC:Disable Lockout"
+        - "KDC:Disable Default Preauth for SPNs"
+        aliases: ['ipaconfigstring']
+    selinuxusermaporder:
+        description: Set order in increasing priority of SELinux users
+        required: false
+        type: list
+        aliases: ['ipaselinuxusermaporder']
+    selinuxusermapdefault:
+        description: Set default SELinux user when no match found in map rule
+        required: false
+        aliases: ['ipaselinuxusermapdefault']
+    pac_type:
+        description: set default types of PAC supported for services
+        required: false
+        type: list
+        choices: ["MS-PAC", "PAD", "nfs:NONE"]
+        aliases: ["pac-type","ipakrbauthzdata"]
+    user_auth_type:
+        description: set default types of supported user authentication
+        required: false
+        type: list
+        choices: ["password", "radius", "otp", "disabled"]
+        aliases: ["user-auth_type","user-auth-type","ipauserauthtype"]
+    domain_resolution_order:
+        description: set list of domains used for short name qualification
+        required: false
+        type: list
+        aliases: ["domain-resolution_order",
+                  "domain-resolution-order",
+                  "ipadomainresolutionorder"]
+'''
+
+EXAMPLES = '''
+---
+- name: Playbook to handle global configuration options
+  hosts: ipaserver
+  become: true
+  tasks:
+    - name: return current values of the global configuration options
+      ipaconfig:
+        ipaadmin_password: password
+      register: result
+    - name: display default login shell
+      debug:
+        msg: '{{result.config.defaultshell[0] }}'
+
+    - name: set defaultshell and maxusername
+      ipaconfig:
+        ipaadmin_password: password
+        defaultshell: /bin/bash
+        maxusername: 64
+'''
+
+RETURN = '''
+config:
+  description: Dict of all global config options
+  returned: When no options are set
+  type: dict
+  options:
+    maxusername:
+        description: maximum username length
+        returned: always
+    homedirectory:
+        description: default location of home directories
+        returned: always
+    defaultshell:
+        description: default shell for new users
+        returned: always
+    defaultgroup:
+        description: default group for new users
+        returned: always
+    emaildomain:
+        description: default e-mail domain
+        returned: always
+    searchtimelimit:
+        description: maximum amount of time (seconds) for a search
+        returned: always
+    searchrecordslimit:
+        description: maximum number of records to search
+        returned: always
+    usersearch:
+        description: comma-separated list of fields to search in user search
+        type: list
+        returned: always
+    groupsearch:
+        description: comma-separated list of fields to search in group search
+        type: list
+        returned: always
+    enable_migration:
+        description: Enable migration mode
+        type: bool
+        returned: always
+    groupobjectclasses:
+        description: default group objectclasses (comma-separated list)
+        type: list
+        returned: always
+    userobjectclasses:
+        description: default user objectclasses (comma-separated list)
+        type: list
+        returned: always
+    pwdexpnotify:
+        description: number of days's notice of impending password expiration
+        returned: always
+    configstring:
+        description: extra hashes to generate in password plug-in
+        type: list
+        returned: always
+    selinuxusermaporder:
+        description: order in increasing priority of SELinux users
+        returned: always
+    selinuxusermapdefault:
+        description: default SELinux user when no match is found in map rule
+        returned: always
+    pac_type:
+        description: default types of PAC supported for services
+        type: list
+        returned: always
+    user_auth_type:
+        description: default types of supported user authentication
+        returned: always
+    domain_resolution_order:
+        description: list of domains used for short name qualification
+        returned: always
+'''
+
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
+    temp_kdestroy, valid_creds, api_connect, api_command_no_name, \
+    compare_args_ipa, module_params_get
+
+
+def config_show(module):
+    _result = api_command_no_name(module, "config_show", {})
+
+    return _result["result"]
+
+
+def gen_args(params):
+    _args = {}
+    for k, v in params.items():
+        if v is not None:
+            _args[k] = v
+
+    return _args
+
+
+def main():
+    ansible_module = AnsibleModule(
+        argument_spec=dict(
+            # general
+            ipaadmin_principal=dict(type="str", default="admin"),
+            ipaadmin_password=dict(type="str", required=False, no_log=True),
+            maxusername=dict(type="int", required=False,
+                             aliases=['ipamaxusernamelength']),
+            homedirectory=dict(type="str", required=False,
+                               aliases=['ipahomesrootdir']),
+            defaultshell=dict(type="str", required=False,
+                              aliases=['ipadefaultloginshell',
+                                       'loginshell']),
+            defaultgroup=dict(type="str", required=False,
+                              aliases=['ipadefaultprimarygroup']),
+            emaildomain=dict(type="str", required=False,
+                             aliases=['ipadefaultemaildomain']),
+            searchtimelimit=dict(type="int", required=False,
+                                 aliases=['ipasearchtimelimit']),
+            searchrecordslimit=dict(type="int", required=False,
+                                    aliases=['ipasearchrecordslimit']),
+            usersearch=dict(type="list", required=False,
+                            aliases=['ipausersearchfields']),
+            groupsearch=dict(type="list", required=False,
+                             aliases=['ipagroupsearchfields']),
+            enable_migration=dict(type="bool", required=False,
+                                  aliases=['ipamigrationenabled',
+                                           'enable-migration']),
+            groupobjectclasses=dict(type="list", required=False,
+                                    aliases=['ipagroupobjectclasses']),
+            userobjectclasses=dict(type="list", required=False,
+                                   aliases=['ipauserobjectclasses']),
+            pwdexpnotify=dict(type="int", required=False,
+                              aliases=['ipapwdexpadvnotify']),
+            configstring=dict(type="list", required=False,
+                              aliases=['ipaconfigstring'],
+                              choices=["AllowNThash",
+                                       "KDC:Disable Last Success",
+                                       "KDC:Disable Lockout",
+                                       "KDC:Disable Default Preauth for SPNs"]), # noqa E128
+            selinuxusermaporder=dict(type="list", required=False,
+                                     aliases=['ipaselinuxusermaporder']),
+            selinuxusermapdefault=dict(type="str", required=False,
+                                       aliases=['ipaselinuxusermapdefault']),
+            pac_type=dict(type="list", required=False,
+                          aliases=["ipakrbauthzdata", "pac-type"],
+                          choices=["MS-PAC", "PAD", "nfs:NONE"]),
+            user_auth_type=dict(type="list", required=False,
+                                aliases=["ipauserauthtype",
+                                         "user-auth_type",
+                                         "user-auth-type"]),
+            domain_resolution_order=dict(type="list", required=False,
+                                         aliases=["ipadomainresolutionorder",
+                                                  "domain-resolution_order",
+                                                  "domain-resolution-order"])
+        ),
+        supports_check_mode=True,
+    )
+
+    ansible_module._ansible_debug = True
+
+    # Get parameters
+
+    # general
+    ipaadmin_principal = module_params_get(ansible_module,
+                                           "ipaadmin_principal")
+    ipaadmin_password = module_params_get(ansible_module,
+                                          "ipaadmin_password")
+
+    field_map = {
+        "maxusername": "ipamaxusernamelength",
+        "homedirectory": "ipahomesrootdir",
+        "defaultshell": "ipadefaultloginshell",
+        "defaultgroup": "ipadefaultprimarygroup",
+        "emaildomain": "ipadefaultemaildomain",
+        "searchtimelimit": "ipasearchtimelimit",
+        "searchrecordslimit": "ipasearchrecordslimit",
+        "usersearch": "ipausersearchfields",
+        "groupsearch": "ipagroupsearchfields",
+        "enable_migration": "ipamigrationenabled",
+        "groupobjectclasses": "ipagroupobjectclasses",
+        "userobjectclasses": "ipauserobjectclasses",
+        "pwdexpnotify": "ipapwdexpadvnotify",
+        "configstring": "ipaconfigstring",
+        "selinuxusermaporder": "ipaselinuxusermaporder",
+        "selinuxusermapdefault": "ipaselinuxusermapdefault",
+        "pac_type": "ipakrbauthzdata",
+        "user_auth_type": "ipauserauthtype",
+        "domain_resolution_order": "ipadomainresolutionorder"
+    }
+    reverse_field_map = {v: k for k, v in field_map.items()}
+
+    params = {}
+    for x in field_map.keys():
+        val = module_params_get(ansible_module, x)
+
+        if val is not None:
+            params[field_map.get(x, x)] = val
+
+    if params.get("ipamigrationenabled") is not None:
+        params["ipamigrationenabled"] = \
+            str(params["ipamigrationenabled"]).upper()
+
+    if params.get("ipaselinuxusermaporder", None):
+        params["ipaselinuxusermaporder"] = \
+            "$".join(params["ipaselinuxusermaporder"])
+
+    if params.get("ipadomainresolutionorder", None):
+        params["ipadomainresolutionorder"] = \
+             ":".join(params["ipadomainresolutionorder"])
+
+    if params.get("ipausersearchfields", None):
+        params["ipausersearchfields"] = \
+             ",".join(params["ipausersearchfields"])
+
+    if params.get("ipagroupsearchfields", None):
+        params["ipagroupsearchfields"] = \
+             ",".join(params["ipagroupsearchfields"])
+
+    if params.get("ipamaxusernamelength", 0) > 255 \
+            or params.get("ipamaxusernamelength", 2) < 1:
+        ansible_module.fail_json(
+            msg="Argument 'maxusername' mustn range 1 to 255")
+
+    for x in ["ipasearchtimelimit",
+              "ipasearchrecordslimit",
+              "ipapwdexpadvnotify"]:
+        if params.get(x, 0) > 2147483647:
+            ansible_module.fail_json(
+                msg="Argument '%s' has a maximum value of 2147483647" % (x))
+
+    for x in ["ipasearchtimelimit", "ipasearchrecordslimit"]:
+        if params.get(x, 0) < -2147483648:
+            ansible_module.fail_json(
+                msg="Argument '%s' has  minimum value of -2147483648" % (x))
+
+    changed = False
+    exit_args = {}
+    ccache_dir = None
+    ccache_name = None
+    res_show = None
+    try:
+        if not valid_creds(ansible_module, ipaadmin_principal):
+            ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
+                                                 ipaadmin_password)
+        api_connect()
+
+        if params.keys():
+            res_show = config_show(ansible_module)
+            if not compare_args_ipa(ansible_module, params, res_show):
+                changed = True
+                api_command_no_name(ansible_module, "config_mod", params)
+
+        else:
+            rawresult = api_command_no_name(ansible_module, "config_show", {})
+            result = rawresult['result']
+            del result['dn']
+            for key, v in result.items():
+                k = reverse_field_map.get(key, key)
+                if ansible_module.argument_spec.get(k):
+                    if k == 'ipaselinuxusermaporder':
+                        exit_args['ipaselinuxusermaporder'] = \
+                            result.get(key)[0].split('$')
+                    elif k == 'domain_resolution_order':
+                        exit_args['domain_resolution_order'] = \
+                           result.get(key)[0].split('$')
+                    elif k == 'usersearch':
+                        exit_args['usersearch'] = \
+                            result.get(key)[0].split(',')
+                    elif k == 'groupsearch':
+                        exit_args['groupsearch'] = \
+                            result.get(key)[0].split(',')
+                    elif isinstance(v, str) and \
+                            ansible_module.argument_spec[k]['type'] == "list":
+                        exit_args[k] = [v]
+                    elif isinstance(v, list) and \
+                            ansible_module.argument_spec[k]['type'] == "str":
+                        exit_args[k] = ",".join(v)
+                    elif isinstance(v, list) and \
+                            ansible_module.argument_spec[k]['type'] == "int":
+                        exit_args[k] = ",".join(v)
+                    elif isinstance(v, list) and \
+                            ansible_module.argument_spec[k]['type'] == "bool":
+                        exit_args[k] = (v[0] == "TRUE")
+                    else:
+                        exit_args[k] = v
+
+    except Exception as e:
+        ansible_module.fail_json(msg="%s %s" % (params, str(e)))
+
+    finally:
+        temp_kdestroy(ccache_dir, ccache_name)
+
+    # Done
+    ansible_module.exit_json(changed=changed, config=exit_args)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/tests/config/test_config.yml b/tests/config/test_config.yml
new file mode 100644
index 00000000..81f2f4e0
--- /dev/null
+++ b/tests/config/test_config.yml
@@ -0,0 +1,143 @@
+---
+- name: Playbook to handle users
+  hosts: ipaserver
+  become: true
+  gather_facts: false
+
+  tasks:
+  - name: return current values of the global configuration options
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+    register: previousconfig
+
+  - debug:
+      msg: "{{previousconfig}}"
+
+  - name: set default shell to default value
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      defaultshell: /bin/sh
+    register: result
+    failed_when: result.changed
+
+  - name: set default shell to new value
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      defaultshell: /bin/bash
+    register: result
+    failed_when: not result.changed
+
+  - name: check default shell is changed
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      defaultshell: /bin/bash
+    register: result
+    failed_when: result.changed
+
+  - name: reset default shell to old value
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      defaultshell: '{{previousconfig.config.defaultshell }}'
+    register: result
+    failed_when: not result.changed
+
+  - name: check default shell is reset
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      defaultshell: '{{previousconfig.config.defaultshell }}'
+    register: result
+    failed_when: result.changed
+
+  - name: Ensure the default e-mail domain is ansible.com.
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      emaildomain: ansible.com
+    register: result
+    failed_when: not result.changed
+
+  - name: Ensure the default e-mail domain is set
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      emaildomain: ansible.com
+    register: result
+    failed_when: result.changed
+
+  - name: reset default e-mail domain
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      emaildomain: '{{previousconfig.config.emaildomain }}'
+    register: result
+    failed_when: not result.changed
+
+  - name: set pac-type
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      pac_type:
+        - nfs:NONE
+    register: result
+    failed_when: not result.changed
+
+  - name: reset pac-type
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      pac_type: '{{previousconfig.config.pac_type}}'
+    register: result
+    failed_when: not result.changed
+
+  - name: set usersearch
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      usersearch:
+        - uid
+    register: result
+    failed_when: not result.changed
+
+  - name: check usersearch
+    ipaconfig:
+      ipaadmin_password: SomeADMINpassword
+      usersearch:
+        - uid
+    register: result
+    failed_when: result.changed
+
+  - name: reset changed fields
+    ipaconfig:
+      ipaadmin_password: 'SomeADMINpassword'
+      configstring: '{{previousconfig.config.configstring}}'
+      emaildomain: '{{previousconfig.config.emaildomain}}'
+      defaultshell: '{{previousconfig.config.defaultshell}}'
+      defaultgroup: '{{previousconfig.config.defaultgroup}}'
+      groupsearch: '{{previousconfig.config.groupsearch}}'
+      homedirectory: '{{previousconfig.config.homedirectory}}'
+      pac_type: '{{previousconfig.config.pac_type}}'
+      maxusername: '{{previousconfig.config.maxusername}}'
+      enable_migration: '{{previousconfig.config.enable_migration}}'
+      pwdexpnotify: '{{previousconfig.config.pwdexpnotify}}'
+      searchrecordslimit: '{{previousconfig.config.searchrecordslimit}}'
+      searchtimelimit: '{{previousconfig.config.searchtimelimit}}'
+      selinuxusermapdefault: '{{previousconfig.config.selinuxusermapdefault}}'
+      selinuxusermaporder: '{{previousconfig.config.selinuxusermaporder}}'
+      usersearch: '{{previousconfig.config.usersearch}}'
+    register: result
+    failed_when: not result.changed
+
+  - name: check reset fields
+    ipaconfig:
+      ipaadmin_password: 'SomeADMINpassword'
+      configstring: '{{previousconfig.config.configstring}}'
+      emaildomain: '{{previousconfig.config.emaildomain}}'
+      defaultshell: '{{previousconfig.config.defaultshell}}'
+      defaultgroup: '{{previousconfig.config.defaultgroup}}'
+      groupsearch: '{{previousconfig.config.groupsearch}}'
+      homedirectory: '{{previousconfig.config.homedirectory}}'
+      pac_type: '{{previousconfig.config.pac_type}}'
+      maxusername: '{{previousconfig.config.maxusername}}'
+      enable_migration: '{{previousconfig.config.enable_migration}}'
+      pwdexpnotify: '{{previousconfig.config.pwdexpnotify}}'
+      searchrecordslimit: '{{previousconfig.config.searchrecordslimit}}'
+      searchtimelimit: '{{previousconfig.config.searchtimelimit}}'
+      selinuxusermapdefault: '{{previousconfig.config.selinuxusermapdefault}}'
+      selinuxusermaporder: '{{previousconfig.config.selinuxusermaporder}}'
+      usersearch: '{{previousconfig.config.usersearch}}'
+    register: result
+    failed_when: result.changed
-- 
GitLab