From 8a93627079643fc800097f72f8a225c2126ed051 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 11 Nov 2021 17:18:37 -0300 Subject: [PATCH 1/9] iparole: Removed unused code. There was some unused code that was removed. --- plugins/modules/iparole.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index 75500d3c..d5b13491 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -298,34 +298,6 @@ def ensure_role_with_members_is_present(module, name, res_find, action): return commands -def ensure_members_are_present(module, name, res_find): - """Define commands to ensure members are present for action `member`.""" - commands = [] - - members = member_difference( - module, 'privilege', 'memberof_privilege', res_find) - if members: - commands.append([name, "role_add_privilege", - {"privilege": members}]) - - member_args = {} - for key in ['user', 'group', 'host', 'hostgroup']: - items = member_difference( - module, key, 'member_%s' % key, res_find) - if items: - member_args[key] = items - - _services = filter_service(module, res_find, - lambda res, svc: not res.startswith(svc)) - if _services: - member_args['service'] = _services - - if member_args: - commands.append([name, "role_add_member", member_args]) - - return commands - - # pylint: disable=unused-argument def result_handler(module, result, command, name, args, errors): """Process the result of a command, looking for errors.""" From 13d7d714d75c8e7f317d2dedd85beefb4fcd529c Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 11 Nov 2021 17:45:03 -0300 Subject: [PATCH 2/9] iparole: Remove custom code in favor of commom functions. Removed custom code used to create add/del lists in iparole in favor of ansible_freeipa_module functions, and custom result_handler, to reduce code duplication, as these methods have equivalent shared versions. --- plugins/modules/iparole.py | 61 ++++++++------------------------------ 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index d5b13491..0f2a0805 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -103,10 +103,10 @@ EXAMPLES = """ # pylint: disable=no-name-in-module from ansible.module_utils._text import to_text from ansible.module_utils.ansible_freeipa_module import \ - IPAAnsibleModule, gen_add_del_lists, compare_args_ipa + IPAAnsibleModule, gen_add_del_lists, compare_args_ipa, \ + gen_intersection_list, ensure_fqdn from ansible.module_utils import six - if six.PY3: unicode = str @@ -170,30 +170,6 @@ def check_parameters(module): module.params_fail_used_invalid(invalid, state, action) -def member_intersect(module, attr, memberof, res_find): - """Filter member arguments from role found by intersection.""" - params = module.params_get(attr) - if not res_find: - return params - filtered = [] - if params: - existing = res_find.get(memberof, []) - filtered = list(set(params) & set(existing)) - return filtered - - -def member_difference(module, attr, memberof, res_find): - """Filter member arguments from role found by difference.""" - params = module.params_get(attr) - if not res_find: - return params - filtered = [] - if params: - existing = res_find.get(memberof, []) - filtered = list(set(params) - set(existing)) - return filtered - - def ensure_absent_state(module, name, action, res_find): """Define commands to ensure absent state.""" commands = [] @@ -203,16 +179,20 @@ def ensure_absent_state(module, name, action, res_find): if action == "member": - members = member_intersect( - module, 'privilege', 'memberof_privilege', res_find) + members = gen_intersection_list( + module.params_get("privilege"), + res_find.get("memberof_privilege") + ) if members: commands.append([name, "role_remove_privilege", {"privilege": members}]) member_args = {} for key in ['user', 'group', 'host', 'hostgroup']: - items = member_intersect( - module, key, 'member_%s' % key, res_find) + items = gen_intersection_list( + module.params_get(key), + res_find.get("member_%s" % key) + ) if items: member_args[key] = items @@ -298,24 +278,6 @@ def ensure_role_with_members_is_present(module, name, res_find, action): return commands -# pylint: disable=unused-argument -def result_handler(module, result, command, name, args, errors): - """Process the result of a command, looking for errors.""" - # Get all errors - # All "already a member" and "not a member" failures in the - # result are ignored. All others are reported. - 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]: - if "already a member" in failure \ - or "not a member" in failure: - continue - errors.append("%s: %s %s: %s" % ( - command, member_type, member, failure)) - - def role_commands_for_name(module, state, action, name): """Define commands for the Role module.""" commands = [] @@ -414,7 +376,8 @@ def main(): # Execute commands - changed = ansible_module.execute_ipa_commands(commands, result_handler) + changed = ansible_module.execute_ipa_commands( + commands, fail_on_member_errors=True) # Done ansible_module.exit_json(changed=changed, **exit_args) From 971fcc917a21ca490f2975456a001d480d90d96f Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 11 Nov 2021 18:52:41 -0300 Subject: [PATCH 3/9] iparole: Case insensitive comparison of service members. Service members in IPA role objects must be compared ignoring character capitalization, but are stored in a case preserving manner. This patch modifies the way service members are handled, creating a map between a lowercase version of the service parameter and the parameter itself, and using the map key to compare against existing services. The mapped value is then added as role member, if necessary. --- plugins/modules/iparole.py | 88 +++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index 0f2a0805..ad54ca09 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -196,10 +196,12 @@ def ensure_absent_state(module, name, action, res_find): if items: member_args[key] = items - _services = filter_service(module, res_find, - lambda res, svc: res.startswith(svc)) + _services = get_service_param(module, "service") if _services: - member_args['service'] = _services + _existing = get_lowercase(res_find, "member_service") + items = gen_intersection_list(_services.keys(), _existing) + if items: + member_args["service"] = [_services[key] for key in items] # Only add remove command if there's at least one member no manage. if member_args: @@ -208,27 +210,59 @@ def ensure_absent_state(module, name, action, res_find): return commands -def filter_service(module, res_find, predicate): +def get_service_param(module, key): """ - Filter service based on predicate. + Retrieve dict of services, with realm, from the module parameters. - Compare service name with existing ones matching - at least until `@` from principal name. - - Predicate is a callable that accepts the existing service, and the - modified service to be compared to. + As the services are compared in a case insensitive manner, but + are recorded in a case preserving way, a dict mapping the services + in lowercase to the provided module parameter is generated, so + that dict keys can be used for comparison and the values are used + with IPA API. """ - _services = [] - service = module.params_get('service') - if service: - existing = [to_text(x) for x in res_find.get('member_service', [])] - for svc in service: - svc = svc if '@' in svc else ('%s@' % svc) - found = [x for x in existing if predicate(x, svc)] - _services.extend(found) + _services = module.params_get(key) + if _services is not None: + ipa_realm = module.ipa_get_realm() + _services = [ + to_text(svc) if '@' in svc else ('%s@%s' % (svc, ipa_realm)) + for svc in _services + ] + if _services: + _services = {svc.lower(): svc for svc in _services} return _services +def get_lowercase(res_find, key, default=None): + """ + Retrieve a member of a dictionary converted to lowercase. + + If 'key' is not found in the dictionary, return 'default'. + """ + existing = res_find.get(key) + if existing is not None: + if isinstance(existing, (list, tuple)): + existing = [to_text(item).lower() for item in existing] + if isinstance(existing, (str, unicode)): + existing = existing.lower() + else: + existing = default + return existing + + +def gen_services_add_del_lists(module, mod_member, res_find, res_member): + """Generate add/del lists for service principals.""" + add_list, del_list = None, None + _services = get_service_param(module, mod_member) + if _services is not None: + _existing = result_get_value_lowercase(res_find, res_member) + add_list, del_list = gen_add_del_lists(_services.keys(), _existing) + if add_list: + add_list = [_services[key] for key in add_list] + if del_list: + del_list = [to_text(item) for item in del_list] + return add_list, del_list + + def ensure_role_with_members_is_present(module, name, res_find, action): """Define commands to ensure member are present for action `role`.""" commands = [] @@ -256,18 +290,12 @@ def ensure_role_with_members_is_present(module, name, res_find, action): if del_list: del_members[key] = [to_text(item) for item in del_list] - service = [ - to_text(svc) - if '@' in svc - else ('%s@%s' % (svc, module.ipa_get_realm())) - for svc in (module.params_get('service') or []) - ] - existing = [str(svc) for svc in res_find.get('member_service', [])] - add_list, del_list = gen_add_del_lists(service, existing) - if add_list: - add_members['service'] = add_list - if del_list: - del_members['service'] = [to_text(item) for item in del_list] + (add_services, del_services) = gen_services_add_del_lists( + module, "service", res_find, "member_service") + if add_services: + add_members["service"] = add_services + if del_services: + del_members["service"] = del_services if add_members: commands.append([name, "role_add_member", add_members]) From bde3eb829431d15f4ec0312fdde177433ed04f6d Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Wed, 12 Jan 2022 16:55:33 -0300 Subject: [PATCH 4/9] IPAAnsibleModule: cache IPA domain. Some attributes retrieved by the IPA API backend don't change, and are used more than once, in different places of the code. IPA API domain is one of these attributes. This patch adds a cache to the attribute, so there is only one request for the API, improving access time to the object and alowing multiple calls with no efficiency penalty. --- plugins/module_utils/ansible_freeipa_module.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py index b4cdf613..b9e32369 100644 --- a/plugins/module_utils/ansible_freeipa_module.py +++ b/plugins/module_utils/ansible_freeipa_module.py @@ -875,10 +875,11 @@ else: """ return api_command_no_name(self, command, args) - @staticmethod - def ipa_get_domain(): + def ipa_get_domain(self): """Retrieve IPA API domain.""" - return api_get_domain() + if not hasattr(self, "__ipa_api_domain"): + setattr(self, "__ipa_api_domain", api_get_domain()) + return getattr(self, "__ipa_api_domain") @staticmethod def ipa_get_realm(): From faace4f37690d7d78950dbf65d8ae3466baac1dc Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 11 Nov 2021 19:17:18 -0300 Subject: [PATCH 5/9] iparole: Ensure host members are lowercase and FQDN. IPA Role host members should always be lowercase and FQDN. This patch ensure that hosts are correctly compared and added as role members. --- plugins/modules/iparole.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index ad54ca09..0f3643ed 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -170,6 +170,17 @@ def check_parameters(module): module.params_fail_used_invalid(invalid, state, action) +def get_member_host_with_fqdn_lowercase(module, mod_member): + """Retrieve host members from module, as FQDN, lowercase.""" + default_domain = module.ipa_get_domain() + hosts = module.params_get(mod_member) + return ( + [ensure_fqdn(host, default_domain).lower() for host in hosts] + if hosts + else hosts + ) + + def ensure_absent_state(module, name, action, res_find): """Define commands to ensure absent state.""" commands = [] @@ -188,7 +199,7 @@ def ensure_absent_state(module, name, action, res_find): {"privilege": members}]) member_args = {} - for key in ['user', 'group', 'host', 'hostgroup']: + for key in ['user', 'group', 'hostgroup']: items = gen_intersection_list( module.params_get(key), res_find.get("member_%s" % key) @@ -196,6 +207,14 @@ def ensure_absent_state(module, name, action, res_find): if items: member_args[key] = items + # ensure hosts are FQDN. + _members = get_member_host_with_fqdn_lowercase(module, "host") + if _members: + del_list = gen_intersection_list( + _members, res_find.get('member_host')) + if del_list: + member_args["host"] = del_list + _services = get_service_param(module, "service") if _services: _existing = get_lowercase(res_find, "member_service") @@ -280,7 +299,7 @@ def ensure_role_with_members_is_present(module, name, res_find, action): add_members = {} del_members = {} - for key in ["user", "group", "host", "hostgroup"]: + for key in ["user", "group", "hostgroup"]: add_list, del_list = gen_add_del_lists( module.params_get(key), res_find.get('member_%s' % key, []) @@ -290,6 +309,16 @@ def ensure_role_with_members_is_present(module, name, res_find, action): if del_list: del_members[key] = [to_text(item) for item in del_list] + # ensure hosts are FQDN. + _members = get_member_host_with_fqdn_lowercase(module, "host") + if _members: + add_list, del_list = gen_add_del_lists( + _members, res_find.get('member_host')) + if add_list: + add_members["host"] = add_list + if del_list: + del_members["host"] = del_list + (add_services, del_services) = gen_services_add_del_lists( module, "service", res_find, "member_service") if add_services: From 846fdc0698dffa550b29a975fc7ccb5061237598 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 11 Nov 2021 19:32:43 -0300 Subject: [PATCH 6/9] iparole: Fix idempotence issues with members. IPA role members users, groups, hostgroups and privilege must be compared in a case insensitive way, and either are stored in lowercase or IPA API fixes the value for proper representation. This patch forces all comparisons of this values to be performed in lowercase, and also only modify the values if it is really needed. --- plugins/modules/iparole.py | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index 0f3643ed..f9cc823b 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -190,22 +190,22 @@ def ensure_absent_state(module, name, action, res_find): if action == "member": - members = gen_intersection_list( - module.params_get("privilege"), - res_find.get("memberof_privilege") - ) - if members: - commands.append([name, "role_remove_privilege", - {"privilege": members}]) + _members = module.params_get_lowercase("privilege") + if _members is not None: + del_list = gen_intersection_list( + _members, get_lowercase(res_find, "memberof_privilege")) + if del_list: + commands.append([name, "role_remove_privilege", + {"privilege": del_list}]) member_args = {} for key in ['user', 'group', 'hostgroup']: - items = gen_intersection_list( - module.params_get(key), - res_find.get("member_%s" % key) - ) - if items: - member_args[key] = items + _members = module.params_get_lowercase(key) + if _members: + del_list = gen_intersection_list( + _members, get_lowercase(res_find, "member_%s" % key)) + if del_list: + member_args[key] = del_list # ensure hosts are FQDN. _members = get_member_host_with_fqdn_lowercase(module, "host") @@ -285,29 +285,31 @@ def gen_services_add_del_lists(module, mod_member, res_find, res_member): def ensure_role_with_members_is_present(module, name, res_find, action): """Define commands to ensure member are present for action `role`.""" commands = [] - privilege_add, privilege_del = gen_add_del_lists( - module.params_get("privilege"), - res_find.get('memberof_privilege', [])) - if privilege_add: - commands.append([name, "role_add_privilege", - {"privilege": privilege_add}]) - if action == "role" and privilege_del: - commands.append([name, "role_remove_privilege", - {"privilege": privilege_del}]) + _members = module.params_get_lowercase("privilege") + if _members: + add_list, del_list = gen_add_del_lists( + _members, get_lowercase(res_find, "memberof_privilege")) + + if add_list: + commands.append([name, "role_add_privilege", + {"privilege": add_list}]) + if action == "role" and del_list: + commands.append([name, "role_remove_privilege", + {"privilege": del_list}]) add_members = {} del_members = {} for key in ["user", "group", "hostgroup"]: - add_list, del_list = gen_add_del_lists( - module.params_get(key), - res_find.get('member_%s' % key, []) - ) - if add_list: - add_members[key] = add_list - if del_list: - del_members[key] = [to_text(item) for item in del_list] + _members = module.params_get_lowercase(key) + if _members is not None: + add_list, del_list = gen_add_del_lists( + _members, get_lowercase(res_find, "member_%s" % key)) + if add_list: + add_members[key] = add_list + if del_list: + del_members[key] = del_list # ensure hosts are FQDN. _members = get_member_host_with_fqdn_lowercase(module, "host") From a44ffbf3dd80f8b77f1c7348fb789c7ed2cee73c Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Wed, 29 Dec 2021 10:49:33 -0300 Subject: [PATCH 7/9] iparole: rename function get_lowercase to result_get_value_lowercase Renamed function and improved its documentation to better explain its use and goals. --- plugins/modules/iparole.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/plugins/modules/iparole.py b/plugins/modules/iparole.py index f9cc823b..61e4d3d4 100644 --- a/plugins/modules/iparole.py +++ b/plugins/modules/iparole.py @@ -193,7 +193,9 @@ def ensure_absent_state(module, name, action, res_find): _members = module.params_get_lowercase("privilege") if _members is not None: del_list = gen_intersection_list( - _members, get_lowercase(res_find, "memberof_privilege")) + _members, + result_get_value_lowercase(res_find, "memberof_privilege") + ) if del_list: commands.append([name, "role_remove_privilege", {"privilege": del_list}]) @@ -203,7 +205,9 @@ def ensure_absent_state(module, name, action, res_find): _members = module.params_get_lowercase(key) if _members: del_list = gen_intersection_list( - _members, get_lowercase(res_find, "member_%s" % key)) + _members, + result_get_value_lowercase(res_find, "member_%s" % key) + ) if del_list: member_args[key] = del_list @@ -217,7 +221,7 @@ def ensure_absent_state(module, name, action, res_find): _services = get_service_param(module, "service") if _services: - _existing = get_lowercase(res_find, "member_service") + _existing = result_get_value_lowercase(res_find, "member_service") items = gen_intersection_list(_services.keys(), _existing) if items: member_args["service"] = [_services[key] for key in items] @@ -251,11 +255,15 @@ def get_service_param(module, key): return _services -def get_lowercase(res_find, key, default=None): +def result_get_value_lowercase(res_find, key, default=None): """ Retrieve a member of a dictionary converted to lowercase. - If 'key' is not found in the dictionary, return 'default'. + If field data is a string it is returned in lowercase. If + field data is a list or tuple, it is assumed that all values + are strings and the result is a list of strings in lowercase. + + If 'key' is not found in the dictionary, returns 'default'. """ existing = res_find.get(key) if existing is not None: @@ -289,7 +297,9 @@ def ensure_role_with_members_is_present(module, name, res_find, action): _members = module.params_get_lowercase("privilege") if _members: add_list, del_list = gen_add_del_lists( - _members, get_lowercase(res_find, "memberof_privilege")) + _members, + result_get_value_lowercase(res_find, "memberof_privilege") + ) if add_list: commands.append([name, "role_add_privilege", @@ -305,7 +315,9 @@ def ensure_role_with_members_is_present(module, name, res_find, action): _members = module.params_get_lowercase(key) if _members is not None: add_list, del_list = gen_add_del_lists( - _members, get_lowercase(res_find, "member_%s" % key)) + _members, + result_get_value_lowercase(res_find, "member_%s" % key) + ) if add_list: add_members[key] = add_list if del_list: From a025e476eaa8854aef2ec1544865ba824ca37b26 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Wed, 29 Dec 2021 10:51:34 -0300 Subject: [PATCH 8/9] iparole: Add tests to verify if capitalisation is ignored. The test playbook provided adds some tests to verify if capitalization of role members does not influence on the module behavior. It also adds some tests to verify check_mode. --- .../test_role_member_case_insensitive.yml | 450 ++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100644 tests/role/test_role_member_case_insensitive.yml diff --git a/tests/role/test_role_member_case_insensitive.yml b/tests/role/test_role_member_case_insensitive.yml new file mode 100644 index 00000000..3f386fc3 --- /dev/null +++ b/tests/role/test_role_member_case_insensitive.yml @@ -0,0 +1,450 @@ +--- +- name: Test role members + hosts: "{{ ipa_test_host | default('ipaserver') }}" + become: no + gather_facts: no + + vars: + user_list: + - User1 + - uSer2 + - usEr3 + group_list: + - Group1 + - gRoup2 + - grOup3 + host_list: + - HoSt01 + - hOsT02 + hostgroup_list: + - TestHostGroup + service_list: + - MySVC/host01 + + tasks: + - include_tasks: ../env_freeipa_facts.yml + + - block: + # setup + + - name: Ensure test role is absent + iparole: + ipaadmin_password: SomeADMINpassword + name: testrule + state: absent + + - name: Ensure test users are present + ipauser: + ipaadmin_password: SomeADMINpassword + users: + - name: "{{ item }}" + first: First + last: Last + with_items: "{{ user_list }}" + + - name: Ensure test groups are present + ipagroup: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + with_items: "{{ group_list }}" + + - name: Ensure test hosts are present + ipahost: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}.{{ ipaserver_domain }}" + ip_address: 192.168.122.101 + force: yes + with_items: "{{ host_list }}" + + - name: Ensure test hostgroups are present + ipahostgroup: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + with_items: "{{ hostgroup_list }}" + + - name: Ensure test services are present + ipaservice: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}.{{ ipaserver_domain }}" + with_items: "{{ service_list }}" + + # Test with action: hbacrule + + - name: Check role present with members would trigger a change, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + check_mode: yes + register: result + failed_when: not result.changed or result.failed + + - name: Ensure role is present with members, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + register: result + failed_when: not result.changed or result.failed + + - name: Check role present with members would not trigger a change, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + check_mode: yes + register: result + failed_when: result.changed or result.failed + + - name: Ensure role is present with members, lowercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | lower }}" + - "{{ user_list[2] | lower }}" + group: + - "{{ group_list[1] | lower }}" + - "{{ group_list[2] | lower }}" + host: + - "{{ host_list[0] | lower }}" + - "{{ host_list[1] | lower }}" + hostgroup: + - "{{ hostgroup_list[0] | lower }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | lower }}" + register: result + failed_when: result.changed or result.failed + + - name: Ensure role is present with members, upercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | upper }}" + - "{{ user_list[2] | upper }}" + group: + - "{{ group_list[1] | upper }}" + - "{{ group_list[2] | upper }}" + host: + - "{{ host_list[0] | upper }}" + - "{{ host_list[1] | upper }}" + hostgroup: + - "{{ hostgroup_list[0] | upper }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | upper }}" + register: result + failed_when: result.changed or result.failed + + - name: Ensure test role is absent + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + state: absent + + # Test with action: members + + - name: Ensure test role is present + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + + - name: Check role members present would trigger a change, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + action: member + check_mode: yes + register: result + failed_when: not result.changed or result.failed + + - name: Ensure role is present with members, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + action: member + register: result + failed_when: not result.changed or result.failed + + - name: Check role members present would not trigger a change, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + action: member + check_mode: yes + register: result + failed_when: result.changed or result.failed + + - name: Ensure role is present with members, lowercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | lower }}" + - "{{ user_list[2] | lower }}" + group: + - "{{ group_list[1] | lower }}" + - "{{ group_list[2] | lower }}" + host: + - "{{ host_list[0] | lower }}" + - "{{ host_list[1] | lower }}" + hostgroup: + - "{{ hostgroup_list[0] | lower }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | lower }}" + action: member + register: result + failed_when: result.changed or result.failed + + - name: Ensure role is present with members, upercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | upper }}" + - "{{ user_list[2] | upper }}" + group: + - "{{ group_list[1] | upper }}" + - "{{ group_list[2] | upper }}" + host: + - "{{ host_list[0] | upper }}" + - "{{ host_list[1] | upper }}" + hostgroup: + - "{{ hostgroup_list[0] | upper }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | upper }}" + action: member + register: result + failed_when: result.changed or result.failed + + # # Test absent members + - name: Check role members absent would trigger a change, upercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | upper }}" + - "{{ user_list[2] | upper }}" + group: + - "{{ group_list[1] | upper }}" + - "{{ group_list[2] | upper }}" + host: + - "{{ host_list[0] | upper }}" + - "{{ host_list[1] | upper }}" + hostgroup: + - "{{ hostgroup_list[0] | upper }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | upper }}" + action: member + state: absent + check_mode: yes + register: result + failed_when: not result.changed or result.failed + + - name: Ensure role members are absent, upercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | upper }}" + - "{{ user_list[2] | upper }}" + group: + - "{{ group_list[1] | upper }}" + - "{{ group_list[2] | upper }}" + host: + - "{{ host_list[0] | upper }}" + - "{{ host_list[1] | upper }}" + hostgroup: + - "{{ hostgroup_list[0] | upper }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | upper }}" + action: member + state: absent + register: result + failed_when: not result.changed or result.failed + + - name: Check role members absent would not trigger a change, upercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | upper }}" + - "{{ user_list[2] | upper }}" + group: + - "{{ group_list[1] | upper }}" + - "{{ group_list[2] | upper }}" + host: + - "{{ host_list[0] | upper }}" + - "{{ host_list[1] | upper }}" + hostgroup: + - "{{ hostgroup_list[0] | upper }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | upper }}" + action: member + state: absent + check_mode: yes + register: result + failed_when: result.changed or result.failed + + - name: Ensure role members are absent, mixed case + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] }}" + - "{{ user_list[2] }}" + group: + - "{{ group_list[1] }}" + - "{{ group_list[2] }}" + host: + - "{{ host_list[0] }}" + - "{{ host_list[1] }}" + hostgroup: + - "{{ hostgroup_list[0] }}" + service: + - "{{ service_list[0] }}.{{ ipaserver_domain }}" + action: member + state: absent + register: result + failed_when: result.changed or result.failed + + - name: Ensure role members are absent, lowercase + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + user: + - "{{ user_list[1] | lower }}" + - "{{ user_list[2] | lower }}" + group: + - "{{ group_list[1] | lower }}" + - "{{ group_list[2] | lower }}" + host: + - "{{ host_list[0] | lower }}" + - "{{ host_list[1] | lower }}" + hostgroup: + - "{{ hostgroup_list[0] | lower }}" + service: + - "{{ (service_list[0] + '.' + ipaserver_domain) | lower }}" + action: member + state: absent + register: result + failed_when: result.changed or result.failed + + always: + - name: Ensure test role is absent + iparole: + ipaadmin_password: SomeADMINpassword + name: testrole + state: absent + + - name: Ensure test users are absent + ipauser: + ipaadmin_password: SomeADMINpassword + users: + - name: "{{ item }}" + state: absent + with_items: "{{ user_list }}" + + - name: Ensure test groups are absent + ipagroup: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + state: absent + with_items: "{{ group_list }}" + + - name: Ensure test hosts are absent + ipahost: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}.{{ ipaserver_domain }}" + state: absent + with_items: "{{ host_list }}" + + - name: Ensure test hostgroups are absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}" + state: absent + with_items: "{{ hostgroup_list }}" + + - name: Ensure test services are absent + ipaservice: + ipaadmin_password: SomeADMINpassword + name: "{{ item }}.{{ ipaserver_domain }}" + continue: yes + state: absent + with_items: "{{ service_list }}" From 07e9d87e92cf32f99668e8564ce59dc621573e68 Mon Sep 17 00:00:00 2001 From: Rafael Guterres Jeffman Date: Thu, 13 Jan 2022 10:20:28 -0300 Subject: [PATCH 9/9] iparole: Skip ansible-test verifications for Python 2.6. --- tests/sanity/ignore-2.12.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/sanity/ignore-2.12.txt b/tests/sanity/ignore-2.12.txt index 33b1770e..b08a6ffa 100644 --- a/tests/sanity/ignore-2.12.txt +++ b/tests/sanity/ignore-2.12.txt @@ -18,6 +18,8 @@ plugins/modules/ipadnsrecord.py pylint:use-maxsplit-arg plugins/modules/ipareplica_enable_ipa.py pylint:ansible-format-automatic-specification plugins/modules/ipareplica_prepare.py pylint:ansible-format-automatic-specification plugins/modules/ipareplica_test.py pylint:ansible-format-automatic-specification +plugins/modules/iparole.py compile-2.6!skip +plugins/modules/iparole.py import-2.6!skip plugins/modules/ipaserver_setup_ca.py compile-2.6!skip plugins/modules/ipaserver_setup_ca.py import-2.6!skip plugins/modules/ipaserver_test.py pylint:ansible-format-automatic-specification