summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Lewis <utoddl@email.unc.edu>2020-02-06 12:32:44 -0500
committerGitHub <noreply@github.com>2020-02-06 12:32:44 -0500
commit640bf31f872a82102d518855a0e83af7472db449 (patch)
tree539e39ceb0a7c2332f7018bd7e65ceb89c9f6745
parentc3635532d3047ff944761005790d4be1111a8f72 (diff)
downloadansible-640bf31f872a82102d518855a0e83af7472db449.tar.gz
user - allow 'groups', 'append' with 'local' (#62134)
-rw-r--r--changelogs/fragments/62134-user-allow-groups-and-append-with-local.yml2
-rw-r--r--lib/ansible/modules/system/user.py82
-rw-r--r--test/integration/targets/user/tasks/main.yml40
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: