mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
commit
c940dbcb03
4 changed files with 410 additions and 101 deletions
|
@ -2893,7 +2893,7 @@ def remove(path):
|
|||
path = os.path.expanduser(path)
|
||||
|
||||
if not os.path.isabs(path):
|
||||
raise SaltInvocationError('File path must be absolute.')
|
||||
raise SaltInvocationError('File path must be absolute: {0}'.format(path))
|
||||
|
||||
try:
|
||||
if os.path.isfile(path) or os.path.islink(path):
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage Windows users with the net user command
|
||||
Module for managing Windows Users
|
||||
|
||||
:depends:
|
||||
- os
|
||||
- pywintypes
|
||||
- win32api
|
||||
- win32net
|
||||
- win32netcon
|
||||
- win32profile
|
||||
- win32security
|
||||
- win32ts
|
||||
|
||||
NOTE: This currently only works with local user accounts, not domain accounts
|
||||
'''
|
||||
|
@ -15,9 +25,14 @@ import logging
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import os
|
||||
import pywintypes
|
||||
import win32api
|
||||
import win32net
|
||||
import win32netcon
|
||||
import win32profile
|
||||
import win32security
|
||||
import win32ts
|
||||
HAS_WIN32NET_MODS = True
|
||||
except ImportError:
|
||||
HAS_WIN32NET_MODS = False
|
||||
|
@ -30,33 +45,54 @@ def __virtual__():
|
|||
'''
|
||||
Set the user module if the kernel is Windows
|
||||
'''
|
||||
if HAS_WIN32NET_MODS is True and salt.utils.is_windows():
|
||||
if HAS_WIN32NET_MODS and salt.utils.is_windows():
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def add(name,
|
||||
password=None,
|
||||
# Disable pylint checking on the next options. They exist to match the
|
||||
# user modules of other distributions.
|
||||
# pylint: disable=W0613
|
||||
uid=None,
|
||||
gid=None,
|
||||
groups=None,
|
||||
home=False,
|
||||
shell=None,
|
||||
unique=False,
|
||||
system=False,
|
||||
fullname=False,
|
||||
roomnumber=False,
|
||||
workphone=False,
|
||||
homephone=False,
|
||||
loginclass=False,
|
||||
createhome=False
|
||||
# pylint: enable=W0613
|
||||
):
|
||||
description=None,
|
||||
groups=None,
|
||||
home=None,
|
||||
homedrive=None,
|
||||
profile=None,
|
||||
logonscript=None):
|
||||
'''
|
||||
Add a user to the minion
|
||||
Add a user to the minion.
|
||||
|
||||
:param name: str
|
||||
User name
|
||||
|
||||
:param password: str
|
||||
User's password in plain text.
|
||||
|
||||
:param fullname: str
|
||||
The user's full name.
|
||||
|
||||
:param description: str
|
||||
A brief description of the user account.
|
||||
|
||||
:param groups: list
|
||||
A list of groups to add the user to.
|
||||
|
||||
:param home: str
|
||||
The path to the user's home directory.
|
||||
|
||||
:param homedrive: str
|
||||
The drive letter to assign to the home directory. Must be the Drive Letter
|
||||
followed by a colon. ie: U:
|
||||
|
||||
:param profile: str
|
||||
An explicit path to a profile. Can be a UNC or a folder on the system. If
|
||||
left blank, windows uses it's default profile directory.
|
||||
|
||||
:param logonscript: str
|
||||
Path to a login script to run when the user logs on.
|
||||
|
||||
:return: bool
|
||||
True if successful. False is unsuccessful.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -64,28 +100,148 @@ def add(name,
|
|||
|
||||
salt '*' user.add name password
|
||||
'''
|
||||
if password:
|
||||
ret = __salt__['cmd.run_all']('net user {0} {1} /add /y'.format(name, password))
|
||||
user_info = {}
|
||||
if name:
|
||||
user_info['name'] = name
|
||||
else:
|
||||
ret = __salt__['cmd.run_all']('net user {0} /add'.format(name))
|
||||
return False
|
||||
user_info['password'] = password
|
||||
user_info['priv'] = win32netcon.USER_PRIV_USER
|
||||
user_info['home_dir'] = home
|
||||
user_info['comment'] = description
|
||||
user_info['flags'] = win32netcon.UF_SCRIPT
|
||||
user_info['script_path'] = logonscript
|
||||
|
||||
try:
|
||||
win32net.NetUserAdd(None, 1, user_info)
|
||||
except win32net.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('Failed to create user {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
update(name=name,
|
||||
homedrive=homedrive,
|
||||
profile=profile,
|
||||
fullname=fullname)
|
||||
|
||||
if groups:
|
||||
chgroups(name, groups)
|
||||
ret = chgroups(name, groups)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def update(name,
|
||||
password=None,
|
||||
fullname=None,
|
||||
description=None,
|
||||
home=None,
|
||||
homedrive=None,
|
||||
logonscript=None,
|
||||
profile=None):
|
||||
r'''
|
||||
Updates settings for the windows user. Name is the only required parameter.
|
||||
Settings will only be changed if the parameter is passed a value.
|
||||
|
||||
.. versionadded:: 2015.8.0
|
||||
|
||||
:param name: str
|
||||
The user name to update.
|
||||
|
||||
:param password: str
|
||||
New user password in plain text.
|
||||
|
||||
:param fullname: str
|
||||
The user's full name.
|
||||
|
||||
:param description: str
|
||||
A brief description of the user account.
|
||||
|
||||
:param home: str
|
||||
The path to the user's home directory.
|
||||
|
||||
:param homedrive: str
|
||||
The drive letter to assign to the home directory. Must be the Drive Letter
|
||||
followed by a colon. ie: U:
|
||||
|
||||
:param logonscript: str
|
||||
The path to the logon script.
|
||||
|
||||
:param profile: str
|
||||
The path to the user's profile directory.
|
||||
|
||||
:return: bool
|
||||
True if successful. False is unsuccessful.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.update bob password=secret profile=C:\Users\Bob
|
||||
home=\\server\homeshare\bob homedrive=U:
|
||||
'''
|
||||
|
||||
# Make sure the user exists
|
||||
# Return an object containing current settings for the user
|
||||
try:
|
||||
user_info = win32net.NetUserGetInfo(None, name, 4)
|
||||
except win32net.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('Failed to update user {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
# Check parameters to update
|
||||
# Update the user object with new settings
|
||||
if password:
|
||||
user_info['password'] = password
|
||||
if home:
|
||||
user_info['home_dir'] = home
|
||||
if homedrive:
|
||||
user_info['home_dir_drive'] = homedrive
|
||||
if description:
|
||||
user_info['comment'] = description
|
||||
if logonscript:
|
||||
user_info['script_path'] = logonscript
|
||||
if fullname:
|
||||
chfullname(name, fullname)
|
||||
return ret['retcode'] == 0
|
||||
user_info['full_name'] = fullname
|
||||
if profile:
|
||||
user_info['profile'] = profile
|
||||
|
||||
# Apply new settings
|
||||
try:
|
||||
win32net.NetUserSetInfo(None, name, 4, user_info)
|
||||
except win32net.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('Failed to update user {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def delete(name,
|
||||
# Disable pylint checking on the next options. They exist to match
|
||||
# the user modules of other distributions.
|
||||
# pylint: disable=W0613
|
||||
purge=False,
|
||||
force=False
|
||||
# pylint: enable=W0613
|
||||
):
|
||||
force=False):
|
||||
'''
|
||||
Remove a user from the minion
|
||||
NOTE: purge and force have not been implemented on Windows yet
|
||||
|
||||
:param name:
|
||||
The name of the user to delete
|
||||
|
||||
:param purge:
|
||||
Boolean value indicating that the user profile should also be removed when
|
||||
the user account is deleted. If set to True the profile will be removed.
|
||||
|
||||
:param force:
|
||||
Boolean value indicating that the user account should be deleted even if the
|
||||
user is logged in. True will log the user out and delete user.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -93,8 +249,98 @@ def delete(name,
|
|||
|
||||
salt '*' user.delete name
|
||||
'''
|
||||
ret = __salt__['cmd.run_all']('net user {0} /delete'.format(name))
|
||||
return ret['retcode'] == 0
|
||||
# Check if the user exists
|
||||
try:
|
||||
user_info = win32net.NetUserGetInfo(None, name, 4)
|
||||
except win32net.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('User not found: {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
# Check if the user is logged in
|
||||
# Return a list of logged in users
|
||||
try:
|
||||
sess_list = win32ts.WTSEnumerateSessions()
|
||||
except win32ts.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('No logged in users found')
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
|
||||
# Is the user one that is logged in
|
||||
logged_in = False
|
||||
session_id = None
|
||||
for sess in sess_list:
|
||||
if win32ts.WTSQuerySessionInformation(None, sess['SessionId'], win32ts.WTSUserName) == name:
|
||||
session_id = sess['SessionId']
|
||||
logged_in = True
|
||||
|
||||
# If logged in and set to force, log the user out and continue
|
||||
# If logged in and not set to force, return false
|
||||
if logged_in:
|
||||
if force:
|
||||
try:
|
||||
win32ts.WTSLogoffSession(win32ts.WTS_CURRENT_SERVER_HANDLE, session_id, True)
|
||||
except win32ts.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('User not found: {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
else:
|
||||
log.error('User {0} is currently logged in.'.format(name))
|
||||
return False
|
||||
|
||||
# Remove the User Profile directory
|
||||
if purge:
|
||||
# If the profile is not defined, get the profile from the registry
|
||||
if user_info['profile'] == '':
|
||||
profiles_dir = __salt__['reg.read_key'](hkey='HKEY_LOCAL_MACHINE',
|
||||
path='SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList',
|
||||
key='ProfilesDirectory')
|
||||
profiles_dir = profiles_dir.replace('%SystemDrive%', os.environ['SystemDrive'])
|
||||
user_info['profile'] = r'{0}\{1}'.format(profiles_dir, name)
|
||||
|
||||
# Make sure the profile exists before deleting it
|
||||
# Otherwise this will throw an error
|
||||
if os.path.exists(user_info['profile']):
|
||||
sid = getUserSid(name)
|
||||
try:
|
||||
win32profile.DeleteProfile(sid)
|
||||
except pywintypes.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('Failed to remove profile for {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
# And finally remove the user account
|
||||
try:
|
||||
win32net.NetUserDel(None, name)
|
||||
except win32net.error as exc:
|
||||
(number, context, message) = exc
|
||||
log.error('Failed to delete user {0}'.format(name))
|
||||
log.error('nbr: {0}'.format(number))
|
||||
log.error('ctx: {0}'.format(context))
|
||||
log.error('msg: {0}'.format(message))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def getUserSid(username):
|
||||
domain = win32api.GetComputerName()
|
||||
if username.find(u'\\') != -1:
|
||||
domain = username.split(u'\\')[0]
|
||||
username = username.split(u'\\')[-1]
|
||||
domain = domain.upper()
|
||||
return win32security.ConvertSidToStringSid(win32security.LookupAccountName(None, domain + u'\\' + username)[0])
|
||||
|
||||
|
||||
def setpassword(name, password):
|
||||
|
@ -107,10 +353,7 @@ def setpassword(name, password):
|
|||
|
||||
salt '*' user.setpassword name password
|
||||
'''
|
||||
ret = __salt__['cmd.run_all'](
|
||||
'net user {0} {1}'.format(name, password), output_loglevel='quiet'
|
||||
)
|
||||
return ret['retcode'] == 0
|
||||
return update(name=name, password=password)
|
||||
|
||||
|
||||
def addgroup(name, group):
|
||||
|
@ -177,8 +420,7 @@ def chhome(name, home, persist=False):
|
|||
if home == pre_info['home']:
|
||||
return True
|
||||
|
||||
if __salt__['cmd.retcode']('net user {0} /homedir:{1}'.format(
|
||||
name, home)) != 0:
|
||||
if not update(name=name, home=home):
|
||||
return False
|
||||
|
||||
if persist and home is not None and pre_info['home'] is not None:
|
||||
|
@ -203,22 +445,7 @@ def chprofile(name, profile):
|
|||
|
||||
salt '*' user.chprofile foo \\\\fileserver\\profiles\\foo
|
||||
'''
|
||||
pre_info = info(name)
|
||||
|
||||
if not pre_info:
|
||||
return False
|
||||
|
||||
if profile == pre_info['profile']:
|
||||
return True
|
||||
if __salt__['cmd.retcode']('net user {0} /profilepath:{1}'.format(
|
||||
name, profile)) != 0:
|
||||
return False
|
||||
|
||||
post_info = info(name)
|
||||
if post_info['profile'] != pre_info['profile']:
|
||||
return post_info['profile'] == profile
|
||||
|
||||
return False
|
||||
return update(name=name, profile=profile)
|
||||
|
||||
|
||||
def chfullname(name, fullname):
|
||||
|
@ -231,22 +458,7 @@ def chfullname(name, fullname):
|
|||
|
||||
salt '*' user.chfullname user 'First Last'
|
||||
'''
|
||||
pre_info = info(name)
|
||||
|
||||
if not pre_info:
|
||||
return False
|
||||
|
||||
if fullname == pre_info['fullname']:
|
||||
return True
|
||||
if __salt__['cmd.retcode']('net user {0} /fullname:"{1}"'.format(
|
||||
name, fullname)) != 0:
|
||||
return False
|
||||
|
||||
post_info = info(name)
|
||||
if post_info['fullname'] != pre_info['fullname']:
|
||||
return post_info['fullname'] == fullname
|
||||
|
||||
return False
|
||||
return update(name=name, fullname=fullname)
|
||||
|
||||
|
||||
def chgroups(name, groups, append=False):
|
||||
|
@ -287,6 +499,25 @@ def info(name):
|
|||
'''
|
||||
Return user information
|
||||
|
||||
:param name: str
|
||||
Username for which to display information
|
||||
|
||||
:returns: dict
|
||||
A dictionary containing user information
|
||||
- fullname
|
||||
- username
|
||||
- uid
|
||||
- passwd (will always return None)
|
||||
- comment (same as description, left here for backwards compatibility)
|
||||
- description
|
||||
- active
|
||||
- logonscript
|
||||
- profile
|
||||
- home
|
||||
- homedrive
|
||||
- groups
|
||||
- gid
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -312,12 +543,14 @@ def info(name):
|
|||
ret['uid'] = win32security.ConvertSidToStringSid(items['user_sid'])
|
||||
ret['passwd'] = items['password']
|
||||
ret['comment'] = items['comment']
|
||||
ret['description'] = items['comment']
|
||||
ret['active'] = (not bool(items['flags'] & win32netcon.UF_ACCOUNTDISABLE))
|
||||
ret['logonscript'] = items['script_path']
|
||||
ret['profile'] = items['profile']
|
||||
if not ret['profile']:
|
||||
ret['profile'] = _get_userprofile_from_registry(name, ret['uid'])
|
||||
ret['home'] = items['home_dir']
|
||||
ret['homedrive'] = items['home_dir_drive']
|
||||
if not ret['home']:
|
||||
ret['home'] = ret['profile']
|
||||
ret['groups'] = groups
|
||||
|
|
|
@ -72,11 +72,18 @@ def _changes(name,
|
|||
maxdays=999999,
|
||||
inactdays=0,
|
||||
warndays=7,
|
||||
expire=-1):
|
||||
expire=-1,
|
||||
win_homedrive=None,
|
||||
win_profile=None,
|
||||
win_logonscript=None,
|
||||
win_description=None):
|
||||
'''
|
||||
Return a dict of the changes required for a user if the user is present,
|
||||
otherwise return False.
|
||||
|
||||
Updated in 2015.8.0 to include support for windows homedrive, profile,
|
||||
logonscript, and description fields.
|
||||
|
||||
Updated in 2014.7.0 to include support for shadow attributes, all
|
||||
attributes supported as integers only.
|
||||
'''
|
||||
|
@ -117,7 +124,6 @@ def _changes(name,
|
|||
newhome = home if home else lusr['home']
|
||||
if newhome is not None and not os.path.isdir(newhome):
|
||||
change['homeDoesNotExist'] = newhome
|
||||
|
||||
if shell:
|
||||
if lusr['shell'] != shell:
|
||||
change['shell'] = shell
|
||||
|
@ -143,6 +149,19 @@ def _changes(name,
|
|||
# GECOS fields
|
||||
if fullname is not None and lusr['fullname'] != fullname:
|
||||
change['fullname'] = fullname
|
||||
if win_homedrive:
|
||||
if lusr['homedrive'] != win_homedrive:
|
||||
change['homedrive'] = win_homedrive
|
||||
if win_profile:
|
||||
if lusr['profile'] != win_profile:
|
||||
change['profile'] = win_profile
|
||||
if win_logonscript:
|
||||
if lusr['logonscript'] != win_logonscript:
|
||||
change['logonscript'] = win_logonscript
|
||||
if win_description:
|
||||
if lusr['description'] != win_description:
|
||||
change['description'] = win_description
|
||||
|
||||
# MacOS doesn't have full GECOS support, so check for the "ch" functions
|
||||
# and ignore these parameters if these functions do not exist.
|
||||
if 'user.chroomnumber' in __salt__:
|
||||
|
@ -189,7 +208,11 @@ def present(name,
|
|||
maxdays=None,
|
||||
inactdays=None,
|
||||
warndays=None,
|
||||
expire=None):
|
||||
expire=None,
|
||||
win_homedrive=None,
|
||||
win_profile=None,
|
||||
win_logonscript=None,
|
||||
win_description=None):
|
||||
'''
|
||||
Ensure that the named user is present with the specified properties
|
||||
|
||||
|
@ -239,6 +262,7 @@ def present(name,
|
|||
password
|
||||
A password hash to set for the user. This field is only supported on
|
||||
Linux, FreeBSD, NetBSD, OpenBSD, and Solaris.
|
||||
For Windows this is the plain text password.
|
||||
|
||||
.. versionchanged:: 0.16.0
|
||||
BSD support added.
|
||||
|
@ -285,7 +309,6 @@ def present(name,
|
|||
homephone
|
||||
The user's home phone number (not supported in MacOS)
|
||||
|
||||
|
||||
.. versionchanged:: 2014.7.0
|
||||
Shadow attribute support added.
|
||||
|
||||
|
@ -313,8 +336,30 @@ def present(name,
|
|||
expire
|
||||
Date that account expires, represented in days since epoch (January 1,
|
||||
1970).
|
||||
'''
|
||||
|
||||
The below parameters apply to windows only:
|
||||
|
||||
win_homedrive (Windows Only)
|
||||
The drive letter to use for the home directory. If not specified the
|
||||
home directory will be a unc path. Otherwise the home directory will be
|
||||
mapped to the specified drive. Must be a letter followed by a colon.
|
||||
Because of the colon, the value must be surrounded by single quotes. ie:
|
||||
- win_homedrive: 'U:
|
||||
.. versionchanged:: 2015.8.0
|
||||
|
||||
win_profile (Windows Only)
|
||||
The custom profile directory of the user. Uses default value of
|
||||
underlying system if not set.
|
||||
.. versionchanged:: 2015.8.0
|
||||
|
||||
win_logonscript (Windows Only)
|
||||
The full path to the logon script to run when the user logs in.
|
||||
.. versionchanged:: 2015.8.0
|
||||
|
||||
win_description (Windows Only)
|
||||
A brief description of the purpose of the users account.
|
||||
.. versionchanged:: 2015.8.0
|
||||
'''
|
||||
fullname = salt.utils.locales.sdecode(fullname)
|
||||
roomnumber = salt.utils.locales.sdecode(roomnumber)
|
||||
workphone = salt.utils.locales.sdecode(workphone)
|
||||
|
@ -378,7 +423,11 @@ def present(name,
|
|||
maxdays,
|
||||
inactdays,
|
||||
warndays,
|
||||
expire)
|
||||
expire,
|
||||
win_homedrive,
|
||||
win_profile,
|
||||
win_logonscript,
|
||||
win_description)
|
||||
|
||||
if changes:
|
||||
if __opts__['test']:
|
||||
|
@ -425,6 +474,18 @@ def present(name,
|
|||
if key == 'expire':
|
||||
__salt__['shadow.set_expire'](name, expire)
|
||||
continue
|
||||
if key == 'win_homedrive':
|
||||
__salt__['user.update'](name=name, homedrive=val)
|
||||
continue
|
||||
if key == 'win_profile':
|
||||
__salt__['user.update'](name=name, profile=val)
|
||||
continue
|
||||
if key == 'win_logonscript':
|
||||
__salt__['user.update'](name=name, logonscript=val)
|
||||
continue
|
||||
if key == 'win_description':
|
||||
__salt__['user.update'](name=name, description=val)
|
||||
continue
|
||||
if key == 'groups':
|
||||
__salt__['user.ch{0}'.format(key)](
|
||||
name, val, not remove_groups
|
||||
|
@ -474,7 +535,11 @@ def present(name,
|
|||
maxdays,
|
||||
inactdays,
|
||||
warndays,
|
||||
expire)
|
||||
expire,
|
||||
win_homedrive,
|
||||
win_profile,
|
||||
win_logonscript,
|
||||
win_description)
|
||||
|
||||
if changes:
|
||||
ret['comment'] = 'These values could not be changed: {0}'.format(
|
||||
|
@ -493,20 +558,36 @@ def present(name,
|
|||
groups.extend(present_optgroups)
|
||||
elif present_optgroups:
|
||||
groups = present_optgroups[:]
|
||||
if __salt__['user.add'](name,
|
||||
uid=uid,
|
||||
gid=gid,
|
||||
groups=groups,
|
||||
home=home,
|
||||
shell=shell,
|
||||
unique=unique,
|
||||
system=system,
|
||||
fullname=fullname,
|
||||
roomnumber=roomnumber,
|
||||
workphone=workphone,
|
||||
homephone=homephone,
|
||||
loginclass=loginclass,
|
||||
createhome=createhome):
|
||||
|
||||
# Setup params specific to Linux and Windows to be passed to the
|
||||
# add.user function
|
||||
if not salt.utils.is_windows():
|
||||
params = {'name': name,
|
||||
'uid': uid,
|
||||
'gid': gid,
|
||||
'groups': groups,
|
||||
'home': home,
|
||||
'shell': shell,
|
||||
'unique': unique,
|
||||
'system': system,
|
||||
'fullname': fullname,
|
||||
'roomnumber': roomnumber,
|
||||
'workphone': workphone,
|
||||
'homephone': homephone,
|
||||
'createhome': createhome,
|
||||
'loginclass': loginclass}
|
||||
else:
|
||||
params = ({'name': name,
|
||||
'password': password,
|
||||
'fullname': fullname,
|
||||
'description': win_description,
|
||||
'groups': groups,
|
||||
'home': home,
|
||||
'homedrive': win_homedrive,
|
||||
'profile': win_profile,
|
||||
'logonscript': win_logonscript})
|
||||
|
||||
if __salt__['user.add'](**params):
|
||||
ret['comment'] = 'New user {0} created'.format(name)
|
||||
ret['changes'] = __salt__['user.info'](name)
|
||||
if 'shadow.info' in __salt__ and not salt.utils.is_windows():
|
||||
|
@ -575,11 +656,6 @@ def present(name,
|
|||
ret['changes']['expire'] = expire
|
||||
elif salt.utils.is_windows():
|
||||
if password and not empty_password:
|
||||
if not __salt__['user.setpassword'](name, password):
|
||||
ret['comment'] = 'User {0} created but failed to set' \
|
||||
' password to' \
|
||||
' {1}'.format(name, password)
|
||||
ret['result'] = False
|
||||
ret['changes']['passwd'] = password
|
||||
else:
|
||||
ret['comment'] = 'Failed to create new user {0}'.format(name)
|
||||
|
|
|
@ -160,7 +160,7 @@ class FileModuleTest(integration.ModuleCase):
|
|||
def test_cannot_remove(self):
|
||||
ret = self.run_function('file.remove', arg=['tty'])
|
||||
self.assertEqual(
|
||||
'ERROR executing \'file.remove\': File path must be absolute.', ret
|
||||
'ERROR executing \'file.remove\': File path must be absolute: tty', ret
|
||||
)
|
||||
|
||||
def test_source_list_for_single_file_returns_unchanged(self):
|
||||
|
|
Loading…
Add table
Reference in a new issue