diff --git a/README-group.md b/README-group.md index c3477f72ea..529553c544 100644 --- a/README-group.md +++ b/README-group.md @@ -130,6 +130,45 @@ And ensure the presence of the groups with this example playbook: groups: "{{ groups }}" ``` +Example playbook to rename a group: + +```yaml +--- +- name: Playbook to rename a single group + hosts: ipaserver + become: false + gather_facts: false + + tasks: + - name: Rename group appops to webops + ipagroup: + ipaadmin_password: SomeADMINpassword + name: appops + rename: webops + state: renamed +``` + +Several groups can also be renamed with a single task, as in the example playbook: + +```yaml +--- +- name: Playbook to rename multiple groups + hosts: ipaserver + become: false + gather_facts: false + + tasks: + - name Rename group1 to newgroup1 and group2 to newgroup2 + ipagroup: + ipaadmin_password: SomeADMINpassword + groups: + - name: group1 + rename: newgroup1 + - name: group2 + rename: newgroup2 + state: renamed +``` + Example playbook to add users to a group: ```yaml @@ -262,11 +301,13 @@ Variable | Description | Required `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 +`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` or `absent`, default: `present`. | yes +`state` | The state to ensure. It can be one of `present`, `absent` or `renamed`, default: `present`. | yes Authors ======= -Thomas Woerner +- Thomas Woerner +- Rafael Jeffman diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py index b80061663c..70d85cb833 100644 --- a/plugins/modules/ipagroup.py +++ b/plugins/modules/ipagroup.py @@ -123,6 +123,11 @@ required: false type: list elements: str + rename: + description: Rename the group object + required: false + type: str + aliases: ["new_name"] description: description: The group description type: str @@ -198,11 +203,16 @@ type: str default: group choices: ["member", "group"] + rename: + description: Rename the group object + required: false + type: str + aliases: ["new_name"] state: description: State to ensure type: str default: present - choices: ["present", "absent"] + choices: ["present", "absent", "renamed"] author: - Thomas Woerner (@t-woerner) """ @@ -267,6 +277,13 @@ group: - group2 +# Rename a group +- ipagroup: + ipaadmin_password: SomeADMINpassword + name: oldname + rename: newestname + state: renamed + # Create a non-POSIX group - ipagroup: ipaadmin_password: SomeADMINpassword @@ -380,18 +397,20 @@ def gen_member_args(user, group, service, externalmember, idoverrideuser): def check_parameters(module, state, action): - invalid = [] - if state == "present": + invalid = ["description", "gid", "posix", "nonposix", "external", + "nomembers"] + if action == "group": + if state == "present": + invalid = [] + elif state == "absent": + invalid.extend(["user", "group", "service", "externalmember"]) + if state == "renamed": if action == "member": - invalid = ["description", "gid", "posix", "nonposix", "external", - "nomembers"] - + module.fail_json( + msg="Action member can not be used with state: renamed.") + invalid.extend(["user", "group", "service", "externalmember"]) else: - invalid = ["description", "gid", "posix", "nonposix", "external", - "nomembers"] - if action == "group": - invalid.extend(["user", "group", "service", "externalmember"]) - + invalid.append("rename") module.params_fail_used_invalid(invalid, state, action) @@ -448,7 +467,9 @@ def main(): aliases=[ "ipaexternalmember", "external_member" - ]) + ]), + rename=dict(type="str", required=False, default=None, + aliases=["new_name"]), ) ansible_module = IPAAnsibleModule( argument_spec=dict( @@ -470,7 +491,7 @@ def main(): action=dict(type="str", default="group", choices=["member", "group"]), state=dict(type="str", default="present", - choices=["present", "absent"]), + choices=["present", "absent", "renamed"]), # Add group specific parameters for simple use case **group_spec @@ -506,8 +527,10 @@ def main(): membermanager_user = ansible_module.params_get("membermanager_user") membermanager_group = ansible_module.params_get("membermanager_group") externalmember = ansible_module.params_get("externalmember") + # rename + rename = ansible_module.params_get("rename") + # state and action action = ansible_module.params_get("action") - # state state = ansible_module.params_get("state") # Check parameters @@ -516,10 +539,11 @@ def main(): (groups is None or len(groups) < 1): ansible_module.fail_json(msg="At least one name or groups is required") - if state == "present": + if state in ["present", "renamed"]: if names is not None and len(names) != 1: + what = "renamed" if state == "renamed" else "added" ansible_module.fail_json( - msg="Only one group can be added at a time using 'name'.") + msg="Only one group can be %s at a time using 'name'." % what) check_parameters(ansible_module, state, action) @@ -633,6 +657,7 @@ def main(): membermanager_group = group_name.get("membermanager_group") externalmember = group_name.get("externalmember") nomembers = group_name.get("nomembers") + rename = group_name.get("rename") check_parameters(ansible_module, state, action) @@ -794,6 +819,11 @@ def main(): membermanager_group, res_find.get("membermanager_group") ) + elif state == "renamed": + if res_find is None: + ansible_module.fail_json(msg="No group '%s'" % name) + elif rename != name: + commands.append([name, 'group_mod', {"rename": rename}]) else: ansible_module.fail_json(msg="Unkown state '%s'" % state) diff --git a/tests/group/test_group.yml b/tests/group/test_group.yml index 4a26400753..8cb76946d2 100644 --- a/tests/group/test_group.yml +++ b/tests/group/test_group.yml @@ -3,6 +3,13 @@ hosts: "{{ ipa_test_host | default('ipaserver') }}" become: true gather_facts: true + module_defaults: + ipauser: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + ipagroup: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" tasks: # setup @@ -19,24 +26,18 @@ - name: Ensure users user1, user2 and user3 are absent ipauser: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: user1,user2,user3 state: absent - name: Ensure group group3, group2 and group1 are absent ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" - name: group3,group2,group1 + name: groupren,group3,group2,group1 state: absent # CREATE TEST ITEMS - name: Ensure users user1..user3 are present ipauser: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" users: - name: user1 first: user1 @@ -54,56 +55,74 @@ - name: Ensure group1 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 register: result failed_when: not result.changed or result.failed - name: Ensure group1 is present again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 register: result failed_when: result.changed or result.failed + - name: Rename group1 to groupren + ipagroup: + name: group1 + rename: groupren + state: renamed + register: result + failed_when: not result.changed or result.failed + + - name: Rename group1 to groupren + ipagroup: + name: group1 + rename: groupren + state: renamed + register: result + failed_when: not result.failed or "No group 'group1'" not in result.msg + + - name: Rename group groupren to groupren + ipagroup: + name: groupren + rename: groupren + state: renamed + register: result + failed_when: result.changed or result.failed + + - name: Rename group groupren back to group1 + ipagroup: + name: groupren + rename: group1 + state: renamed + register: result + failed_when: not result.changed or result.failed + - name: Ensure group2 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group2 register: result failed_when: not result.changed or result.failed - name: Ensure group2 is present again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group2 register: result failed_when: result.changed or result.failed - name: Ensure group3 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group3 register: result failed_when: not result.changed or result.failed - name: Ensure group3 is present again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group3 register: result failed_when: result.changed or result.failed - name: Ensure groups group2 and group3 are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 group: - group2 @@ -114,8 +133,6 @@ - name: Ensure groups group2 and group3 are present in group group1 again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 group: - group2 @@ -126,8 +143,6 @@ - name: Ensure group3 ia present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 group: - group3 @@ -143,8 +158,6 @@ - name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -154,8 +167,6 @@ - name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -165,8 +176,6 @@ - name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'ldap/' + fqdn_at_domain }}" @@ -176,8 +185,6 @@ - name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'ldap/' + fqdn_at_domain }}" @@ -187,8 +194,6 @@ - name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -199,8 +204,6 @@ - name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -211,8 +214,6 @@ - name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'ldap/' + fqdn_at_domain }}" @@ -223,8 +224,6 @@ - name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'ldap/' + fqdn_at_domain }}" @@ -235,8 +234,6 @@ - name: Ensure services are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -247,8 +244,6 @@ - name: Ensure services are present in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'http/' + fqdn_at_domain }}" @@ -259,8 +254,6 @@ - name: Ensure services are absent in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -272,8 +265,6 @@ - name: Ensure services are absent in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 service: - "{{ 'HTTP/' + fqdn_at_domain }}" @@ -287,8 +278,6 @@ - name: Ensure users user1, user2 and user3 are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -300,8 +289,6 @@ - name: Ensure users user1, user2 and user3 are present in group group1 again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -312,8 +299,6 @@ failed_when: result.changed or result.failed #- ipagroup: - # ipaadmin_password: SomeADMINpassword - # ipaapi_context: "{{ ipa_context | default(omit) }}" # name: group1 # user: # - user7 @@ -321,8 +306,6 @@ - name: Ensure user user7 is absent in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user7 @@ -333,8 +316,6 @@ - name: Ensure group group4 is absent ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group4 state: absent register: result @@ -342,8 +323,6 @@ - name: Ensure groups group3, group2, and group1 are absent ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group3,group2,group1 state: absent register: result @@ -351,16 +330,12 @@ - name: Ensure group group1 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 register: result failed_when: not result.changed or result.failed - name: Ensure users user1, user2 are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -371,8 +346,6 @@ - name: Ensure users user1, user2 and user3 are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -384,8 +357,6 @@ - name: Ensure users user1, user2 are present in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -396,8 +367,6 @@ - name: Ensure users user1, user2 and user3 are present in group group1, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -409,8 +378,6 @@ - name: Ensure group group1 is absent ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 state: absent register: result @@ -418,8 +385,6 @@ - name: Ensure group group1 with users user1, user2 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -429,8 +394,6 @@ - name: Ensure group group1 with users user1, user2 and user3 is present ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -441,8 +404,6 @@ - name: Ensure group group1 with users user1, user2 and user3 is present, again ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -454,8 +415,6 @@ - name: Ensure only users user1, user2 are present in group group1 ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group1 user: - user1 @@ -467,8 +426,6 @@ - name: Ensure group group3, group2 and group1 are absent ipagroup: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: group3,group2,group1 state: absent register: result @@ -476,8 +433,6 @@ - name: Ensure users user1, user2 and user3 are absent ipauser: - ipaadmin_password: SomeADMINpassword - ipaapi_context: "{{ ipa_context | default(omit) }}" name: user1,user2,user3 state: absent register: result diff --git a/tests/group/test_groups.yml b/tests/group/test_groups.yml index 648b35b878..2e0d3a8c7f 100644 --- a/tests/group/test_groups.yml +++ b/tests/group/test_groups.yml @@ -19,7 +19,7 @@ - name: Remove test groups ipagroup: ipaadmin_password: SomeADMINpassword - name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10 + name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10,newgroup1,newgroup2 state: absent - name: Remove test users @@ -130,10 +130,53 @@ register: result failed_when: result.changed or not result.failed or "Only one group can be added at a time using 'name'." not in result.msg + - name: Ensure group1 and group2 exist + ipagroup: + ipaadmin_password: SomeADMINpassword + groups: + - name: group1 + - name: group2 + + - name: Rename group1 and group2 to newgroup1 and newgroup2, respectively + ipagroup: + ipaadmin_password: SomeADMINpassword + groups: + - name: group1 + rename: newgroup1 + - name: group2 + rename: newgroup2 + state: renamed + register: result + failed_when: not result.changed or result.failed + + - name: Rename newgroup1 and newgroup2 to the same name + ipagroup: + ipaadmin_password: SomeADMINpassword + groups: + - name: newgroup1 + rename: newgroup1 + - name: newgroup2 + rename: newgroup2 + state: renamed + register: result + failed_when: result.changed or result.failed + + - name: Rename newgroup1 and newgroup2 back to group1 and group2, respectively + ipagroup: + ipaadmin_password: SomeADMINpassword + groups: + - name: newgroup1 + rename: group1 + - name: newgroup2 + rename: group2 + state: renamed + register: result + failed_when: not result.changed or result.failed + - name: Remove test groups ipagroup: ipaadmin_password: SomeADMINpassword - name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10 + name: group1,group2,group3,group4,group5,group6,group7,group8,group9,group10,newgroup1,newgroup2 state: absent - name: Remove test users