Skip to content
Snippets Groups Projects
Commit 67e19224 authored by Thomas Woerner's avatar Thomas Woerner
Browse files

automember: Add automember state: rebuilt

There was state: rebuild before, but the code was incomplete and was not
able to run properly.

New parameters:
- users: Limit the rebuild to the given users only
- hosts: Limit the rebuild to the given hosts only
- no_wait: Don't wait for rebuilding membership

New parameters and examples have been added to README-automember.md

tests/automember/test_automember_client_context.yml has been using
state: rebuild and lacked the automember_type parameter.

grouping was used in functions and has been replaced by automember_type.

Some typos in examples have been fixed also.

New playbooks:
- playbooks/automember/automember-group-membership-all-users-rebuilt.yml
- playbooks/automember/automember-group-membership-users-rebuilt.yml
- playbooks/automember/automember-hostgroup-membership-all-hosts-rebuilt.yml
- playbooks/automember/automember-hostgroup-membership-hosts-rebuilt.yml

New tests:
- tests/automember/test_automember_rebuilt.yml
parent 9eefc1ae
No related branches found
No related tags found
No related merge requests found
...@@ -104,13 +104,74 @@ Example playbook to add an inclusive condition to an existing rule ...@@ -104,13 +104,74 @@ Example playbook to add an inclusive condition to an existing rule
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: "My domain hosts" name: "My domain hosts"
description: "my automember condition" description: "my automember condition"
automember_tye: hostgroup automember_type: hostgroup
action: member action: member
inclusive: inclusive:
- key: fqdn - key: fqdn
expression: ".*.mydomain.com" expression: ".*.mydomain.com"
``` ```
Example playbook to ensure group membership for all users has been rebuilt
```yaml
- name: Playbook to ensure group membership for all users has been rebuilt
hosts: ipaserver
become: yes
gather_facts: no
tasks:
- ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: group
state: rebuilt
```
Example playbook to ensure group membership for given users has been rebuilt
```yaml
- name: Playbook to ensure group membership for given users has been rebuilt
hosts: ipaserver
become: yes
gather_facts: no
tasks:
- ipaautomember:
ipaadmin_password: SomeADMINpassword
users:
- user1
- user2
state: rebuilt
```
Example playbook to ensure hostgroup membership for all hosts has been rebuilt
```yaml
- name: Playbook to ensure hostgroup membership for all hosts has been rebuilt
hosts: ipaserver
become: yes
gather_facts: no
tasks:
- ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: hostgroup
state: rebuilt
```
Example playbook to ensure hostgroup membership for given hosts has been rebuilt
```yaml
- name: Playbook to ensure hostgroup membership for given hosts has been rebuilt
hosts: ipaserver
become: yes
gather_facts: no
tasks:
- ipaautomember:
ipaadmin_password: SomeADMINpassword
hosts:
- host1.mydomain.com
- host2.mydomain.com
state: rebuilt
```
Variables Variables
--------- ---------
...@@ -129,11 +190,15 @@ Variable | Description | Required ...@@ -129,11 +190,15 @@ Variable | Description | Required
`automember_type` | Grouping to which the rule applies. It can be one of `group`, `hostgroup`. | yes `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 `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 `exclusive` | List of dictionaries in the format of `{'key': attribute, 'expression': exclusive_regex}` | no
`users` | Users to rebuild membership for. | no
`hosts` | Hosts to rebuild membership for. | no
`no_wait` | Don't wait for rebuilding membership. | no
`action` | Work on automember or member level. It can be one of `member` or `automember` and defaults to `automember`. | 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`, default: `present`. | no `state` | The state to ensure. It can be one of `present`, `absent`, 'rebuilt'. default: `present`. | no
Authors Authors
======= =======
Mark Hahl Mark Hahl
Thomas Woerner
---
- name: Automember group membership for all users rebuilt example
hosts: ipaserver
become: true
tasks:
- name: Ensure group automember rule admins is present
ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: group
state: rebuilt
---
- name: Automember group membership for given users rebuilt example
hosts: ipaserver
become: true
tasks:
- name: Ensure group membership for given users has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
users:
- user1
- user2
state: rebuilt
---
- name: Automember hostgroup membership for all hosts rebuilt example
hosts: ipaserver
become: true
tasks:
- name: Ensure hostgroup membership for all hosts has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: hostgroup
state: rebuilt
---
- name: Automember hostgroup membership for given hosts rebuilt example
hosts: ipaserver
become: true
tasks:
- name: Ensure hostgroup membership for given hosts has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
hosts:
- host1.mydomain.com
- host2.mydomain.com
state: rebuilt
...@@ -79,6 +79,17 @@ options: ...@@ -79,6 +79,17 @@ options:
description: The expression of the regex description: The expression of the regex
type: str type: str
required: true required: true
users:
description: Users to rebuild membership for.
type: list
required: false
hosts:
description: Hosts to rebuild membership for.
type: list
required: false
no_wait:
description: Don't wait for rebuilding membership.
type: bool
action: action:
description: Work on automember or member level description: Work on automember or member level
default: automember default: automember
...@@ -86,10 +97,11 @@ options: ...@@ -86,10 +97,11 @@ options:
state: state:
description: State to ensure description: State to ensure
default: present default: present
choices: ["present", "absent"] choices: ["present", "absent", "rebuilt"]
author: author:
- Mark Hahl - Mark Hahl
- Jake Reynolds - Jake Reynolds
- Thomas Woerner
""" """
EXAMPLES = """ EXAMPLES = """
...@@ -116,12 +128,39 @@ EXAMPLES = """ ...@@ -116,12 +128,39 @@ EXAMPLES = """
- ipaautomember: - ipaautomember:
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
name: "My domain hosts" name: "My domain hosts"
automember_tye: hostgroup automember_type: hostgroup
action: member action: member
inclusive: inclusive:
- key: fqdn - key: fqdn
expression: ".*.mydomain.com" expression: ".*.mydomain.com"
# Ensure group membership for all users has been rebuilt
- ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: group
state: rebuilt
# Ensure group membership for given users has been rebuilt
- ipaautomember:
ipaadmin_password: SomeADMINpassword
users:
- user1
- user2
state: rebuilt
# Ensure hostgroup membership for all hosts has been rebuilt
- ipaautomember:
ipaadmin_password: SomeADMINpassword
automember_type: hostgroup
state: rebuilt
# Ensure hostgroup membership for given hosts has been rebuilt
- ipaautomember:
ipaadmin_password: SomeADMINpassword
hosts:
- host1.mydomain.com
- host2.mydomain.com
state: rebuilt
""" """
RETURN = """ RETURN = """
...@@ -133,10 +172,10 @@ from ansible.module_utils.ansible_freeipa_module import ( ...@@ -133,10 +172,10 @@ from ansible.module_utils.ansible_freeipa_module import (
) )
def find_automember(module, name, grouping): def find_automember(module, name, automember_type):
_args = { _args = {
"all": True, "all": True,
"type": grouping "type": automember_type
} }
try: try:
...@@ -146,13 +185,13 @@ def find_automember(module, name, grouping): ...@@ -146,13 +185,13 @@ def find_automember(module, name, grouping):
return _result["result"] return _result["result"]
def gen_condition_args(grouping, def gen_condition_args(automember_type,
key, key,
inclusiveregex=None, inclusiveregex=None,
exclusiveregex=None): exclusiveregex=None):
_args = {} _args = {}
if grouping is not None: if automember_type is not None:
_args['type'] = grouping _args['type'] = automember_type
if key is not None: if key is not None:
_args['key'] = key _args['key'] = key
if inclusiveregex is not None: if inclusiveregex is not None:
...@@ -163,13 +202,23 @@ def gen_condition_args(grouping, ...@@ -163,13 +202,23 @@ def gen_condition_args(grouping,
return _args return _args
def gen_args(description, grouping): def gen_rebuild_args(automember_type, rebuild_users, rebuild_hosts, no_wait):
_args = {"no_wait": no_wait}
if automember_type is not None:
_args['type'] = automember_type
if rebuild_users is not None:
_args["users"] = rebuild_users
if rebuild_hosts is not None:
_args["hosts"] = rebuild_hosts
return _args
def gen_args(description, automember_type):
_args = {} _args = {}
if description is not None: if description is not None:
_args["description"] = description _args["description"] = description
if grouping is not None: if automember_type is not None:
_args['type'] = grouping _args['type'] = automember_type
return _args return _args
...@@ -208,14 +257,15 @@ def main(): ...@@ -208,14 +257,15 @@ def main():
), ),
elements="dict", required=False), elements="dict", required=False),
name=dict(type="list", aliases=["cn"], name=dict(type="list", aliases=["cn"],
default=None, required=True), default=None, required=False),
description=dict(type="str", default=None), description=dict(type="str", default=None),
automember_type=dict(type='str', required=False, automember_type=dict(type='str', required=False,
choices=['group', 'hostgroup']), choices=['group', 'hostgroup']),
no_wait=dict(type="bool", default=None),
action=dict(type="str", default="automember", action=dict(type="str", default="automember",
choices=["member", "automember"]), choices=["member", "automember"]),
state=dict(type="str", default="present", state=dict(type="str", default="present",
choices=["present", "absent", "rebuild"]), choices=["present", "absent", "rebuilt"]),
users=dict(type="list", default=None), users=dict(type="list", default=None),
hosts=dict(type="list", default=None), hosts=dict(type="list", default=None),
), ),
...@@ -228,6 +278,8 @@ def main(): ...@@ -228,6 +278,8 @@ def main():
# general # general
names = ansible_module.params_get("name") names = ansible_module.params_get("name")
if names is None:
names = []
# present # present
description = ansible_module.params_get("description") description = ansible_module.params_get("description")
...@@ -236,6 +288,9 @@ def main(): ...@@ -236,6 +288,9 @@ def main():
inclusive = ansible_module.params_get("inclusive") inclusive = ansible_module.params_get("inclusive")
exclusive = ansible_module.params_get("exclusive") exclusive = ansible_module.params_get("exclusive")
# no_wait for rebuilt
no_wait = ansible_module.params_get("no_wait")
# action # action
action = ansible_module.params_get("action") action = ansible_module.params_get("action")
# state # state
...@@ -250,12 +305,29 @@ def main(): ...@@ -250,12 +305,29 @@ def main():
# Check parameters # Check parameters
invalid = [] invalid = []
if state != "rebuild": if state in ["rebuilt"]:
invalid = ["rebuild_hosts", "rebuild_users"] invalid = ["name", "description", "exclusive", "inclusive"]
if not automember_type and state != "rebuild": if action == "member":
ansible_module.fail_json( ansible_module.fail_json(
msg="'automember_type' is required unless state: rebuild") msg="'action=member' is not usable with state '%s'" % state)
if state == "rebuilt":
if automember_type == "group" and rebuild_hosts is not None:
ansible_module.fail_json(
msg="state %s: hosts can not be set when type is '%s'" %
(state, automember_type))
if automember_type == "hostgroup" and rebuild_users is not None:
ansible_module.fail_json(
msg="state %s: users can not be set when type is '%s'" %
(state, automember_type))
else:
invalid = ["users", "hosts", "no_wait"]
if not automember_type:
ansible_module.fail_json(
msg="'automember_type' is required.")
ansible_module.params_fail_used_invalid(invalid, state, action) ansible_module.params_fail_used_invalid(invalid, state, action)
...@@ -392,16 +464,14 @@ def main(): ...@@ -392,16 +464,14 @@ def main():
'automember_remove_condition', 'automember_remove_condition',
condition_args]) condition_args])
elif state == "rebuild": if len(names) == 0:
if automember_type: if state == "rebuilt":
commands.append([None, 'automember_rebuild', args = gen_rebuild_args(automember_type, rebuild_users,
{"type": automember_type}]) rebuild_hosts, no_wait)
if rebuild_users: commands.append([None, 'automember_rebuild', args])
commands.append([None, 'automember_rebuild',
{"users": rebuild_users}]) else:
if rebuild_hosts: ansible_module.fail_json(msg="Invalid operation")
commands.append([None, 'automember_rebuild',
{"hosts": rebuild_hosts}])
# Execute commands # Execute commands
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
ipaadmin_password: SomeADMINpassword ipaadmin_password: SomeADMINpassword
ipaapi_context: server ipaapi_context: server
name: ThisShouldNotWork name: ThisShouldNotWork
state: rebuild automember_type: group
state: rebuilt
register: result register: result
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*")) failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
when: ipa_host_is_client when: ipa_host_is_client
......
---
- name: Test automember rebuilt
hosts: "{{ ipa_test_host | default('ipaserver') }}"
become: true
tasks:
# SET FACTS
- name: Get Domain from server name
set_fact:
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] |
join ('.') }}"
when: ipaserver_domain is not defined
# CLEANUP TEST ITEMS
- name: Ensure user testuser is absent
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testuser
state: absent
- name: Ensure host testhost is absent
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ 'testhost.' + ipaserver_domain }}"
state: absent
# CREATE TEST ITEMS
- name: Ensure user testuser is present
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testuser
first: Test
last: User
register: result
failed_when: not result.changed or result.failed
- name: Ensure host testhost is present
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ 'testhost.' + ipaserver_domain }}"
force: yes
reverse: no
register: result
failed_when: not result.changed or result.failed
# TESTS
- name: Ensure group membership has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: group
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure group membership has been rebuilt no_wait
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: group
no_wait: yes
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure group membership for given users has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
users:
- testuser
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure hostgroup membership for given hosts has been rebuilt
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
hosts:
- "{{ 'testhost.' + ipaserver_domain }}"
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure group membership for given users has been rebuilt with type group
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: group
users:
- testuser
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure hostgroup membership for given hosts has been rebuilt with type hostgroup
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: hostgroup
hosts:
- "{{ 'testhost.' + ipaserver_domain }}"
state: rebuilt
register: result
failed_when: not result.changed or result.failed
- name: Ensure group membership rebuild fails with hosts
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: group
hosts:
- "{{ 'testhost.' + ipaserver_domain }}"
state: rebuilt
register: result
failed_when: not result.failed or
"hosts can not be set when type is 'group'" not in result.msg
- name: Ensure hostgroup membership rebuild fails with users
ipaautomember:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
automember_type: hostgroup
users:
- testuser
state: rebuilt
register: result
failed_when: not result.failed or
"users can not be set when type is 'hostgroup'" not in result.msg
# CLEANUP TEST ITEMS
- name: Ensure user testuser is absent
ipauser:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: testuser
state: absent
- name: Ensure host testhost is absent
ipahost:
ipaadmin_password: SomeADMINpassword
ipaapi_context: "{{ ipa_context | default(omit) }}"
name: "{{ 'testhost.' + ipaserver_domain }}"
state: absent
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment