From 0e0bdf1f52263c2d47f9356d4be29f0a810d7cb3 Mon Sep 17 00:00:00 2001 From: Mark Hahl <mhahl@redhat.com> Date: Fri, 11 Sep 2020 07:33:51 +1000 Subject: [PATCH] New automember management module There is a new automember management module placed in the plugins folder: plugins/modules/ipaautomember.py The automember module allows to ensure presence or absence of automember rules and manage automember rule conditions. Here is the documentation for the module: README-automember.md New example playbooks have been added: playbooks/automember/automember-group-absent.yml playbooks/automember/automember-group-present.yml playbooks/automember/automember-hostgroup-absent.yml playbooks/automember/automember-hostgroup-present.yml playbooks/automember/automember-hostgroup-rule-absent.yml playbooks/automember/automember-hostgroup-rule-present.yml New tests for the module: tests/automember/test_automember.yml --- README-automember.md | 136 ++++++ README.md | 2 + .../automember/automember-group-absent.yml | 11 + .../automember/automember-group-present.yml | 11 + .../automember-hostgroup-absent.yml | 11 + .../automember-hostgroup-present.yml | 11 + .../automember-hostgroup-rule-absent.yml | 15 + .../automember-hostgroup-rule-present.yml | 15 + plugins/modules/ipaautomember.py | 397 ++++++++++++++++++ tests/automember/test_automember.yml | 311 ++++++++++++++ 10 files changed, 920 insertions(+) create mode 100644 README-automember.md create mode 100644 playbooks/automember/automember-group-absent.yml create mode 100644 playbooks/automember/automember-group-present.yml create mode 100644 playbooks/automember/automember-hostgroup-absent.yml create mode 100644 playbooks/automember/automember-hostgroup-present.yml create mode 100644 playbooks/automember/automember-hostgroup-rule-absent.yml create mode 100644 playbooks/automember/automember-hostgroup-rule-present.yml create mode 100644 plugins/modules/ipaautomember.py create mode 100644 tests/automember/test_automember.yml diff --git a/README-automember.md b/README-automember.md new file mode 100644 index 00000000..8a4ebd27 --- /dev/null +++ b/README-automember.md @@ -0,0 +1,136 @@ +Automember module +=========== + +Description +----------- + +The automember module allows to ensure presence or absence of automember rules and manage automember rule conditions. + +Features +-------- + +* Automember management + + +Supported FreeIPA Versions +-------------------------- + +FreeIPA versions 4.4.0 and up are supported by the ipaautomember 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 make sure group automember rule is present with no conditions. + +```yaml +--- +- name: Playbook to ensure a group automember rule is present with no conditions + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + description: "my automember rule" + automember_type: group +``` + +Example playbook to make sure group automember rule is present with conditions: + +```yaml +--- +- name: Playbook to add a group automember rule with two conditions + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + description: "my automember rule" + automember_type: group + inclusive: + - key: mail + expression: '@example.com$' + exclusive: + - key: uid + expression: "1234" +``` + +Example playbook to delete a group automember rule: + +```yaml +- name: Playbook to delete a group automember rule + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + description: "my automember rule" + automember_type: group + state: absent +``` + +Example playbook to add an inclusive condition to an existing rule + +```yaml +- name: Playbook to add an inclusive condition to an existing rule + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + name: "My domain hosts" + description: "my automember condition" + automember_tye: hostgroup + action: member + inclusive: + - key: fqdn + expression: ".*.mydomain.com" +``` + + +Variables +--------- + +ipaautomember +------- + +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 +`name` \| `cn` | Automember rule. | yes +`description` | A description of this auto member rule. | no +`automember_type` | Grouping to which the rule applies. It can be one of `group`, `hostgroup`. | yes +`inclusive` | List of dictionaries in the format of `{'key': attribute, 'expression': inclusive_regex}` | no +`exclusive` | List of dictionaries in the format of `{'key': attribute, 'expression': exclusive_regex}` | no +`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no + + +Authors +======= + +Mark Hahl diff --git a/README.md b/README.md index 29f9d89c..fe8be14c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Features * One-time-password (OTP) support for client installation * Repair mode for clients * Backup and restore, also to and from controller +* Modules for automembership rule management * Modules for config management * Modules for delegation management * Modules for dns config management @@ -422,6 +423,7 @@ Roles Modules in plugin/modules ========================= +* [ipaautomember](README-automember.md) * [ipaconfig](README-config.md) * [ipadelegation](README-delegation.md) * [ipadnsconfig](README-dnsconfig.md) diff --git a/playbooks/automember/automember-group-absent.yml b/playbooks/automember/automember-group-absent.yml new file mode 100644 index 00000000..853fd2dc --- /dev/null +++ b/playbooks/automember/automember-group-absent.yml @@ -0,0 +1,11 @@ +--- +- name: Automember group absent example + hosts: ipaserver + become: true + tasks: + - name: Ensure group automember rule admins is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + automember_type: group + state: absent diff --git a/playbooks/automember/automember-group-present.yml b/playbooks/automember/automember-group-present.yml new file mode 100644 index 00000000..a62532ad --- /dev/null +++ b/playbooks/automember/automember-group-present.yml @@ -0,0 +1,11 @@ +--- +- name: Automember group present example + hosts: ipaserver + become: true + tasks: + - name: Ensure group automember rule admins is present + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + automember_type: group + state: present diff --git a/playbooks/automember/automember-hostgroup-absent.yml b/playbooks/automember/automember-hostgroup-absent.yml new file mode 100644 index 00000000..5afeb583 --- /dev/null +++ b/playbooks/automember/automember-hostgroup-absent.yml @@ -0,0 +1,11 @@ +--- +- name: Automember hostgroup absent example + hosts: ipaserver + become: true + tasks: + - name: Ensure hostgroup automember rule ipaservers is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: ipaservers + automember_type: hostgroup + state: absent diff --git a/playbooks/automember/automember-hostgroup-present.yml b/playbooks/automember/automember-hostgroup-present.yml new file mode 100644 index 00000000..05eb7e41 --- /dev/null +++ b/playbooks/automember/automember-hostgroup-present.yml @@ -0,0 +1,11 @@ +--- +- name: Automember hostgroup present example + hosts: ipaserver + become: true + tasks: + - name: Ensure hostgroup automember rule ipaservers is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: ipaservers + automember_type: hostgroup + state: present diff --git a/playbooks/automember/automember-hostgroup-rule-absent.yml b/playbooks/automember/automember-hostgroup-rule-absent.yml new file mode 100644 index 00000000..34e90a64 --- /dev/null +++ b/playbooks/automember/automember-hostgroup-rule-absent.yml @@ -0,0 +1,15 @@ +--- +- name: Automember hostgroup rule member absent example + hosts: ipaserver + become: true + tasks: + - name: Ensure hostgroup automember condition is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: "My domain hosts" + automember_type: hostgroup + state: absent + action: member + inclusive: + - key: fqdn + expression: ".*.mydomain.com" diff --git a/playbooks/automember/automember-hostgroup-rule-present.yml b/playbooks/automember/automember-hostgroup-rule-present.yml new file mode 100644 index 00000000..c71890a8 --- /dev/null +++ b/playbooks/automember/automember-hostgroup-rule-present.yml @@ -0,0 +1,15 @@ +--- +- name: Automember hostgroup rule member present example + hosts: ipaserver + become: true + tasks: + - name: Ensure hostgroup automember condition is present + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: "My domain hosts" + automember_type: hostgroup + state: present + action: member + inclusive: + - key: fqdn + expression: ".*.mydomain.com" diff --git a/plugins/modules/ipaautomember.py b/plugins/modules/ipaautomember.py new file mode 100644 index 00000000..bef175fd --- /dev/null +++ b/plugins/modules/ipaautomember.py @@ -0,0 +1,397 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Mark Hahl <mhahl@redhat.com> +# Jake Reynolds <jakealexis@gmail.com> +# +# Copyright (C) 2021 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/>. + + +from ansible.module_utils._text import to_text +from ansible.module_utils.ansible_freeipa_module import ( + api_command, api_command_no_name, api_connect, compare_args_ipa, + gen_add_del_lists, temp_kdestroy, temp_kinit, valid_creds, + ipalib_errors +) +from ansible.module_utils.basic import AnsibleModule + +ANSIBLE_METADATA = { + "metadata_version": "1.0", + "supported_by": "community", + "status": ["preview"], +} + + +DOCUMENTATION = """ +--- +module: ipaautomember +short description: Add and delete FreeIPA Auto Membership Rules. +description: Add, modify and delete an IPA Auto Membership Rules. +options: + ipaadmin_principal: + description: The admin principal + default: admin + ipaadmin_password: + description: The admin password + required: false + name: + description: The automember rule + required: true + aliases: ["cn"] + description: + description: A description of this auto member rule + required: false + automember_type: + description: Grouping to which the rule applies + required: true + type: str + choices: ["group", "hostgroup"] + exclusive: + description: List of dictionaries containing the attribute and expression. + type: list + elements: dict + aliases: ["automemberexclusiveregex"] + inclusive: + description: List of dictionaries containing the attribute and expression. + type: list + elements: dict + aliases: ["automemberinclusiveregex"] + action: + description: Work on service or member level + default: service + choices: ["member", "service"] + state: + description: State to ensure + default: present + choices: ["present", "absent"] +author: + - Mark Hahl + - Jake Reynolds +""" + +EXAMPLES = """ +# Ensure an automember rule exists +- ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + description: "example description" + automember_type: group + state: present + inclusive: + - key: "mail" + expression: "example.com$ + +# Delete an automember rule +- ipaautomember: + ipaadmin_password: SomeADMINpassword + name: admins + description: "my automember rule" + automember_type: group + state: absent + +# Add an inclusive condition to an existing rule +- ipaautomember: + ipaadmin_password: SomeADMINpassword + name: "My domain hosts" + automember_tye: hostgroup + action: member + inclusive: + - key: fqdn + expression: ".*.mydomain.com" + +""" + +RETURN = """ +""" + + +def find_automember(module, name, grouping): + _args = { + "all": True, + "type": to_text(grouping) + } + + try: + _result = api_command(module, "automember_show", to_text(name), _args) + except ipalib_errors.NotFound: + return None + return _result["result"] + + +def gen_condition_args(grouping, + key, + inclusiveregex=None, + exclusiveregex=None): + _args = {} + if grouping is not None: + _args['type'] = to_text(grouping) + if key is not None: + _args['key'] = to_text(key) + if inclusiveregex is not None: + _args['automemberinclusiveregex'] = to_text(inclusiveregex) + if exclusiveregex is not None: + _args['automemberexclusiveregex'] = to_text(exclusiveregex) + + return _args + + +def gen_args(description, grouping): + _args = {} + if description is not None: + _args["description"] = to_text(description) + if grouping is not None: + _args['type'] = to_text(grouping) + + return _args + + +def transform_conditions(conditions): + """Transform a list of dicts into a list with the format of key=value.""" + transformed = ['%s=%s' % (condition['key'], condition['expression']) + for condition in conditions] + return transformed + + +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), + + inclusive=dict(type="list", aliases=[ + "automemberinclusiveregex"], default=None), + exclusive=dict(type="list", aliases=[ + "automemberexclusiveregex"], default=None), + name=dict(type="list", aliases=["cn"], + default=None, required=True), + description=dict(type="str", default=None), + automember_type=dict(type='str', required=False, + choices=['group', 'hostgroup']), + action=dict(type="str", default="service", + choices=["member", "service"]), + state=dict(type="str", default="present", + choices=["present", "absent", "rebuild"]), + users=dict(type="list", default=None), + hosts=dict(type="list", default=None), + ), + supports_check_mode=True, + ) + + ansible_module._ansible_debug = True + + # Get parameters + + # general + ipaadmin_principal = ansible_module.params.get("ipaadmin_principal") + ipaadmin_password = ansible_module.params.get("ipaadmin_password") + names = ansible_module.params.get("name") + + # present + description = ansible_module.params.get("description") + + # conditions + inclusive = ansible_module.params.get("inclusive") + exclusive = ansible_module.params.get("exclusive") + + # action + action = ansible_module.params.get("action") + # state + state = ansible_module.params.get("state") + + # grouping/type + automember_type = ansible_module.params.get("automember_type") + + rebuild_users = ansible_module.params.get("users") + rebuild_hosts = ansible_module.params.get("hosts") + + if (rebuild_hosts or rebuild_users) and state != "rebuild": + ansible_module.fail_json( + msg="'hosts' and 'users' are only valid with state: rebuild") + if not automember_type and state != "rebuild": + ansible_module.fail_json( + msg="'automember_type' is required unless state: rebuild") + + # Init + changed = False + exit_args = {} + ccache_dir = None + ccache_name = None + res_find = None + + try: + if not valid_creds(ansible_module, ipaadmin_principal): + ccache_dir, ccache_name = temp_kinit(ipaadmin_principal, + ipaadmin_password) + api_connect() + + commands = [] + + for name in names: + # Make sure automember rule exists + res_find = find_automember(ansible_module, name, automember_type) + + # Create command + if state == 'present': + args = gen_args(description, automember_type) + + if action == "service": + if res_find is not None: + if not compare_args_ipa(ansible_module, + args, + res_find, + ignore=['type']): + commands.append([name, 'automember_mod', args]) + else: + commands.append([name, 'automember_add', args]) + res_find = {} + + inclusive_add, inclusive_del = gen_add_del_lists( + transform_conditions(inclusive or []), + res_find.get("automemberinclusiveregex", []) + ) + + exclusive_add, exclusive_del = gen_add_del_lists( + transform_conditions(exclusive or []), + res_find.get("automemberexclusiveregex", []) + ) + + elif action == "member": + if res_find is None: + ansible_module.fail_json(msg="No service '%s'" % name) + + inclusive_add = transform_conditions(inclusive or []) + inclusive_del = [] + exclusive_add = transform_conditions(exclusive or []) + exclusive_del = [] + + for _inclusive in inclusive_add: + key, regex = _inclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, inclusiveregex=regex) + commands.append([name, 'automember_add_condition', + condition_args]) + + for _inclusive in inclusive_del: + key, regex = _inclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, inclusiveregex=regex) + commands.append([name, 'automember_remove_condition', + condition_args]) + + for _exclusive in exclusive_add: + key, regex = _exclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, exclusiveregex=regex) + commands.append([name, 'automember_add_condition', + condition_args]) + + for _exclusive in exclusive_del: + key, regex = _exclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, exclusiveregex=regex) + commands.append([name, 'automember_remove_condition', + condition_args]) + + elif state == 'absent': + if action == "service": + if res_find is not None: + commands.append([name, 'automember_del', + {'type': to_text(automember_type)}]) + + elif action == "member": + if res_find is None: + ansible_module.fail_json(msg="No service '%s'" % name) + + if inclusive is not None: + for _inclusive in transform_conditions(inclusive): + key, regex = _inclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, inclusiveregex=regex) + commands.append( + [name, 'automember_remove_condition', + condition_args]) + + if exclusive is not None: + for _exclusive in transform_conditions(exclusive): + key, regex = _exclusive.split("=", 1) + condition_args = gen_condition_args( + automember_type, key, exclusiveregex=regex) + commands.append([name, + 'automember_remove_condition', + condition_args]) + + elif state == "rebuild": + if automember_type: + commands.append([None, 'automember_rebuild', + {"type": to_text(automember_type)}]) + if rebuild_users: + commands.append([None, 'automember_rebuild', + {"users": [ + to_text(_u) + for _u in rebuild_users]}]) + if rebuild_hosts: + commands.append([None, 'automember_rebuild', + {"hosts": [ + to_text(_h) + for _h in rebuild_hosts]}]) + + # Check mode exit + if ansible_module.check_mode: + ansible_module.exit_json(changed=len(commands) > 0, **exit_args) + + errors = [] + for name, command, args in commands: + try: + if name is None: + result = api_command_no_name(ansible_module, command, args) + else: + result = api_command(ansible_module, command, + to_text(name), args) + + if "completed" in result: + if result["completed"] > 0: + changed = True + else: + changed = True + except Exception as ex: + ansible_module.fail_json(msg="%s: %s: %s" % (command, name, + str(ex))) + # Get all errors + if "failed" in result and len(result["failed"]) > 0: + for item in result["failed"]: + failed_item = result["failed"][item] + for member_type in failed_item: + for member, failure in failed_item[member_type]: + errors.append("%s: %s %s: %s" % ( + command, member_type, member, failure)) + if len(errors) > 0: + ansible_module.fail_json(msg=", ".join(errors)) + + except Exception as e: + ansible_module.fail_json(msg=str(e)) + + finally: + temp_kdestroy(ccache_dir, ccache_name) + + # Done + ansible_module.exit_json(changed=changed, **exit_args) + + +if __name__ == "__main__": + main() diff --git a/tests/automember/test_automember.yml b/tests/automember/test_automember.yml new file mode 100644 index 00000000..96b8c287 --- /dev/null +++ b/tests/automember/test_automember.yml @@ -0,0 +1,311 @@ +--- +- name: Test automember + hosts: ipaserver + become: true + + tasks: + + # CLEANUP TEST ITEMS + + - name: Ensure group testgroup is absent + ipagroup: + ipaadmin_password: SomeADMINpassword + name: testgroup + state: absent + + - name: Ensure hostgroup testhostgroup is absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + state: absent + + - name: Ensure group automember rule testgroup is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + state: absent + automember_type: group + + - name: Ensure hostgroup automember rule testhostgroup is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + state: absent + automember_type: hostgroup + + # CREATE TEST ITEMS + + # TESTS + - name: Ensure testgroup group is present + ipagroup: + ipaadmin_password: SomeADMINpassword + name: testgroup + + - name: Ensure testhostgroup hostgroup is present + ipahostgroup: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + + - name: Ensure testgroup group automember rule is present + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + description: testgroup automember rule. + automember_type: group + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testgroup group automember rule is present again + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + description: testgroup automember rule. + automember_type: group + register: result + failed_when: result.changed or result.failed + + - name: Change testgroup group automember rule description + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + description: testgroup automember rule description. + automember_type: group + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testgroup group automember rule has conditions + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + inclusive: + - key: 'uid' + expression: 'uid' + - key: 'uidnumber' + expression: 'uidnumber' + exclusive: + - key: 'uid' + expression: 'uid' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testgroup group automember rule has conditions again + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + inclusive: + - key: 'uid' + expression: 'uid' + - key: 'uidnumber' + expression: 'uidnumber' + exclusive: + - key: 'uid' + expression: 'uid' + register: result + failed_when: result.changed or result.failed + + - name: Add testgroup group automember rule member condition + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + action: member + inclusive: + - key: 'manager' + expression: 'uid=mscott' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testgroup group automember rule has conditions + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + inclusive: + - key: 'uid' + expression: 'uid' + - key: 'uidnumber' + expression: 'uidnumber' + - key: 'manager' + expression: 'uid=mscott' + exclusive: + - key: 'uid' + expression: 'uid' + register: result + failed_when: result.changed or result.failed + + - name: Remove testgroup group automember rule member condition + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + action: member + state: absent + inclusive: + - key: 'manager' + expression: 'uid=mscott' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testgroup group automember rule has conditions again + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testgroup + automember_type: group + inclusive: + - key: 'uid' + expression: 'uid' + - key: 'uidnumber' + expression: 'uidnumber' + exclusive: + - key: 'uid' + expression: 'uid' + register: result + failed_when: result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule is present + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + description: testhostgroup automember rule + automember_type: hostgroup + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule is present again + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + description: testhostgroup automember rule + automember_type: hostgroup + register: result + failed_when: result.changed or result.failed + + - name: Change testhostgroup hostgroup automember rule description + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + description: testhostgroup test automember rule + automember_type: hostgroup + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule has conditions + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + inclusive: + - key: 'description' + expression: 'description' + - key: 'description' + expression: 'description' + exclusive: + - key: 'cn' + expression: 'cn' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule has conditions again + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + inclusive: + - key: 'description' + expression: 'description' + - key: 'description' + expression: 'description' + exclusive: + - key: 'cn' + expression: 'cn' + register: result + failed_when: result.changed or result.failed + + - name: Add testhostgroup hostgroup automember rule member condition + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + action: member + inclusive: + - key: 'fqdn' + expression: '.*.domain.com' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule has conditions + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + inclusive: + - key: 'description' + expression: 'description' + - key: 'description' + expression: 'description' + - key: 'fqdn' + expression: '.*.domain.com' + exclusive: + - key: 'cn' + expression: 'cn' + register: result + failed_when: result.changed or result.failed + + - name: Remove testhostgroup hostgroup automember rule member condition + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + action: member + state: absent + inclusive: + - key: 'fqdn' + expression: '.*.domain.com' + register: result + failed_when: not result.changed or result.failed + + - name: Ensure testhostgroup hostgroup automember rule has conditions + ipaautomember: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + automember_type: hostgroup + inclusive: + - key: 'description' + expression: 'description' + - key: 'description' + expression: 'description' + exclusive: + - key: 'cn' + expression: 'cn' + register: result + failed_when: result.changed or result.failed + + # CLEANUP TEST ITEMS + + - name: Ensure group testgroup is absent + ipagroup: + ipaadmin_password: SomeADMINpassword + name: testgroup + state: absent + + - name: Ensure hostgroup testhostgroup is absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword + name: testhostgroup + state: absent + + - name: Ensure group automember rule testgroup is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: group + name: testgroup + state: absent + + - name: Ensure hostgroup automember rule testhostgroup is absent + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + name: testhostgroup + state: absent -- GitLab