Repository: ansible/ansible

Issue:
user module on HP-UX cannot append secondary-groups
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
user module

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
- Runnning Ansible on CentOS 7.3
- Managing to HP-UX 11i v3

##### SUMMARY
<!--- Explain the problem briefly -->
On HP-UX, user.py cannot **append** secondary groups.
Because **usermod.sam** command  on HP-UX (not only 11i v3, but also 11i v2)
have neither -A nor -a option.

So, function **modify_user** ("if self.groups is not None:" caluse) in HPUX subclass
 implements like FreeBsdUser or SunOS subclass , I think.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Run playbook like playbooks as follow,
- assign groupA to testuser is OK   (1st time use create_user function)
- assign groupB to testuser is FAIL (2nd time use modify_user function)
 
<!--- Paste example playbooks or commands between quotes below -->
```yaml
- hosts: hpux
  become: yes
  vars:
    mygroup: [ 'groupA', 'groupB' ]
  tasks:
    - name: make group
      group:
        state: present
        name: "{{ item }}"
      with_items: [ 'groupA', 'groupB' ]
    - name: make user
      user:
        state: present
        name: testuser
        append: yes
        groups: "{{ item }}"
      with_items: [ 'groupA', 'groupB' ]
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Success to **append** secondary-groups multi-times.


##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
$ ansible-playbook -K -i hosts test.yml
SUDO password:

PLAY [hpux] ********************************************************************


TASK [make group] **************************************************************

changed: [hpux.foobar.com] => (item=groupA)
changed: [hpux.foobar.com] => (item=groupB)

TASK [make user] ***************************************************************

changed: [hpux.foobar.com] => (item=groupA)
failed: [hpux.foobar.com] (item=groupB) => {"failed": true, "item": "groupB", "msg": "Unrecognized Option 'A'\nUsage: usermod.sam [-F] [-p <encrypted-password>] [-u <uid> [-o]] [-g <group>] [-G <group>[,<group...>]] [-d <dir> [-m] [-i]] [-s <shell>] [-c <comment>] [-f <inactive>] [-e <expire>] [-l <new
logname>] [-P -S <alternate password file>] <login>\n", "name": "testuser", "rc": 2}

PLAY RECAP *********************************************************************

hpux.foobar.com  : ok=1    changed=1    unreachable=0    failed=1

$
```

user module on HP-UX cannot append secondary-groups
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
user module

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.3.0.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
- Runnning Ansible on CentOS 7.3
- Managing to HP-UX 11i v3

##### SUMMARY
<!--- Explain the problem briefly -->
On HP-UX, user.py cannot **append** secondary groups.
Because **usermod.sam** command  on HP-UX (not only 11i v3, but also 11i v2)
have neither -A nor -a option.

So, function **modify_user** ("if self.groups is not None:" caluse) in HPUX subclass
 implements like FreeBsdUser or SunOS subclass , I think.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Run playbook like playbooks as follow,
- assign groupA to testuser is OK   (1st time use create_user function)
- assign groupB to testuser is FAIL (2nd time use modify_user function)
 
<!--- Paste example playbooks or commands between quotes below -->
```yaml
- hosts: hpux
  become: yes
  vars:
    mygroup: [ 'groupA', 'groupB' ]
  tasks:
    - name: make group
      group:
        state: present
        name: "{{ item }}"
      with_items: [ 'groupA', 'groupB' ]
    - name: make user
      user:
        state: present
        name: testuser
        append: yes
        groups: "{{ item }}"
      with_items: [ 'groupA', 'groupB' ]
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Success to **append** secondary-groups multi-times.


##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
$ ansible-playbook -K -i hosts test.yml
SUDO password:

PLAY [hpux] ********************************************************************


TASK [make group] **************************************************************

changed: [hpux.foobar.com] => (item=groupA)
changed: [hpux.foobar.com] => (item=groupB)

TASK [make user] ***************************************************************

changed: [hpux.foobar.com] => (item=groupA)
failed: [hpux.foobar.com] (item=groupB) => {"failed": true, "item": "groupB", "msg": "Unrecognized Option 'A'\nUsage: usermod.sam [-F] [-p <encrypted-password>] [-u <uid> [-o]] [-g <group>] [-G <group>[,<group...>]] [-d <dir> [-m] [-i]] [-s <shell>] [-c <comment>] [-f <inactive>] [-e <expire>] [-l <new
logname>] [-P -S <alternate password file>] <login>\n", "name": "testuser", "rc": 2}

PLAY RECAP *********************************************************************

hpux.foobar.com  : ok=1    changed=1    unreachable=0    failed=1

$
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py
--- a/lib/ansible/modules/system/user.py
+++ b/lib/ansible/modules/system/user.py
@@ -2068,20 +2068,17 @@ def modify_user(self):
                     if self.append:
                         for g in groups:
                             if g in group_diff:
-                                if has_append:
-                                    cmd.append('-a')
                                 groups_need_mod = True
                                 break
                     else:
                         groups_need_mod = True
 
             if groups_need_mod:
-                if self.append and not has_append:
-                    cmd.append('-A')
-                    cmd.append(','.join(group_diff))
-                else:
-                    cmd.append('-G')
-                    cmd.append(','.join(groups))
+                cmd.append('-G')
+                new_groups = groups
+                if self.append:
+                    new_groups = groups | set(current_groups)
+                cmd.append(','.join(new_groups))
 
 
         if self.comment is not None and info[4] != self.comment:


Test patch: