Repository: ansible-collections/community.general

Issue:
Make it possible to add a single user to a group with ipa_group
### Summary

I'm trying to create a user and add it to an existing group. ~~This is not possible with ipa_group as it expects a full member list.~~ I realized that calling the method without user list will return the current member list, and then I can call it again appending then new user. Feel like a hack, so I think this is still a valid use case

### Issue Type

Feature Idea

### Component Name

ipa_group

### Additional Information

_No response_

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/identity/ipa/ipa_group.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/identity/ipa/ipa_group.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @Akasurde @Nosmoht @fxfitz @justchris1
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/plugins/module_utils/ipa.py b/plugins/module_utils/ipa.py
--- a/plugins/module_utils/ipa.py
+++ b/plugins/module_utils/ipa.py
@@ -178,10 +178,10 @@ def get_diff(self, ipa_data, module_data):
                 result.append(key)
         return result
 
-    def modify_if_diff(self, name, ipa_list, module_list, add_method, remove_method, item=None):
+    def modify_if_diff(self, name, ipa_list, module_list, add_method, remove_method, item=None, append=None):
         changed = False
         diff = list(set(ipa_list) - set(module_list))
-        if len(diff) > 0:
+        if append is not True and len(diff) > 0:
             changed = True
             if not self.module.check_mode:
                 if item:
diff --git a/plugins/modules/identity/ipa/ipa_group.py b/plugins/modules/identity/ipa/ipa_group.py
--- a/plugins/modules/identity/ipa/ipa_group.py
+++ b/plugins/modules/identity/ipa/ipa_group.py
@@ -14,6 +14,13 @@
 description:
 - Add, modify and delete group within IPA server
 options:
+  append:
+    description:
+    - If C(yes), add the listed I(user) and I(group) to the group members.
+    - If C(no), only the listed I(user) and I(group) will be group members, removing any other members.
+    default: no
+    type: bool
+    version_added: 4.0.0
   cn:
     description:
     - Canonical name.
@@ -37,9 +44,10 @@
   group:
     description:
     - List of group names assigned to this group.
-    - If an empty list is passed all groups will be removed from this group.
-    - If option is omitted assigned groups will not be checked or changed.
+    - If I(append=no) and an empty list is passed all groups will be removed from this group.
     - Groups that are already assigned but not passed will be removed.
+    - If I(append=yes) the listed groups will be assigned without removing other groups.
+    - If option is omitted assigned groups will not be checked or changed.
     type: list
     elements: str
   nonposix:
@@ -49,9 +57,10 @@
   user:
     description:
     - List of user names assigned to this group.
-    - If an empty list is passed all users will be removed from this group.
-    - If option is omitted assigned users will not be checked or changed.
+    - If I(append=no) and an empty list is passed all users will be removed from this group.
     - Users that are already assigned but not passed will be removed.
+    - If I(append=yes) the listed users will be assigned without removing other users.
+    - If option is omitted assigned users will not be checked or changed.
     type: list
     elements: str
   state:
@@ -95,6 +104,17 @@
     ipa_user: admin
     ipa_pass: topsecret
 
+- name: Ensure that new starter named john is member of the group, without removing other members
+  community.general.ipa_group:
+    name: developers
+    user:
+    - john
+    append: yes
+    state: present
+    ipa_host: ipa.example.com
+    ipa_user: admin
+    ipa_pass: topsecret
+
 - name: Ensure group is absent
   community.general.ipa_group:
     name: sysops
@@ -187,6 +207,7 @@ def ensure(module, client):
     name = module.params['cn']
     group = module.params['group']
     user = module.params['user']
+    append = module.params['append']
 
     module_group = get_group_dict(description=module.params['description'], external=module.params['external'],
                                   gid=module.params['gidnumber'], nonposix=module.params['nonposix'])
@@ -211,12 +232,14 @@ def ensure(module, client):
         if group is not None:
             changed = client.modify_if_diff(name, ipa_group.get('member_group', []), group,
                                             client.group_add_member_group,
-                                            client.group_remove_member_group) or changed
+                                            client.group_remove_member_group,
+                                            append=append) or changed
 
         if user is not None:
             changed = client.modify_if_diff(name, ipa_group.get('member_user', []), user,
                                             client.group_add_member_user,
-                                            client.group_remove_member_user) or changed
+                                            client.group_remove_member_user,
+                                            append=append) or changed
 
     else:
         if ipa_group:
@@ -236,7 +259,8 @@ def main():
                          group=dict(type='list', elements='str'),
                          nonposix=dict(type='bool'),
                          state=dict(type='str', default='present', choices=['present', 'absent']),
-                         user=dict(type='list', elements='str'))
+                         user=dict(type='list', elements='str'),
+                         append=dict(type='bool', default=False))
 
     module = AnsibleModule(argument_spec=argument_spec,
                            supports_check_mode=True,


Test patch: