implemented account expiration as flag and not state, removed from unsupported platforms

reviewable/pr18780/r1
Brian Coca 10 years ago
parent fc1045a1ee
commit 543c45a15f

@ -84,12 +84,9 @@ options:
state: state:
required: false required: false
default: "present" default: "present"
choices: [ present, absent, expired ] choices: [ present, absent ]
description: description:
- Whether the account should exist, and whether it is expired. - Whether the account should exist or not, taking action if the state is different from what is stated.
When C(absent), removes the user account.
When C(expired), the user will not be able to login through any means.
Expired state is only implemented for Linux.
createhome: createhome:
required: false required: false
default: "yes" default: "yes"
@ -97,7 +94,7 @@ options:
description: description:
- Unless set to C(no), a home directory will be made for the user - 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 when the account is created or if the home directory does not
exist. exist.
move_home: move_home:
required: false required: false
default: "no" default: "no"
@ -180,6 +177,13 @@ options:
version_added: "1.3" version_added: "1.3"
description: description:
- C(always) will update passwords if they differ. C(on_create) will only set the password for newly created users. - C(always) will update passwords if they differ. C(on_create) will only set the password for newly created users.
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.
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -194,6 +198,9 @@ EXAMPLES = '''
# Create a 2048-bit SSH key for user jsmith in ~jsmith/.ssh/id_rsa # 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 - user: name=jsmith generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa
# added a consultant who's account you want to expire
- user: name=james18 shell=/bin/zsh groups=developers expires=1422403387
''' '''
import os import os
@ -202,6 +209,7 @@ import grp
import syslog import syslog
import platform import platform
import socket import socket
import time
try: try:
import spwd import spwd
@ -229,6 +237,7 @@ class User(object):
platform = 'Generic' platform = 'Generic'
distribution = None distribution = None
SHADOWFILE = '/etc/shadow' SHADOWFILE = '/etc/shadow'
DATE_FORMAT = '%Y-%M-%d'
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
return load_platform_subclass(User, args, kwargs) return load_platform_subclass(User, args, kwargs)
@ -258,6 +267,14 @@ class User(object):
self.ssh_comment = module.params['ssh_key_comment'] self.ssh_comment = module.params['ssh_key_comment']
self.ssh_passphrase = module.params['ssh_key_passphrase'] self.ssh_passphrase = module.params['ssh_key_passphrase']
self.update_password = module.params['update_password'] self.update_password = module.params['update_password']
self.expires = None
if module.params['expires']:
try:
self.expires = time.gmtime(module.params['expires'])
except Exception,e:
module.fail_json("Invalid expires time %s: %s" %(self.expires, str(e)))
if module.params['ssh_key_file'] is not None: if module.params['ssh_key_file'] is not None:
self.ssh_file = module.params['ssh_key_file'] self.ssh_file = module.params['ssh_key_file']
else: else:
@ -266,6 +283,7 @@ class User(object):
# select whether we dump additional debug info through syslog # select whether we dump additional debug info through syslog
self.syslogging = False self.syslogging = False
def execute_command(self, cmd, use_unsafe_shell=False, data=None): def execute_command(self, cmd, use_unsafe_shell=False, data=None):
if self.syslogging: if self.syslogging:
syslog.openlog('ansible-%s' % os.path.basename(__file__)) syslog.openlog('ansible-%s' % os.path.basename(__file__))
@ -330,9 +348,9 @@ class User(object):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.state == 'expired': if self.expires:
cmd.append('--expiredate') cmd.append('--expiredate')
cmd.append('1') cmd.append(time.strftime(self.DATE_FORMAT, self.expires))
if self.password is not None: if self.password is not None:
cmd.append('-p') cmd.append('-p')
@ -440,9 +458,9 @@ class User(object):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.state == 'expired': if self.expires:
cmd.append('--expiredate') cmd.append('--expiredate')
cmd.append('1') cmd.append(time.strftime(self.DATE_FORMAT, self.expires))
if self.update_password == 'always' and self.password is not None and info[1] != self.password: if self.update_password == 'always' and self.password is not None and info[1] != self.password:
cmd.append('-p') cmd.append('-p')
@ -548,7 +566,7 @@ class User(object):
if not os.path.exists(info[5]): if not os.path.exists(info[5]):
return (1, '', 'User %s home directory does not exist' % self.name) return (1, '', 'User %s home directory does not exist' % self.name)
ssh_key_file = self.get_ssh_key_path() ssh_key_file = self.get_ssh_key_path()
ssh_dir = os.path.dirname(ssh_key_file) ssh_dir = os.path.dirname(ssh_key_file)
if not os.path.exists(ssh_dir): if not os.path.exists(ssh_dir):
try: try:
os.mkdir(ssh_dir, 0700) os.mkdir(ssh_dir, 0700)
@ -637,7 +655,7 @@ class User(object):
os.chown(os.path.join(root, f), uid, gid) os.chown(os.path.join(root, f), uid, gid)
except OSError, e: except OSError, e:
self.module.exit_json(failed=True, msg="%s" % e) self.module.exit_json(failed=True, msg="%s" % e)
# =========================================== # ===========================================
@ -714,9 +732,10 @@ class FreeBsdUser(User):
cmd.append('-L') cmd.append('-L')
cmd.append(self.login_class) cmd.append(self.login_class)
if self.state == 'expired': if self.expires:
days =( time.mktime(self.expires) - time.time() ) / 86400
cmd.append('-e') cmd.append('-e')
cmd.append('1970-01-01') cmd.append(str(int(days)))
# system cannot be handled currently - should we error if its requested? # system cannot be handled currently - should we error if its requested?
# create the user # create the user
@ -730,7 +749,7 @@ class FreeBsdUser(User):
self.module.get_bin_path('chpass', True), self.module.get_bin_path('chpass', True),
'-p', '-p',
self.password, self.password,
self.name self.name
] ]
return self.execute_command(cmd) return self.execute_command(cmd)
@ -741,7 +760,7 @@ class FreeBsdUser(User):
self.module.get_bin_path('pw', True), self.module.get_bin_path('pw', True),
'usermod', 'usermod',
'-n', '-n',
self.name self.name
] ]
cmd_len = len(cmd) cmd_len = len(cmd)
info = self.user_info() info = self.user_info()
@ -802,9 +821,10 @@ class FreeBsdUser(User):
new_groups = groups | set(current_groups) new_groups = groups | set(current_groups)
cmd.append(','.join(new_groups)) cmd.append(','.join(new_groups))
if self.state == 'expired': if self.expires:
days = ( time.mktime(self.expires) - time.time() ) / 86400
cmd.append('-e') cmd.append('-e')
cmd.append('1970-01-01') cmd.append(str(int(days)))
# modify the user if cmd will do anything # modify the user if cmd will do anything
if cmd_len != len(cmd): if cmd_len != len(cmd):
@ -882,10 +902,6 @@ class OpenBSDUser(User):
cmd.append('-L') cmd.append('-L')
cmd.append(self.login_class) cmd.append(self.login_class)
if self.state == 'expired':
cmd.append('-e')
cmd.append('1')
if self.password is not None: if self.password is not None:
cmd.append('-p') cmd.append('-p')
cmd.append(self.password) cmd.append(self.password)
@ -980,10 +996,6 @@ class OpenBSDUser(User):
cmd.append('-L') cmd.append('-L')
cmd.append(self.login_class) cmd.append(self.login_class)
if self.state == 'expired':
cmd.append('-e')
cmd.append('1')
if self.update_password == 'always' and self.password is not None and info[1] != self.password: if self.update_password == 'always' and self.password is not None and info[1] != self.password:
cmd.append('-p') cmd.append('-p')
cmd.append(self.password) cmd.append(self.password)
@ -1057,10 +1069,6 @@ class NetBSDUser(User):
cmd.append('-L') cmd.append('-L')
cmd.append(self.login_class) cmd.append(self.login_class)
if self.state == 'expired':
cmd.append('-e')
cmd.append('1')
if self.password is not None: if self.password is not None:
cmd.append('-p') cmd.append('-p')
cmd.append(self.password) cmd.append(self.password)
@ -1143,10 +1151,6 @@ class NetBSDUser(User):
cmd.append('-L') cmd.append('-L')
cmd.append(self.login_class) cmd.append(self.login_class)
if self.state == 'expired':
cmd.append('-e')
cmd.append('1')
if self.update_password == 'always' and self.password is not None and info[1] != self.password: if self.update_password == 'always' and self.password is not None and info[1] != self.password:
cmd.append('-p') cmd.append('-p')
cmd.append(self.password) cmd.append(self.password)
@ -1224,10 +1228,6 @@ class SunOS(User):
if self.createhome: if self.createhome:
cmd.append('-m') cmd.append('-m')
if self.state == 'expired':
cmd.append('-e')
cmd.append('1/1/70')
cmd.append(self.name) cmd.append(self.name)
if self.module.check_mode: if self.module.check_mode:
@ -1312,10 +1312,6 @@ class SunOS(User):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.state == 'expired':
cmd.append('-e')
cmd.append('1/1/70')
if self.module.check_mode: if self.module.check_mode:
return (0, '', '') return (0, '', '')
else: else:
@ -1405,10 +1401,6 @@ class AIX(User):
if self.createhome: if self.createhome:
cmd.append('-m') cmd.append('-m')
if self.state == 'expired':
cmd.append('-e')
cmd.append('0101000070')
cmd.append(self.name) cmd.append(self.name)
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
@ -1477,10 +1469,6 @@ class AIX(User):
cmd.append('-s') cmd.append('-s')
cmd.append(self.shell) cmd.append(self.shell)
if self.state == 'expired':
cmd.append('-e')
cmd.append('0101000070')
# skip if no changes to be made # skip if no changes to be made
if len(cmd) == 1: if len(cmd) == 1:
(rc, out, err) = (None, '', '') (rc, out, err) = (None, '', '')
@ -1516,7 +1504,7 @@ def main():
} }
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
state=dict(default='present', choices=['present', 'absent', 'expired'], type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'),
name=dict(required=True, aliases=['user'], type='str'), name=dict(required=True, aliases=['user'], type='str'),
uid=dict(default=None, type='str'), uid=dict(default=None, type='str'),
non_unique=dict(default='no', type='bool'), non_unique=dict(default='no', type='bool'),
@ -1543,7 +1531,8 @@ def main():
ssh_key_file=dict(default=None, type='str'), ssh_key_file=dict(default=None, type='str'),
ssh_key_comment=dict(default=ssh_defaults['comment'], type='str'), ssh_key_comment=dict(default=ssh_defaults['comment'], type='str'),
ssh_key_passphrase=dict(default=None, type='str'), ssh_key_passphrase=dict(default=None, type='str'),
update_password=dict(default='always',choices=['always','on_create'],type='str') update_password=dict(default='always',choices=['always','on_create'],type='str'),
expires=dict(default=None, type='float'),
), ),
supports_check_mode=True supports_check_mode=True
) )
@ -1571,10 +1560,7 @@ def main():
module.fail_json(name=user.name, msg=err, rc=rc) module.fail_json(name=user.name, msg=err, rc=rc)
result['force'] = user.force result['force'] = user.force
result['remove'] = user.remove result['remove'] = user.remove
elif user.state == 'expired' and user.platform != 'Generic': elif user.state == 'present':
module.fail_json(name=user.state,
msg='expired state not yet support for {0} platform'.format(user.platform))
elif user.state == 'present' or user.state == 'expired':
if not user.user_exists(): if not user.user_exists():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True) module.exit_json(changed=True)

Loading…
Cancel
Save