1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

user: PEP8 compliancy and doc fixes (#30895)

This PR includes:
- PEP8 compliancy fixes
- Documentation fixes
This commit is contained in:
Dag Wieers 2017-10-30 01:06:37 +01:00 committed by GitHub
parent 63edeb1644
commit 86bb82a220
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 143 additions and 184 deletions

View file

@ -1,22 +1,21 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2012, Stephen Fromm <sfromm@gmail.com>
# Copyright: (c) 2012, Stephen Fromm <sfromm@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'core'}
DOCUMENTATION = '''
---
module: user
author: "Stephen Fromm (@sfromm)"
author:
- Stephen Fromm (@sfromm)
version_added: "0.2"
short_description: Manage user accounts
notes:
@ -29,67 +28,56 @@ description:
- For Windows targets, use the M(win_user) module instead.
options:
name:
required: true
aliases: [ "user" ]
description:
- Name of the user to create, remove or modify.
required: true
aliases: [ user ]
comment:
required: false
description:
- Optionally sets the description (aka I(GECOS)) of user account.
uid:
required: false
description:
- Optionally sets the I(UID) of the user.
non_unique:
required: false
default: "no"
choices: [ "yes", "no" ]
description:
- Optionally when used with the -u option, this option allows to
change the user ID to a non-unique value.
type: bool
default: "no"
version_added: "1.1"
seuser:
required: false
description:
- Optionally sets the seuser type (user_u) on selinux enabled systems.
version_added: "2.1"
group:
required: false
description:
- Optionally sets the user's primary group (takes a group name).
groups:
required: false
description:
- Puts the user in list of groups. When set to the empty string ('groups='),
the user is removed from all groups except the primary group.
- Before version 2.3, the only input format allowed was a 'comma separated string',
now it should be able to accept YAML lists also.
append:
required: false
default: "no"
choices: [ "yes", "no" ]
description:
- If C(yes), will only add groups, not set them to just the list
in I(groups).
type: bool
default: "no"
shell:
required: false
description:
- Optionally set the user's shell.
- On Mac OS X, before version 2.5, the default shell for non-system users was
/usr/bin/false. Since 2.5, the default shell for non-system users on
Mac OS X is /bin/bash.
home:
required: false
description:
- Optionally set the user's home directory.
skeleton:
required: false
description:
- Optionally set a home skeleton directory. Requires create_home option!
version_added: "2.0"
password:
required: false
description:
- Optionally set the user's password to this crypted value. See
the user example in the github examples directory for what this looks
@ -98,172 +86,157 @@ options:
Note on Darwin system, this value has to be cleartext.
Beware of security issues.
state:
required: false
default: "present"
choices: [ present, absent ]
description:
- Whether the account should exist or not, taking action if the state is different from what is stated.
choices: [ absent, present ]
default: present
create_home:
description:
- Unless set to C(no), a home directory will be made for the user
when the account is created or if the home directory does not
exist.
- Changed from C(createhome) to C(create_home) in version 2.5.
default: yes
type: bool
default: 'yes'
aliases: ['createhome']
move_home:
required: false
default: "no"
choices: [ "yes", "no" ]
description:
- If set to C(yes) when used with C(home=), attempt to move the
user's home directory to the specified directory if it isn't there
already.
system:
required: false
type: bool
default: "no"
choices: [ "yes", "no" ]
system:
description:
- When creating an account, setting this to C(yes) makes the user a
system account. This setting cannot be changed on existing users.
force:
required: false
type: bool
default: "no"
choices: [ "yes", "no" ]
force:
description:
- When used with C(state=absent), behavior is as with
C(userdel --force).
- When used with C(state=absent), behavior is as with C(userdel --force).
type: bool
default: "no"
login_class:
required: false
description:
- Optionally sets the user's login class for FreeBSD, OpenBSD and NetBSD systems.
remove:
required: false
default: "no"
choices: [ "yes", "no" ]
description:
- When used with C(state=absent), behavior is as with
C(userdel --remove).
generate_ssh_key:
required: false
- When used with C(state=absent), behavior is as with C(userdel --remove).
type: bool
default: "no"
choices: [ "yes", "no" ]
version_added: "0.9"
generate_ssh_key:
description:
- Whether to generate a SSH key for the user in question.
This will B(not) overwrite an existing SSH key.
ssh_key_bits:
required: false
default: default set by ssh-keygen
type: bool
default: "no"
version_added: "0.9"
ssh_key_bits:
description:
- Optionally specify number of bits in SSH key to create.
ssh_key_type:
required: false
default: rsa
default: default set by ssh-keygen
version_added: "0.9"
ssh_key_type:
description:
- Optionally specify the type of SSH key to generate.
Available SSH key types will depend on implementation
present on target host.
ssh_key_file:
required: false
default: .ssh/id_rsa
default: rsa
version_added: "0.9"
ssh_key_file:
description:
- Optionally specify the SSH key filename. If this is a relative
filename then it will be relative to the user's home directory.
ssh_key_comment:
required: false
default: ansible-generated on $HOSTNAME
default: .ssh/id_rsa
version_added: "0.9"
ssh_key_comment:
description:
- Optionally define the comment for the SSH key.
ssh_key_passphrase:
required: false
default: ansible-generated on $HOSTNAME
version_added: "0.9"
ssh_key_passphrase:
description:
- Set a passphrase for the SSH key. If no
passphrase is provided, the SSH key will default to
having no passphrase.
version_added: "0.9"
update_password:
required: false
default: always
choices: ['always', 'on_create']
version_added: "1.3"
description:
- C(always) will update passwords if they differ. C(on_create) will only set the password for newly created users.
choices: [ always, on_create ]
default: always
version_added: "1.3"
expires:
version_added: "1.9"
required: false
default: "None"
description:
- An expiry time for the user in epoch, it will be ignored on platforms that do not support this.
Currently supported on Linux and FreeBSD.
version_added: "1.9"
local:
version_added: "2.4"
required: false
default: "False"
description:
- Forces the use of "local" command alternatives on platforms that implement it.
This is useful in environments that use centralized authentification when you want to manipulate the local users.
I.E. it uses `luseradd` instead of `useradd`.
- This requires that these commands exist on the targeted host, otherwise it will be a fatal error.
type: bool
default: 'no'
version_added: "2.4"
'''
EXAMPLES = '''
# Add the user 'johnd' with a specific uid and a primary group of 'admin'
- user:
- name: Add the user 'johnd' with a specific uid and a primary group of 'admin'
user:
name: johnd
comment: "John Doe"
comment: John Doe
uid: 1040
group: admin
# Add the user 'james' with a bash shell, appending the group 'admins' and 'developers' to the user's groups
- user:
- name: Add the user 'james' with a bash shell, appending the group 'admins' and 'developers' to the user's groups
user:
name: james
shell: /bin/bash
groups: admins,developers
append: yes
# Remove the user 'johnd'
- user:
- name: Remove the user 'johnd'
user:
name: johnd
state: absent
remove: yes
# Create a 2048-bit SSH key for user jsmith in ~jsmith/.ssh/id_rsa
- user:
- name: Create a 2048-bit SSH key for user jsmith in ~jsmith/.ssh/id_rsa
user:
name: jsmith
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: .ssh/id_rsa
# added a consultant whose account you want to expire
- user:
- name: Added a consultant whose account you want to expire
user:
name: james18
shell: /bin/zsh
groups: developers
expires: 1422403387
'''
import os
import pwd
import grp
import os
import platform
import pwd
import shutil
import socket
import time
import shutil
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import load_platform_subclass, AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
try:
import spwd
HAVE_SPWD=True
HAVE_SPWD = True
except:
HAVE_SPWD=False
HAVE_SPWD = False
class User(object):
"""
@ -290,31 +263,31 @@ class User(object):
return load_platform_subclass(User, args, kwargs)
def __init__(self, module):
self.module = module
self.state = module.params['state']
self.name = module.params['name']
self.uid = module.params['uid']
self.non_unique = module.params['non_unique']
self.seuser = module.params['seuser']
self.group = module.params['group']
self.comment = module.params['comment']
self.shell = module.params['shell']
self.password = module.params['password']
self.force = module.params['force']
self.remove = module.params['remove']
self.module = module
self.state = module.params['state']
self.name = module.params['name']
self.uid = module.params['uid']
self.non_unique = module.params['non_unique']
self.seuser = module.params['seuser']
self.group = module.params['group']
self.comment = module.params['comment']
self.shell = module.params['shell']
self.password = module.params['password']
self.force = module.params['force']
self.remove = module.params['remove']
self.create_home = module.params['create_home']
self.move_home = module.params['move_home']
self.skeleton = module.params['skeleton']
self.system = module.params['system']
self.move_home = module.params['move_home']
self.skeleton = module.params['skeleton']
self.system = module.params['system']
self.login_class = module.params['login_class']
self.append = module.params['append']
self.sshkeygen = module.params['generate_ssh_key']
self.ssh_bits = module.params['ssh_key_bits']
self.ssh_type = module.params['ssh_key_type']
self.append = module.params['append']
self.sshkeygen = module.params['generate_ssh_key']
self.ssh_bits = module.params['ssh_key_bits']
self.ssh_type = module.params['ssh_key_type']
self.ssh_comment = module.params['ssh_key_comment']
self.ssh_passphrase = module.params['ssh_key_passphrase']
self.update_password = module.params['update_password']
self.home = module.params['home']
self.home = module.params['home']
self.expires = None
self.groups = None
self.local = module.params['local']
@ -327,18 +300,17 @@ class User(object):
self.expires = time.gmtime(module.params['expires'])
except Exception:
e = get_exception()
module.fail_json(msg="Invalid expires time %s: %s" %(self.expires, str(e)))
module.fail_json(msg="Invalid expires time %s: %s" % (self.expires, e))
if module.params['ssh_key_file'] is not None:
self.ssh_file = module.params['ssh_key_file']
else:
self.ssh_file = os.path.join('.ssh', 'id_%s' % self.ssh_type)
def execute_command(self, cmd, use_unsafe_shell=False, data=None, obey_checkmode=True):
if self.module.check_mode and obey_checkmode:
self.module.debug('In check mode, would have run: "%s"' % cmd)
return (0, '','')
return (0, '', '')
else:
# cast all args to strings ansible-modules-core/issues/4397
cmd = [str(x) for x in cmd]
@ -438,7 +410,6 @@ class User(object):
cmd.append(self.name)
return self.execute_command(cmd)
def _check_usermod_append(self):
# check if this version of usermod can append groups
@ -466,8 +437,6 @@ class User(object):
return False
def modify_user_usermod(self):
if self.local:
@ -555,7 +524,7 @@ class User(object):
cmd.append(self.name)
return self.execute_command(cmd)
def group_exists(self,group):
def group_exists(self, group):
try:
# Try group as a gid first
grp.getgrgid(int(group))
@ -693,7 +662,7 @@ class User(object):
ssh_key_file = self.get_ssh_key_path()
if not os.path.exists(ssh_key_file):
return (1, 'SSH Key file %s does not exist' % ssh_key_file, '')
cmd = [ self.module.get_bin_path('ssh-keygen', True) ]
cmd = [self.module.get_bin_path('ssh-keygen', True)]
cmd.append('-l')
cmd.append('-f')
cmd.append(ssh_key_file)
@ -835,7 +804,7 @@ class FreeBsdUser(User):
cmd.append(self.login_class)
if self.expires:
days =( time.mktime(self.expires) - time.time() ) // 86400
days = (time.mktime(self.expires) - time.time()) // 86400
cmd.append('-e')
cmd.append(str(int(days)))
@ -933,7 +902,7 @@ class FreeBsdUser(User):
cmd.append(','.join(new_groups))
if self.expires:
days = ( time.mktime(self.expires) - time.time() ) // 86400
days = (time.mktime(self.expires) - time.time()) // 86400
cmd.append('-e')
cmd.append(str(int(days)))
@ -957,7 +926,6 @@ class FreeBsdUser(User):
return (rc, out, err)
# ===========================================
class OpenBSDUser(User):
"""
@ -1502,7 +1470,7 @@ class SunOS(User):
return (rc, out, err)
# ===========================================
class DarwinUser(User):
"""
This is a Darwin Mac OS X User manipulation class.
@ -1535,11 +1503,11 @@ class DarwinUser(User):
]
def _get_dscl(self):
return [ self.module.get_bin_path('dscl', True), self.dscl_directory ]
return [self.module.get_bin_path('dscl', True), self.dscl_directory]
def _list_user_groups(self):
cmd = self._get_dscl()
cmd += [ '-search', '/Groups', 'GroupMembership', self.name ]
cmd += ['-search', '/Groups', 'GroupMembership', self.name]
(rc, out, err) = self.execute_command(cmd, obey_checkmode=False)
groups = []
for line in out.splitlines():
@ -1551,7 +1519,7 @@ class DarwinUser(User):
def _get_user_property(self, property):
'''Return user PROPERTY as given my dscl(1) read or None if not found.'''
cmd = self._get_dscl()
cmd += [ '-read', '/Users/%s' % self.name, property ]
cmd += ['-read', '/Users/%s' % self.name, property]
(rc, out, err) = self.execute_command(cmd, obey_checkmode=False)
if rc != 0:
return None
@ -1559,12 +1527,12 @@ class DarwinUser(User):
# if property contains embedded spaces, the list will instead be
# displayed one entry per line, starting on the line after the key.
lines = out.splitlines()
#sys.stderr.write('*** |%s| %s -> %s\n' % (property, out, lines))
# sys.stderr.write('*** |%s| %s -> %s\n' % (property, out, lines))
if len(lines) == 1:
return lines[0].split(': ')[1]
else:
if len(lines) > 2:
return '\n'.join([ lines[1].strip() ] + lines[2:])
return '\n'.join([lines[1].strip()] + lines[2:])
else:
if len(lines) == 2:
return lines[1].strip()
@ -1614,9 +1582,9 @@ class DarwinUser(User):
# https://gist.github.com/nueh/8252572
cmd = self._get_dscl()
if self.password:
cmd += [ '-passwd', '/Users/%s' % self.name, self.password]
cmd += ['-passwd', '/Users/%s' % self.name, self.password]
else:
cmd += [ '-create', '/Users/%s' % self.name, 'Password', '*']
cmd += ['-create', '/Users/%s' % self.name, 'Password', '*']
(rc, out, err) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json(msg='Error when changing password', err=err, out=out, rc=rc)
@ -1640,7 +1608,7 @@ class DarwinUser(User):
option = '-a'
else:
option = '-d'
cmd = [ 'dseditgroup', '-o', 'edit', option, self.name, '-t', 'user', group ]
cmd = ['dseditgroup', '-o', 'edit', option, self.name, '-t', 'user', group]
(rc, out, err) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json(msg='Cannot %s user "%s" to group "%s".'
@ -1687,7 +1655,7 @@ class DarwinUser(User):
plist_file = '/Library/Preferences/com.apple.loginwindow.plist'
# http://support.apple.com/kb/HT5017?viewlocale=en_US
cmd = [ 'defaults', 'read', plist_file, 'HiddenUsersList' ]
cmd = ['defaults', 'read', plist_file, 'HiddenUsersList']
(rc, out, err) = self.execute_command(cmd, obey_checkmode=False)
# returned value is
# (
@ -1704,27 +1672,26 @@ class DarwinUser(User):
hidden_users.append(x)
if self.system:
if not self.name in hidden_users:
cmd = [ 'defaults', 'write', plist_file,
'HiddenUsersList', '-array-add', self.name ]
if self.name not in hidden_users:
cmd = ['defaults', 'write', plist_file, 'HiddenUsersList', '-array-add', self.name]
(rc, out, err) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json( msg='Cannot user "%s" to hidden user list.' % self.name, err=err, out=out, rc=rc)
self.module.fail_json(msg='Cannot user "%s" to hidden user list.' % self.name, err=err, out=out, rc=rc)
return 0
else:
if self.name in hidden_users:
del(hidden_users[hidden_users.index(self.name)])
cmd = [ 'defaults', 'write', plist_file, 'HiddenUsersList', '-array' ] + hidden_users
cmd = ['defaults', 'write', plist_file, 'HiddenUsersList', '-array'] + hidden_users
(rc, out, err) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json( msg='Cannot remove user "%s" from hidden user list.' % self.name, err=err, out=out, rc=rc)
self.module.fail_json(msg='Cannot remove user "%s" from hidden user list.' % self.name, err=err, out=out, rc=rc)
return 0
def user_exists(self):
'''Check is SELF.NAME is a known user on the system.'''
cmd = self._get_dscl()
cmd += [ '-list', '/Users/%s' % self.name]
cmd += ['-list', '/Users/%s' % self.name]
(rc, out, err) = self.execute_command(cmd, obey_checkmode=False)
return rc == 0
@ -1733,11 +1700,11 @@ class DarwinUser(User):
info = self.user_info()
cmd = self._get_dscl()
cmd += [ '-delete', '/Users/%s' % self.name]
cmd += ['-delete', '/Users/%s' % self.name]
(rc, out, err) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json( msg='Cannot delete user "%s".' % self.name, err=err, out=out, rc=rc)
self.module.fail_json(msg='Cannot delete user "%s".' % self.name, err=err, out=out, rc=rc)
if self.force:
if os.path.exists(info[5]):
@ -1748,11 +1715,10 @@ class DarwinUser(User):
def create_user(self, command_name='dscl'):
cmd = self._get_dscl()
cmd += [ '-create', '/Users/%s' % self.name]
cmd += ['-create', '/Users/%s' % self.name]
(rc, err, out) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json( msg='Cannot create user "%s".' % self.name, err=err, out=out, rc=rc)
self.module.fail_json(msg='Cannot create user "%s".' % self.name, err=err, out=out, rc=rc)
self._make_group_numerical()
if self.uid is None:
@ -1776,18 +1742,16 @@ class DarwinUser(User):
if field[0] in self.__dict__ and self.__dict__[field[0]]:
cmd = self._get_dscl()
cmd += [ '-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]]
cmd += ['-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]]
(rc, _err, _out) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json( msg='Cannot add property "%s" to user "%s".'
% (field[0], self.name), err=err, out=out, rc=rc)
self.module.fail_json(msg='Cannot add property "%s" to user "%s".' % (field[0], self.name), err=err, out=out, rc=rc)
out += _out
err += _err
if rc != 0:
return (rc, _err, _out)
(rc, _err, _out) = self._change_user_password()
out += _out
err += _err
@ -1814,7 +1778,7 @@ class DarwinUser(User):
current = self._get_user_property(field[1])
if current is None or current != self.__dict__[field[0]]:
cmd = self._get_dscl()
cmd += [ '-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]]
cmd += ['-create', '/Users/%s' % self.name, field[1], self.__dict__[field[0]]]
(rc, _err, _out) = self.execute_command(cmd)
if rc != 0:
self.module.fail_json(
@ -1843,7 +1807,6 @@ class DarwinUser(User):
return (changed, out, err)
# ===========================================
class AIX(User):
"""
@ -1990,11 +1953,10 @@ class AIX(User):
(rc2, out2, err2) = (None, '', '')
if rc is not None:
return (rc, out+out2, err+err2)
return (rc, out + out2, err + err2)
else:
return (rc2, out+out2, err+err2)
return (rc2, out + out2, err + err2)
# ===========================================
class HPUX(User):
"""
@ -2115,7 +2077,6 @@ class HPUX(User):
new_groups = groups | set(current_groups)
cmd.append(','.join(new_groups))
if self.comment is not None and info[4] != self.comment:
cmd.append('-c')
cmd.append(self.comment)
@ -2141,49 +2102,48 @@ class HPUX(User):
cmd.append(self.name)
return self.execute_command(cmd)
# ===========================================
def main():
ssh_defaults = {
'bits': 0,
'type': 'rsa',
'passphrase': None,
'comment': 'ansible-generated on %s' % socket.gethostname()
}
ssh_defaults = dict(
bits=0,
type='rsa',
passphrase=None,
comment='ansible-generated on %s' % socket.gethostname()
)
module = AnsibleModule(
argument_spec = dict(
state=dict(default='present', choices=['present', 'absent'], type='str'),
name=dict(required=True, aliases=['user'], type='str'),
uid=dict(default=None, type='str'),
non_unique=dict(default='no', type='bool'),
group=dict(default=None, type='str'),
groups=dict(default=None, type='list'),
comment=dict(default=None, type='str'),
home=dict(default=None, type='path'),
shell=dict(default=None, type='str'),
password=dict(default=None, type='str', no_log=True),
login_class=dict(default=None, type='str'),
argument_spec=dict(
state=dict(type='str', default='present', choices=['absent', 'present']),
name=dict(type='str', required=True, aliases=['user']),
uid=dict(type='str'),
non_unique=dict(type='bool', default=False),
group=dict(type='str'),
groups=dict(type='list'),
comment=dict(type='str'),
home=dict(type='path'),
shell=dict(type='str'),
password=dict(type='str', no_log=True),
login_class=dict(type='str'),
# following options are specific to selinux
seuser=dict(default=None, type='str'),
seuser=dict(type='str'),
# following options are specific to userdel
force=dict(default='no', type='bool'),
remove=dict(default='no', type='bool'),
force=dict(type='bool', default=False),
remove=dict(type='bool', default=False),
# following options are specific to useradd
create_home=dict(default='yes', aliases=['createhome'], type='bool'),
skeleton=dict(default=None, type='str'),
system=dict(default='no', type='bool'),
create_home=dict(type='bool', default=True, aliases=['createhome']),
skeleton=dict(type='str'),
system=dict(type='bool', default=False),
# following options are specific to usermod
move_home=dict(default='no', type='bool'),
append=dict(default='no', type='bool'),
move_home=dict(type='bool', default=False),
append=dict(type='bool', default=False),
# following are specific to ssh key generation
generate_ssh_key=dict(type='bool'),
ssh_key_bits=dict(default=ssh_defaults['bits'], type='int'),
ssh_key_type=dict(default=ssh_defaults['type'], type='str'),
ssh_key_file=dict(default=None, type='path'),
ssh_key_comment=dict(default=ssh_defaults['comment'], type='str'),
ssh_key_passphrase=dict(default=None, type='str', no_log=True),
update_password=dict(default='always',choices=['always','on_create'],type='str'),
expires=dict(default=None, type='float'),
ssh_key_bits=dict(type='int', default=ssh_defaults['bits']),
ssh_key_type=dict(type='str', default=ssh_defaults['type']),
ssh_key_file=dict(type='path'),
ssh_key_comment=dict(type='str', default=ssh_defaults['comment']),
ssh_key_passphrase=dict(type='str', no_log=True),
update_password=dict(type='str', default='always', choices=['always', 'on_create']),
expires=dict(type='float'),
local=dict(type='bool'),
),
supports_check_mode=True

View file

@ -362,5 +362,4 @@ lib/ansible/modules/system/solaris_zone.py
lib/ansible/modules/system/svc.py
lib/ansible/modules/system/timezone.py
lib/ansible/modules/system/ufw.py
lib/ansible/modules/system/user.py
lib/ansible/playbook/base.py