diff options
author | Todd Lewis <utoddl@email.unc.edu> | 2020-02-06 12:32:44 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-06 12:32:44 -0500 |
commit | 640bf31f872a82102d518855a0e83af7472db449 (patch) | |
tree | 539e39ceb0a7c2332f7018bd7e65ceb89c9f6745 | |
parent | c3635532d3047ff944761005790d4be1111a8f72 (diff) | |
download | ansible-640bf31f872a82102d518855a0e83af7472db449.tar.gz |
user - allow 'groups', 'append' with 'local' (#62134)
-rw-r--r-- | changelogs/fragments/62134-user-allow-groups-and-append-with-local.yml | 2 | ||||
-rw-r--r-- | lib/ansible/modules/system/user.py | 82 | ||||
-rw-r--r-- | test/integration/targets/user/tasks/main.yml | 40 |
3 files changed, 93 insertions, 31 deletions
diff --git a/changelogs/fragments/62134-user-allow-groups-and-append-with-local.yml b/changelogs/fragments/62134-user-allow-groups-and-append-with-local.yml new file mode 100644 index 0000000000..5d3e291fbf --- /dev/null +++ b/changelogs/fragments/62134-user-allow-groups-and-append-with-local.yml @@ -0,0 +1,2 @@ +minor_changes: + - user - allow groups, append parameters with local diff --git a/lib/ansible/modules/system/user.py b/lib/ansible/modules/system/user.py index 2fada8d0fd..23a2eb1bf9 100644 --- a/lib/ansible/modules/system/user.py +++ b/lib/ansible/modules/system/user.py @@ -59,14 +59,12 @@ options: - List of groups user will be added to. When set to an empty string C(''), the user is removed from all groups except the primary group. - Before Ansible 2.3, the only input format allowed was a comma separated string. - - Mutually exclusive with C(local) type: list append: description: - If C(yes), add the user to the groups specified in C(groups). - If C(no), user will only be added to the groups specified in C(groups), removing them from all other groups. - - Mutually exclusive with C(local) type: bool default: no shell: @@ -211,7 +209,6 @@ options: - This will check C(/etc/passwd) for an existing account before invoking commands. If the local account database exists somewhere other than C(/etc/passwd), this setting will not work properly. - This requires that the above commands as well as C(/etc/passwd) must exist on the target host, otherwise it will be a fatal error. - - Mutually exclusive with C(groups) and C(append) type: bool default: no version_added: "2.4" @@ -573,7 +570,7 @@ class User(object): command_name = 'userdel' cmd = [self.module.get_bin_path(command_name, True)] - if self.force: + if self.force and not self.local: cmd.append('-f') if self.remove: cmd.append('-r') @@ -585,6 +582,7 @@ class User(object): if self.local: command_name = 'luseradd' + lgroupmod_cmd = self.module.get_bin_path('lgroupmod', True) else: command_name = 'useradd' @@ -613,7 +611,7 @@ class User(object): if os.path.exists('/etc/redhat-release'): dist = distro.linux_distribution(full_distribution_name=False) major_release = int(dist[1].split('.')[0]) - if major_release <= 5: + if major_release <= 5 or self.local: cmd.append('-n') else: cmd.append('-N') @@ -627,10 +625,11 @@ class User(object): else: cmd.append('-N') - if self.groups is not None and not self.local and len(self.groups): + if self.groups is not None and len(self.groups): groups = self.get_groups_set() - cmd.append('-G') - cmd.append(','.join(groups)) + if not self.local: + cmd.append('-G') + cmd.append(','.join(groups)) if self.comment is not None: cmd.append('-c') @@ -675,7 +674,17 @@ class User(object): cmd.append('-r') cmd.append(self.name) - return self.execute_command(cmd) + (rc, err, out) = self.execute_command(cmd) + if not self.local or rc != 0 or self.groups is None or len(self.groups) == 0: + return (rc, err, out) + + for add_group in groups: + (rc, _err, _out) = self.execute_command([lgroupmod_cmd, '-M', self.name, add_group]) + out += _out + err += _err + if rc != 0: + return (rc, out, err) + return (rc, out, err) def _check_usermod_append(self): # check if this version of usermod can append groups @@ -708,6 +717,9 @@ class User(object): if self.local: command_name = 'lusermod' + lgroupmod_cmd = self.module.get_bin_path('lgroupmod', True) + lgroupmod_add = set() + lgroupmod_del = set() else: command_name = 'usermod' @@ -754,13 +766,21 @@ class User(object): else: groups_need_mod = True - if groups_need_mod and not self.local: - if self.append and not has_append: - cmd.append('-A') - cmd.append(','.join(group_diff)) + if groups_need_mod: + if self.local: + if self.append: + lgroupmod_add = set(groups).difference(current_groups) + lgroupmod_del = set() + else: + lgroupmod_add = set(groups).difference(current_groups) + lgroupmod_del = set(current_groups).difference(groups) else: - cmd.append('-G') - cmd.append(','.join(groups)) + if self.append and not has_append: + cmd.append('-A') + cmd.append(','.join(group_diff)) + else: + cmd.append('-G') + cmd.append(','.join(groups)) if self.comment is not None and info[4] != self.comment: cmd.append('-c') @@ -804,12 +824,30 @@ class User(object): cmd.append('-p') cmd.append(self.password) - # skip if no changes to be made - if len(cmd) == 1: - return (None, '', '') + (rc, err, out) = (None, '', '') - cmd.append(self.name) - return self.execute_command(cmd) + # skip if no usermod changes to be made + if len(cmd) > 1: + cmd.append(self.name) + (rc, err, out) = self.execute_command(cmd) + + if not self.local or not (rc is None or rc == 0) or (len(lgroupmod_add) == 0 and len(lgroupmod_del) == 0): + return (rc, err, out) + + for add_group in lgroupmod_add: + (rc, _err, _out) = self.execute_command([lgroupmod_cmd, '-M', self.name, add_group]) + out += _out + err += _err + if rc != 0: + return (rc, out, err) + + for del_group in lgroupmod_del: + (rc, _err, _out) = self.execute_command([lgroupmod_cmd, '-m', self.name, del_group]) + out += _out + err += _err + if rc != 0: + return (rc, out, err) + return (rc, out, err) def group_exists(self, group): try: @@ -2873,10 +2911,6 @@ def main(): role=dict(type='str'), ), supports_check_mode=True, - mutually_exclusive=[ - ('local', 'groups'), - ('local', 'append') - ] ) user = User(module) diff --git a/test/integration/targets/user/tasks/main.yml b/test/integration/targets/user/tasks/main.yml index 8fd23904a0..25fc9f8c68 100644 --- a/test/integration/targets/user/tasks/main.yml +++ b/test/integration/targets/user/tasks/main.yml @@ -789,6 +789,7 @@ name: ansibulluser state: present generate_ssh_key: yes + force: yes ssh_key_file: "{{ output_dir }}/test_id_rsa" ssh_key_passphrase: secret_passphrase @@ -994,9 +995,14 @@ tags: - user_test_local_mode -- name: Create test group +- name: Create test groups group: - name: testgroup + name: "{{ item }}" + loop: + - testgroup1 + - testgroup2 + - testgroup3 + - testgroup4 tags: - user_test_local_mode @@ -1005,7 +1011,7 @@ name: local_ansibulluser state: present local: yes - groups: testgroup + groups: ['testgroup1', 'testgroup2'] register: local_user_test_3 ignore_errors: yes tags: @@ -1016,6 +1022,7 @@ name: local_ansibulluser state: present local: yes + groups: ['testgroup3', 'testgroup4'] append: yes register: local_user_test_4 ignore_errors: yes @@ -1032,15 +1039,34 @@ tags: - user_test_local_mode +- name: Remove local_ansibulluser again + user: + name: local_ansibulluser + state: absent + remove: yes + local: yes + tags: + - user_test_local_mode + +- name: Remove test groups + group: + name: "{{ item }}" + state: absent + loop: + - testgroup1 + - testgroup2 + - testgroup3 + - testgroup4 + tags: + - user_test_local_mode + - name: Ensure local user accounts were created and removed properly assert: that: - local_user_test_1 is changed - local_user_test_2 is not changed - - local_user_test_3 is failed - - 'local_user_test_3["msg"] is search("parameters are mutually exclusive: groups|local")' - - local_user_test_4 is failed - - 'local_user_test_4["msg"] is search("parameters are mutually exclusive: groups|append")' + - local_user_test_3 is changed + - local_user_test_4 is changed - local_user_test_remove_1 is changed - local_user_test_remove_2 is not changed tags: |