diff --git a/README-group.md b/README-group.md index 75b8bb54fa44fd9d6039a423dfe47cac385e58aa..05fd6054826214d561b1567cf38c6b81bb95e99e 100644 --- a/README-group.md +++ b/README-group.md @@ -8,8 +8,12 @@ The group module allows to ensure presence and absence of groups and members of The group module is as compatible as possible to the Ansible upstream `ipa_group` module, but additionally offers to add users to a group and also to remove users from a group. -## Note -Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case. + +Notes +----- + +* Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case. +* Using `externalmember` or `idoverrideuser` is only supported with `ipaapi_context: server`. With 'client' context, module execution will fail. Features @@ -213,7 +217,7 @@ Example playbook to add members from a trusted realm to an external group: --- - name: Playbook to handle groups. hosts: ipaserver - + tasks: - name: Create an external group and add members from a trust to it. ipagroup: @@ -276,6 +280,7 @@ Example playbook to ensure groups are absent: state: absent ``` + Variables ========= @@ -299,8 +304,8 @@ Variable | Description | Required `service` | List of service name strings assigned to this group. Only usable with IPA versions 4.7 and up. | no `membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no `membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no -`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no -`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up.| no +`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. Requires "server" context. | no +`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up. Requires "server" context. | no `rename` \| `new_name` | Rename the user object to the new name string. Only usable with `state: renamed`. | no `action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no `state` | The state to ensure. It can be one of `present`, `absent` or `renamed`, default: `present`. | yes diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index 3386cb8c10e64cd95a00d3bbe83530380481d083..2f861efa6b0578eb4724551b5af253fc86047897 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -589,6 +589,20 @@ def ensure_fqdn(name, domain): return name +def convert_to_sid(items): + """Convert all items to SID, if possible.""" + def get_sid(data): + try: + return get_trusted_domain_object_sid(data) + except ipalib_errors.NotFound: + return data + if items is None: + return None + if not isinstance(items, (list, tuple)): + items = [items] + return [get_sid(item) for item in items] + + def api_get_realm(): return api.env.realm @@ -903,6 +917,13 @@ def get_trusted_domain_sid_from_name(dom_name): return unicode(sid) if sid is not None else None +def get_trusted_domain_object_sid(object_name): + """Given an object name, returns de object SID.""" + domain_validator = __get_domain_validator() + sid = domain_validator.get_trusted_domain_object_sid(object_name) + return unicode(sid) if sid is not None else None + + class IPAParamMapping(Mapping): """ Provides IPA API mapping to playbook parameters or computed values. diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py index 7251fda2eb9accfe134f567739bb017bfe4c0f82..3405774132e9cfe15c64d4d4908d520de5671325 100644 --- a/plugins/modules/ipagroup.py +++ b/plugins/modules/ipagroup.py @@ -113,13 +113,14 @@ options: externalmember: description: - List of members of a trusted domain in DOM\\name or name@domain form. + Requires "server" context. required: false type: list elements: str aliases: ["ipaexternalmember", "external_member"] idoverrideuser: description: - - User ID overrides to add + - User ID overrides to add. Requires "server" context. required: false type: list elements: str @@ -188,13 +189,14 @@ options: externalmember: description: - List of members of a trusted domain in DOM\\name or name@domain form. + Requires "server" context. required: false type: list elements: str aliases: ["ipaexternalmember", "external_member"] idoverrideuser: description: - - User ID overrides to add + - User ID overrides to add. Requires "server" context. required: false type: list elements: str @@ -297,6 +299,7 @@ EXAMPLES = """ posix: yes # Create an external group and add members from a trust to it. +# Module will fail if running under 'client' context. - ipagroup: ipaadmin_password: SomeADMINpassword name: extgroup @@ -327,7 +330,8 @@ RETURN = """ from ansible.module_utils._text import to_text from ansible.module_utils.ansible_freeipa_module import \ IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \ - gen_add_list, gen_intersection_list, api_check_param + gen_add_list, gen_intersection_list, api_check_param, \ + convert_to_sid from ansible.module_utils import six if six.PY3: unicode = str @@ -562,21 +566,29 @@ def main(): # The simple solution is to switch to client context for ensuring # several groups simply if the user was not explicitly asking for # the server context no matter if mixed types are used. - context = None + context = ansible_module.params_get("ipaapi_context") if state == "present" and groups is not None and len(groups) > 1 \ and not FIX_6741_DEEPCOPY_OBJECTCLASSES: - _context = ansible_module.params_get("ipaapi_context") - if _context is None: + if context is None: context = "client" ansible_module.debug( "Switching to client context due to an unfixed issue in " "your IPA version: https://pagure.io/freeipa/issue/9349") - elif _context == "server": + elif context == "server": ansible_module.fail_json( msg="Ensuring several groups with server context is not " "supported by your IPA version: " "https://pagure.io/freeipa/issue/9349") + if ( + externalmember is not None + or idoverrideuser is not None + and context == "client" + ): + ansible_module.fail_json( + msg="Cannot use externalmember in client context." + ) + # Use groups if names is None if groups is not None: names = groups @@ -676,6 +688,23 @@ def main(): # Make sure group exists res_find = find_group(ansible_module, name) + # external members must de handled as SID + externalmember = convert_to_sid(externalmember) + + # idoverrides need to be compared through SID + idoverrideuser_sid = convert_to_sid(idoverrideuser) + res_idoverrideuser_sid = convert_to_sid( + (res_find or {}).get("member_idoverrideuser", [])) + idoverride_set = dict( + list(zip(idoverrideuser_sid or [], idoverrideuser or [])) + + list( + zip( + res_idoverrideuser_sid or [], + (res_find or {}).get("member_idoverrideuser", []) + ) + ) + ) + user_add, user_del = [], [] group_add, group_del = [], [] service_add, service_del = [], [] @@ -723,11 +752,12 @@ def main(): res_find = {} # if we just created/modified the group, update res_find - res_find.setdefault("objectclass", []) + classes = list(res_find.setdefault("objectclass", [])) if external and not is_external_group(res_find): - res_find["objectclass"].append("ipaexternalgroup") + classes.append("ipaexternalgroup") if posix and not is_posix_group(res_find): - res_find["objectclass"].append("posixgroup") + classes.append("posixgroup") + res_find["objectclass"] = classes member_args = gen_member_args( user, group, service, externalmember, idoverrideuser @@ -752,11 +782,19 @@ def main(): ) ) + # There are multiple ways to name an AD User, and any + # can be used in idoverrides, so we create the add/del + # lists based on SID, and then use the given user name + # to the idoverride. (idoverrides_add, idoverrides_del) = gen_add_del_lists( - idoverrideuser, - res_find.get("member_idoverrideuser") - ) + idoverrideuser_sid, res_idoverrideuser_sid) + idoverrides_add = [ + idoverride_set[sid] for sid in set(idoverrides_add) + ] + idoverrides_del = [ + idoverride_set[sid] for sid in set(idoverrides_del) + ] membermanager_user_add, membermanager_user_del = \ gen_add_del_lists( @@ -790,7 +828,10 @@ def main(): ) ) idoverrides_add = gen_add_list( - idoverrideuser, res_find.get("member_idoverrideuser")) + idoverrideuser_sid, res_idoverrideuser_sid) + idoverrides_add = [ + idoverride_set[sid] for sid in set(idoverrides_add) + ] membermanager_user_add = gen_add_list( membermanager_user, @@ -829,7 +870,10 @@ def main(): ) ) idoverrides_del = gen_intersection_list( - idoverrideuser, res_find.get("member_idoverrideuser")) + idoverrideuser_sid, res_idoverrideuser_sid) + idoverrides_del = [ + idoverride_set[sid] for sid in set(idoverrides_del) + ] membermanager_user_del = gen_intersection_list( membermanager_user, res_find.get("membermanager_user")) @@ -872,7 +916,7 @@ def main(): if len(externalmember_del) > 0: del_member_args["ipaexternalmember"] = \ externalmember_del - elif externalmember or external: + elif externalmember: ansible_module.fail_json( msg="Cannot add external members to a " "non-external group." diff --git a/tests/env_freeipa_facts.yml b/tests/env_freeipa_facts.yml index 280e8efa43f8ab36ba9f2770b93668618f00c813..bb8fb6747bfd1d7866b3c495ee9bd270cd132b0a 100644 --- a/tests/env_freeipa_facts.yml +++ b/tests/env_freeipa_facts.yml @@ -7,6 +7,10 @@ # ipa_api_version: The installed FreeIPA API version. # --- +- name: Ensure minimal facts are available + ansible.builtin.setup: + gather_subset: dns + - name: Retrieving FreeIPA version. ansible.builtin.shell: cmd: 'ipa --version | sed -n "s/VERSION: \([^,]*\).*API_VERSION: \([^,]*\).*/\1\\n\2/p"' @@ -15,20 +19,31 @@ - name: Verify if host is an IPA server or client. ansible.builtin.shell: cmd: | - echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin - RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa server-show `hostname` && echo SERVER || echo CLIENT) - kdestroy -A -c {{ krb5ccname }} + echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin >/dev/null + RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa server-show `hostname` >/dev/null && echo SERVER || echo CLIENT) + kdestroy -A -c {{ krb5ccname }} >/dev/null echo $RESULT vars: krb5ccname: "__check_ipa_host_is_client_or_server__" - register: output + register: check_client + +- name: Verify if AD tests are possible + ansible.builtin.shell: + cmd: | + echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin > /dev/null + RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa server-find --all | grep "Enabled server roles") + kdestroy -A -c {{ krb5ccname }} > /dev/null + echo $RESULT + vars: + krb5ccname: "__check_ipa_host_is_client_or_server__" + register: check_ad_support - name: Set FreeIPA facts. ansible.builtin.set_fact: ipa_version: "{{ ipa_cmd_version.stdout_lines[0] }}" ipa_api_version: "{{ ipa_cmd_version.stdout_lines[1] }}" - ipa_host_is_client: "{{ (output.stdout_lines[-1] == 'CLIENT') | bool }}" - trust_test_is_supported: no + ipa_host_is_client: "{{ (check_client.stdout_lines[-1] == 'CLIENT') | bool }}" + trust_test_is_supported: "{{ 'AD trust agent' in check_ad_support.stdout }}" - name: Ensure ipaserver_domain is set when: ipaserver_domain is not defined @@ -42,3 +57,8 @@ ansible.builtin.set_fact: ipaserver_domain: "ipa.test" when: "'fqdn' not in ansible_facts" + +- name: Ensure ipaserver_realm is set + ansible.builtin.set_fact: + ipaserver_realm: "{{ ipaserver_domain | upper }}" + when: ipaserver_realm is not defined diff --git a/tests/group/test_group.yml b/tests/group/test_group.yml index 72fe1d746f1ca04ceaf54607692ec8175f5c754b..2a6b635b35c88a365f07f04d8821e3b16f8d955f 100644 --- a/tests/group/test_group.yml +++ b/tests/group/test_group.yml @@ -1,8 +1,8 @@ --- - name: Test group hosts: "{{ ipa_test_host | default('ipaserver') }}" - become: true - gather_facts: true + become: false + gather_facts: false module_defaults: ipauser: ipaadmin_password: SomeADMINpassword @@ -10,6 +10,9 @@ ipagroup: ipaadmin_password: SomeADMINpassword ipaapi_context: "{{ ipa_context | default(omit) }}" + ipaservice: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" tasks: # setup @@ -51,6 +54,16 @@ register: result failed_when: not result.changed or result.failed + - name: Ensure test service HTTP is present + ipaservice: + name: "{{ 'HTTP/' + fqdn_at_domain }}" + notify: Cleanup http service + + - name: Ensure test service LDAP is present + ipaservice: + name: "{{ 'ldap/' + fqdn_at_domain }}" + notify: Cleanup ldap service + # TESTS - name: Ensure group1 is present @@ -437,3 +450,16 @@ state: absent register: result failed_when: not result.changed or result.failed + + # ansible-lint is complaining on the use of 'when' and requiring + # the use of handlers. + handlers: + - name: Cleanup http service + ipaservice: + name: "{{ 'HTTP/' + fqdn_at_domain }}" + state: absent + + - name: Cleanup ldap service + ipaservice: + name: "{{ 'ldap/' + fqdn_at_domain }}" + state: absent diff --git a/tests/group/test_group_ad_users.yml b/tests/group/test_group_ad_users.yml new file mode 100644 index 0000000000000000000000000000000000000000..0c84db6c25e4a3eaec6854f39dc209ba898f04d3 --- /dev/null +++ b/tests/group/test_group_ad_users.yml @@ -0,0 +1,73 @@ +--- +- name: Test group AD external members idempotence + hosts: ipaserver + become: false + gather_facts: false + module_defaults: + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: server # external_member requires 'server' context + + vars: + ad_user: "{{ test_ad_user | default('AD\\aduser') }}" + alt_user: "{{ test_alt_user | default('aduser@ad.ipa.test') }}" + + tasks: + - name: Include tasks ../env_freeipa_facts.yml + ansible.builtin.include_tasks: ../env_freeipa_facts.yml + + - name: Ensure test group is absent. + ipagroup: + name: extgroup + state: absent + + - name: Execute group tests if trust test environment is supported + when: trust_test_is_supported | default(false) + block: + - name: Ensure external group, with AD users, is present. + ipagroup: + name: extgroup + external: true + external_member: "{{ ad_user }}" + register: result + failed_when: result.failed or not result.changed + + - name: Ensure external group, with AD users, is present, again + ipagroup: + name: extgroup + external: true + external_member: "{{ ad_user }}" + register: result + failed_when: result.failed or result.changed + + - name: Ensure external group, with alternate name AD users, is present + ipagroup: + name: extgroup + external: true + external_member: "{{ alt_user }}" + register: result + failed_when: result.failed or result.changed + + - name: Ensure external_member is absent + ipagroup: + name: extgroup + external_member: "{{ ad_user }}" + action: member + state: absent + register: result + failed_when: result.failed or not result.changed + + - name: Ensure external_member is absent, again + ipagroup: + name: extgroup + external_member: "{{ alt_user }}" + action: member + state: absent + register: result + failed_when: result.failed or result.changed + + always: + - name: Cleanup environment. + ipagroup: + name: extgroup + state: absent diff --git a/tests/group/test_group_client_context.yml b/tests/group/test_group_client_context.yml index 8d0132def01dd7b1c42212b4b0673e911139b162..add34b6b08d51aec73e229127b54ee15131936e1 100644 --- a/tests/group/test_group_client_context.yml +++ b/tests/group/test_group_client_context.yml @@ -4,6 +4,9 @@ become: no gather_facts: no + vars: + ad_user: "{{ test_ad_user | default('AD\\aduser') }}" + tasks: - name: Include FreeIPA facts. ansible.builtin.include_tasks: ../env_freeipa_facts.yml @@ -18,6 +21,16 @@ failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*")) when: ipa_host_is_client + - name: Ensuref fail if externalmember is used in client context. + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: client + name: ThisShouldNotWork + external_member: "{{ ad_user }}" + external: true + register: result + failed_when: not (result.failed and result.msg == "Cannot use externalmember in client context.") + # Import basic module tests, and execute with ipa_context set to 'client'. # If ipaclients is set, it will be executed using the client, if not, # ipaserver will be used. diff --git a/tests/group/test_group_external_members.yml b/tests/group/test_group_external_members.yml index f9214d3dfd451c532598b976ad7d045837a0129b..b1f9f85d1d77ab0671f5260b4fe9398ae41b894d 100644 --- a/tests/group/test_group_external_members.yml +++ b/tests/group/test_group_external_members.yml @@ -1,12 +1,16 @@ --- -- name: Find trust - hosts: ipaserver +- name: Test groups with external members + hosts: "{{ ipa_test_host | default('ipaserver') }}" become: false gather_facts: false module_defaults: ipagroup: ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" + ipaapi_context: server # external_member requires 'server' context + + vars: + ad_user: "{{ test_ad_user | default('AD\\aduser') }}" + alt_user: "{{ test_alt_user | default('aduser@ad.ipa.test') }}" tasks: @@ -24,86 +28,121 @@ when: trust_test_is_supported | default(false) block: - - name: Add nonposix group. + - name: Ensure nonposix group is present ipagroup: name: extgroup nonposix: true register: result failed_when: result.failed or not result.changed - - name: Set group to be external + - name: Ensure nonposix group is present, again + ipagroup: + name: extgroup + nonposix: true + register: result + failed_when: result.failed or result.changed + + - name: Ensure nonposix group is external ipagroup: name: extgroup external: true register: result failed_when: result.failed or not result.changed - - name: Add AD users to group + - name: Ensure nonposix group has AD users ipagroup: name: extgroup - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or not result.changed - - name: Add AD users to group, again + - name: Ensure nonposix group has AD users, again ipagroup: name: extgroup - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or result.changed - - name: Remove external group + - name: Ensure nonposix group is absent. ipagroup: name: extgroup state: absent register: result failed_when: result.failed or not result.changed - - name: Add nonposix, external group, with AD users. + - name: Ensure nonposix group is absent, again. + ipagroup: + name: extgroup + state: absent + register: result + failed_when: result.failed or result.changed + + - name: Ensure external group is present, with AD users. ipagroup: name: extgroup - nonposix: true external: true - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or not result.changed - - name: Add nonposix, external group, with AD users, again. + - name: Ensure external group is present, with AD alternate users. + ipagroup: + name: extgroup + external: true + external_member: "{{ alt_user }}" + register: result + failed_when: result.failed or result.changed + + - name: Ensure external group is present, with AD users, again. ipagroup: name: extgroup - nonposix: true external: true - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or result.changed - - name: Remove group + - name: Ensure external group is absent ipagroup: name: extgroup state: absent register: result failed_when: result.failed or not result.changed - - name: Add nonposix group. + - name: Ensure external group is absent, again + ipagroup: + name: extgroup + state: absent + register: result + failed_when: result.failed or result.changed + + - name: Ensure nonposix group is present. ipagroup: name: extgroup nonposix: true register: result failed_when: result.failed or not result.changed - - name: Set group to be external, and add users. + - name: Ensure group is external, and has AD users. ipagroup: name: extgroup external: true - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or not result.changed - - name: Set group to be external, and add users, again. + - name: Ensure group is external, and has AD alternate users. + ipagroup: + name: extgroup + external: true + external_member: "{{ alt_user }}" + register: result + failed_when: result.failed or result.changed + + - name: Ensure group is external, and has AD users, again. ipagroup: name: extgroup external: true - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" register: result failed_when: result.failed or result.changed @@ -117,7 +156,7 @@ - name: Ensure external group members are present ipagroup: name: extgroup_members - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" action: member register: result failed_when: result.failed or not result.changed @@ -125,7 +164,7 @@ - name: Ensure external group members are present, again ipagroup: name: extgroup_members - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" action: member register: result failed_when: result.failed or result.changed @@ -133,16 +172,25 @@ - name: Ensure external group members are absent ipagroup: name: extgroup_members - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" action: member state: absent register: result failed_when: result.failed or not result.changed + - name: Ensure external group alternate members are absent + ipagroup: + name: extgroup_members + external_member: "{{ alt_user }}" + action: member + state: absent + register: result + failed_when: result.failed or result.changed + - name: Ensure external group members are absent, again ipagroup: name: extgroup_members - external_member: "AD\\Domain Users" + external_member: "{{ ad_user }}" action: member state: absent register: result diff --git a/tests/group/test_group_idoverrideuser.yml b/tests/group/test_group_idoverrideuser.yml index ce4c0bb4eea2e8ad3308a05c3ed091c0a341ed3c..2b028919b84280311397068818ad5f87b46af8ee 100644 --- a/tests/group/test_group_idoverrideuser.yml +++ b/tests/group/test_group_idoverrideuser.yml @@ -1,12 +1,17 @@ --- -- name: Test group +- name: Test group idoverrideuser hosts: ipaserver - become: yes - gather_facts: yes + become: false + gather_facts: false + module_defaults: + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword vars: - ad_user: "{{ test_ad_user | default('AD\\aduser') }}" - ad_domain: "{{ test_ad_domain | default('ad.ipa.test') }}" + ad_user: "{{ test_ad_user | default('AD\\aduser') }}" + alt_user: "{{ test_alt_user | default('aduser@ad.ipa.test') }}" tasks: - name: Include tasks ../env_freeipa_facts.yml @@ -15,38 +20,42 @@ - name: Execute tests if ipa_verison >= 4.8.7 and trust test environment is supported when: ipa_version is version("4.8.7", ">=") and trust_test_is_supported | default(false) block: - - name: Create idoverrideuser. - ansible.builtin.shell: | - kinit -c idoverride_cache admin <<< SomeADMINpassword - ipa idoverrideuser-add "Default Trust View" {{ ad_user }} - kdestroy -A -q -c idoverride_cache + - name: Ensure test idoverrideuser is present + ipaidoverrideuser: + idview: "Default Trust View" + anchor: "{{ ad_user }}" + register: result + failed_when: result.failed and "no modifications to be performed" not in result.msg - - name: Remove testing groups. + - name: Ensure test groups are absent ipagroup: - ipaadmin_password: SomeADMINpassword name: - - idovergroup + - idovergroup state: absent - - name: Add group with idoverrideuser. + - name: Ensure group with idoverrideuser is present. ipagroup: - ipaadmin_password: SomeADMINpassword name: idovergroup idoverrideuser: "{{ ad_user }}" register: result failed_when: result.failed or not result.changed - - name: Add group with idoverrideuser, again. + - name: Ensure group with idoverrideuser is present, again. ipagroup: - ipaadmin_password: SomeADMINpassword name: idovergroup idoverrideuser: "{{ ad_user }}" register: result failed_when: result.failed or result.changed - - name: Remove idoverrideuser member. + - name: Ensure group with alternative idoverrideuser is present. + ipagroup: + name: idovergroup + idoverrideuser: "{{ alt_user }}" + register: result + failed_when: result.failed or result.changed + + - name: Ensure idoverrideuser member is absent. ipagroup: - ipaadmin_password: SomeADMINpassword name: idovergroup idoverrideuser: "{{ ad_user }}" action: member @@ -54,9 +63,8 @@ register: result failed_when: result.failed or not result.changed - - name: Remove idoverrideuser member, again. + - name: Ensure idoverrideuser member is absent, again. ipagroup: - ipaadmin_password: SomeADMINpassword name: idovergroup idoverrideuser: "{{ ad_user }}" action: member @@ -64,7 +72,7 @@ register: result failed_when: result.failed or result.changed - - name: Add idoverrideuser member. + - name: Ensure idoverrideuser member is present. ipagroup: ipaadmin_password: SomeADMINpassword name: idovergroup @@ -73,7 +81,7 @@ register: result failed_when: result.failed or not result.changed - - name: Add idoverrideuser member, again. + - name: Ensure idoverrideuser member is present, again. ipagroup: ipaadmin_password: SomeADMINpassword name: idovergroup @@ -82,13 +90,7 @@ register: result failed_when: result.failed or result.changed - - name: Cleanup idoverrideuser member. - ipagroup: - ipaadmin_password: SomeADMINpassword - name: idovergroup - idoverrideuser: "{{ ad_user }}" - state: absent - + always: - name: Remove testing groups. ipagroup: ipaadmin_password: SomeADMINpassword @@ -96,10 +98,9 @@ - idovergroup state: absent - always: - name: Remove idoverrideuser. - ansible.builtin.shell: - cmd: | - kinit -c idoverride_cache admin <<< SomeADMINpassword - ipa idoverrideuser-del "Default Trust View" {{ ad_user }} - kdestroy -A -q -c idoverride_cache + ipaidoverrideuser: + idview: "Default Trust View" + anchor: "{{ ad_user }}" + continue: true + state: absent