diff --git a/README-automember.md b/README-automember.md index f5e075ff6f80e439460fdb756e224c1b20e4913c..eb44a4f0bcac6b8cc46d74d33e6e958b7065b83a 100644 --- a/README-automember.md +++ b/README-automember.md @@ -172,6 +172,64 @@ Example playbook to ensure hostgroup membership for given hosts has been rebuilt state: rebuilt ``` +Example playbook to ensure default group fallback_group for all unmatched group entries is set + +```yaml +- name: Playbook to ensure default group fallback_group for all unmatched group entries is set + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: group + default_group: fallback_group +``` + +Example playbook to ensure default group for all unmatched group entries is not set + +```yaml +- name: Playbook to ensure default group for all unmatched group entries is not set + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + default_group: "" + automember_type: group + state: absent +``` + +Example playbook to ensure default hostgroup fallback_hostgroup for all unmatched group entries + +```yaml +- name: Playbook to ensure default hostgroup fallback_hostgroup for all unmatched group entries + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: fallback_hostgroup +``` + +Example playbook to ensure default hostgroup for all unmatched group entries is not set + +```yaml +- name: Playbook to ensure default hostgroup for all unmatched group entries is not set + hosts: ipaserver + become: yes + gather_facts: no + tasks: + - ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: "" + state: absent +``` + Variables --------- @@ -193,6 +251,7 @@ Variable | Description | Required `users` | Users to rebuild membership for. | no `hosts` | Hosts to rebuild membership for. | no `no_wait` | Don't wait for rebuilding membership. | no +`default_group` | Default (fallback) group for all unmatched entries. Use the empty string "" for ensuring the default group is not set. | no `action` | Work on automember or member level. It can be one of `member` or `automember` and defaults to `automember`. | no `state` | The state to ensure. It can be one of `present`, `absent`, 'rebuilt'. default: `present`. | no diff --git a/playbooks/automember/automember-default-group-not-set.yml b/playbooks/automember/automember-default-group-not-set.yml new file mode 100644 index 0000000000000000000000000000000000000000..7c85bfb4068da523c98e9390c71a981f74353faa --- /dev/null +++ b/playbooks/automember/automember-default-group-not-set.yml @@ -0,0 +1,10 @@ +--- +- name: Automember default group not set + hosts: ipaserver + become: true + tasks: + - name: Ensure automember default group is not set + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: group + default_group: "" diff --git a/playbooks/automember/automember-default-group-set.yml b/playbooks/automember/automember-default-group-set.yml new file mode 100644 index 0000000000000000000000000000000000000000..41ce1185039fe82eada6f449074d188e344d3fac --- /dev/null +++ b/playbooks/automember/automember-default-group-set.yml @@ -0,0 +1,10 @@ +--- +- name: Automember default group set + hosts: ipaserver + become: true + tasks: + - name: Ensure automember default group is set + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: group + default_group: fallback_group diff --git a/playbooks/automember/automember-default-hostgroup-not-set.yml b/playbooks/automember/automember-default-hostgroup-not-set.yml new file mode 100644 index 0000000000000000000000000000000000000000..c37a875741131b5e59fc8e3bf6b01d021de47a32 --- /dev/null +++ b/playbooks/automember/automember-default-hostgroup-not-set.yml @@ -0,0 +1,10 @@ +--- +- name: Automember default hostgroup not set + hosts: ipaserver + become: true + tasks: + - name: Ensure automember default hostgroup is not set + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: "" diff --git a/playbooks/automember/automember-default-hostgroup-set.yml b/playbooks/automember/automember-default-hostgroup-set.yml new file mode 100644 index 0000000000000000000000000000000000000000..ac3b8d6d025d5f0ad6bf580937fc6c981fd46139 --- /dev/null +++ b/playbooks/automember/automember-default-hostgroup-set.yml @@ -0,0 +1,10 @@ +--- +- name: Automember default hostgroup set + hosts: ipaserver + become: true + tasks: + - name: Ensure automember default hostgroup is set + ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: fallback_hostgroup diff --git a/plugins/modules/ipaautomember.py b/plugins/modules/ipaautomember.py index cd2aac6882be672e0bf4a659031d05707bc5313c..0fab2f328a45e42522c54efae8398e73175ebd04 100644 --- a/plugins/modules/ipaautomember.py +++ b/plugins/modules/ipaautomember.py @@ -90,6 +90,9 @@ options: no_wait: description: Don't wait for rebuilding membership. type: bool + default_group: + description: Default (fallback) group for all unmatched entries. + type: str action: description: Work on automember or member level default: automember @@ -161,6 +164,33 @@ EXAMPLES = """ - host1.mydomain.com - host2.mydomain.com state: rebuilt + +# Ensure default group fallback_group for all unmatched group entries is set +- ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: group + default_group: fallback_group + +# Ensure default group for all unmatched group entries is not set +- ipaautomember: + ipaadmin_password: SomeADMINpassword + default_group: "" + automember_type: group + state: absent + +# Ensure default hostgroup fallback_hostgroup for all unmatched group entries +# is set +- ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: fallback_hostgroup + +# Ensure default hostgroup for all unmatched group entries is not set +- ipaautomember: + ipaadmin_password: SomeADMINpassword + automember_type: hostgroup + default_group: "" + state: absent """ RETURN = """ @@ -168,7 +198,7 @@ RETURN = """ from ansible.module_utils.ansible_freeipa_module import ( - IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, ipalib_errors + IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, ipalib_errors, DN ) @@ -185,6 +215,20 @@ def find_automember(module, name, automember_type): return _result["result"] +def find_automember_default_group(module, automember_type): + _args = { + "all": True, + "type": automember_type + } + + try: + _result = module.ipa_command_no_name("automember_default_group_show", + _args) + except ipalib_errors.NotFound: + return None + return _result["result"] + + def gen_condition_args(automember_type, key, inclusiveregex=None, @@ -262,6 +306,7 @@ def main(): automember_type=dict(type='str', required=False, choices=['group', 'hostgroup']), no_wait=dict(type="bool", default=None), + default_group=dict(type="str", default=None), action=dict(type="str", default="automember", choices=["member", "automember"]), state=dict(type="str", default="present", @@ -291,6 +336,9 @@ def main(): # no_wait for rebuilt no_wait = ansible_module.params_get("no_wait") + # default_group + default_group = ansible_module.params_get("default_group") + # action action = ansible_module.params_get("action") # state @@ -306,7 +354,8 @@ def main(): invalid = [] if state in ["rebuilt"]: - invalid = ["name", "description", "exclusive", "inclusive"] + invalid = ["name", "description", "exclusive", "inclusive", + "default_group"] if action == "member": ansible_module.fail_json( @@ -323,7 +372,21 @@ def main(): (state, automember_type)) else: - invalid = ["users", "hosts", "no_wait"] + if default_group is not None: + for param in ["name", "exclusive", "inclusive", "users", "hosts" + "no_wait"]: + if ansible_module.params.get(param) is not None: + msg = "Cannot use {0} together with default_group" + ansible_module.fail_json(msg=msg.format(param)) + if action == "member": + ansible_module.fail_json( + msg="Cannot use default_group with action:member") + if state == "absent": + ansible_module.fail_json( + msg="Cannot use default_group with state:absent") + + else: + invalid = ["users", "hosts", "no_wait"] if not automember_type: ansible_module.fail_json( @@ -470,6 +533,29 @@ def main(): rebuild_hosts, no_wait) commands.append([None, 'automember_rebuild', args]) + elif default_group is not None and state == "present": + res_find = find_automember_default_group(ansible_module, + automember_type) + + if default_group == "": + if isinstance(res_find["automemberdefaultgroup"], list): + commands.append([None, + 'automember_default_group_remove', + {'type': automember_type}]) + ansible_module.warn("commands: %s" % repr(commands)) + + else: + dn_default_group = [DN(('cn', default_group), + ('cn', '%ss' % automember_type), + ('cn', 'accounts'), + ansible_module.ipa_get_basedn())] + if repr(res_find["automemberdefaultgroup"]) != \ + repr(dn_default_group): + commands.append( + [None, 'automember_default_group_set', + {'type': automember_type, + 'automemberdefaultgroup': default_group}]) + else: ansible_module.fail_json(msg="Invalid operation") diff --git a/tests/automember/test_automember_default_group.yml b/tests/automember/test_automember_default_group.yml new file mode 100644 index 0000000000000000000000000000000000000000..9b082127459938cd86ed806fe665ce933937da6e --- /dev/null +++ b/tests/automember/test_automember_default_group.yml @@ -0,0 +1,166 @@ +--- +- name: Test automember default groups + hosts: "{{ ipa_test_host | default('ipaserver') }}" + become: true + + tasks: + + # SET FACTS + + # CLEANUP TEST ITEMS + + - name: Ensure group testgroup is absent + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testgroup + state: absent + + - name: Ensure hostgroup testhostgroup is absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testhostgroup + state: absent + + - name: Ensure automember default group is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: group + + - name: Ensure automember default hostgroup is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: hostgroup + + # CREATE TEST ITEMS + + - name: Ensure group testgroup is present + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testgroup + state: present + register: result + failed_when: not result.changed or result.failed + + - name: Ensure hostgroup testhostgroup is present + ipahostgroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testhostgroup + state: present + register: result + failed_when: not result.changed or result.failed + + # TESTS + + # GROUP TEST + + - name: Ensure automember default group is set to testgroup + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: testgroup + automember_type: group + register: result + failed_when: not result.changed or result.failed + + - name: Ensure automember default group is set to testgroup, again + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: testgroup + automember_type: group + register: result + failed_when: result.changed or result.failed + + - name: Ensure automember default group is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: group + register: result + failed_when: not result.changed or result.failed + + - name: Ensure automember default group is unset, again + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: group + register: result + failed_when: result.changed or result.failed + + # HOSTGROUP TEST + + - name: Ensure automember default hostgroup is set to testhostgroup + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: testhostgroup + automember_type: hostgroup + register: result + failed_when: not result.changed or result.failed + + - name: Ensure automember default hostgroup is set to testhostgroup, again + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: testhostgroup + automember_type: hostgroup + register: result + failed_when: result.changed or result.failed + + - name: Ensure automember default hostgroup is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: hostgroup + register: result + failed_when: not result.changed or result.failed + + - name: Ensure automember default hostgroup is unset, again + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: hostgroup + register: result + failed_when: result.changed or result.failed + + # CLEANUP TEST ITEMS + + - name: Ensure group testgroup is absent + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testgroup + state: absent + + - name: Ensure hostgroup testhostgroup is absent + ipahostgroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + name: testhostgroup + state: absent + + - name: Ensure automember default group is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: group + + - name: Ensure automember default hostgroup is unset + ipaautomember: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + default_group: "" + automember_type: hostgroup