mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Fix group state for Windows
group no longer fails when domain is not specified group.present now accepts group names without domains local groups are assumed if domain is not specified documentation improved moved fix_local_user function to salt.utils.win_functions now called get_sam_name
This commit is contained in:
parent
f9b4976c02
commit
4f4e34c79f
3 changed files with 190 additions and 53 deletions
|
@ -12,6 +12,7 @@ from __future__ import absolute_import
|
|||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.win_functions
|
||||
|
||||
|
||||
try:
|
||||
|
@ -35,10 +36,18 @@ def __virtual__():
|
|||
return (False, "Module win_groupadd: module only works on Windows systems")
|
||||
|
||||
|
||||
def add(name, gid=None, system=False):
|
||||
def add(name, **kwargs):
|
||||
'''
|
||||
Add the specified group
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group to add
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of results
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -57,21 +66,16 @@ def add(name, gid=None, system=False):
|
|||
compObj = nt.GetObject('', 'WinNT://.,computer')
|
||||
newGroup = compObj.Create('group', name)
|
||||
newGroup.SetInfo()
|
||||
ret['changes'].append((
|
||||
'Successfully created group {0}'
|
||||
).format(name))
|
||||
ret['changes'].append('Successfully created group {0}'.format(name))
|
||||
except pywintypes.com_error as com_err:
|
||||
ret['result'] = False
|
||||
if len(com_err.excepinfo) >= 2:
|
||||
friendly_error = com_err.excepinfo[2].rstrip('\r\n')
|
||||
ret['comment'] = (
|
||||
'Failed to create group {0}. {1}'
|
||||
).format(name, friendly_error)
|
||||
ret['comment'] = 'Failed to create group {0}. {1}' \
|
||||
''.format(name, friendly_error)
|
||||
else:
|
||||
ret['result'] = None
|
||||
ret['comment'] = (
|
||||
'The group {0} already exists.'
|
||||
).format(name)
|
||||
ret['comment'] = 'The group {0} already exists.'.format(name)
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -80,6 +84,14 @@ def delete(name):
|
|||
'''
|
||||
Remove the named group
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group to remove
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of results
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -118,6 +130,14 @@ def info(name):
|
|||
'''
|
||||
Return information about a group
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group for which to get information
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of information about the group
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -151,6 +171,17 @@ def getent(refresh=False):
|
|||
'''
|
||||
Return info on all groups
|
||||
|
||||
Args:
|
||||
|
||||
refresh (bool):
|
||||
Refresh the info for all groups in ``__context__``. If False only
|
||||
the groups in ``__context__`` wil be returned. If True the
|
||||
``__context__`` will be refreshed with current data and returned.
|
||||
Default is False
|
||||
|
||||
Returns:
|
||||
A list of groups and their information
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -184,14 +215,24 @@ def getent(refresh=False):
|
|||
|
||||
def adduser(name, username):
|
||||
'''
|
||||
add a user to a group
|
||||
Add a user to a group
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group to modify
|
||||
|
||||
username (str):
|
||||
The name of the user to add to the group
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of results
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' group.adduser foo username
|
||||
|
||||
'''
|
||||
|
||||
ret = {'name': name,
|
||||
|
@ -209,7 +250,7 @@ def adduser(name, username):
|
|||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
|
||||
try:
|
||||
if __fixlocaluser(username.lower()) not in existingMembers:
|
||||
if salt.utils.win_functions.get_sam_name(username) not in existingMembers:
|
||||
if not __opts__['test']:
|
||||
groupObj.Add('WinNT://' + username.replace('\\', '/'))
|
||||
|
||||
|
@ -233,14 +274,24 @@ def adduser(name, username):
|
|||
|
||||
def deluser(name, username):
|
||||
'''
|
||||
remove a user from a group
|
||||
Remove a user from a group
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group to modify
|
||||
|
||||
username (str):
|
||||
The name of the user to remove from the group
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of results
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' group.deluser foo username
|
||||
|
||||
'''
|
||||
|
||||
ret = {'name': name,
|
||||
|
@ -258,7 +309,7 @@ def deluser(name, username):
|
|||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
|
||||
try:
|
||||
if __fixlocaluser(username.lower()) in existingMembers:
|
||||
if salt.utils.win_functions.get_sam_name(username) in existingMembers:
|
||||
if not __opts__['test']:
|
||||
groupObj.Remove('WinNT://' + username.replace('\\', '/'))
|
||||
|
||||
|
@ -282,14 +333,25 @@ def deluser(name, username):
|
|||
|
||||
def members(name, members_list):
|
||||
'''
|
||||
remove a user from a group
|
||||
Ensure a group contains only the members in the list
|
||||
|
||||
Args:
|
||||
|
||||
name (str):
|
||||
The name of the group to modify
|
||||
|
||||
members_list (str):
|
||||
A single user or a comma separated list of users. The group will
|
||||
contain only the users specified in this list.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of results
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' group.members foo 'user1,user2,user3'
|
||||
|
||||
'''
|
||||
|
||||
ret = {'name': name,
|
||||
|
@ -297,7 +359,7 @@ def members(name, members_list):
|
|||
'changes': {'Users Added': [], 'Users Removed': []},
|
||||
'comment': []}
|
||||
|
||||
members_list = [__fixlocaluser(thisMember) for thisMember in members_list.lower().split(",")]
|
||||
members_list = [salt.utils.win_functions.get_sam_name(m) for m in members_list.split(",")]
|
||||
if not isinstance(members_list, list):
|
||||
ret['result'] = False
|
||||
ret['comment'].append('Members is not a list object')
|
||||
|
@ -364,27 +426,26 @@ def members(name, members_list):
|
|||
return ret
|
||||
|
||||
|
||||
def __fixlocaluser(username):
|
||||
'''
|
||||
prefixes a username w/o a backslash with the computername
|
||||
|
||||
i.e. __fixlocaluser('Administrator') would return 'computername\administrator'
|
||||
'''
|
||||
if '\\' not in username:
|
||||
username = ('{0}\\{1}').format(__salt__['grains.get']('host'), username)
|
||||
|
||||
return username.lower()
|
||||
|
||||
|
||||
def list_groups(refresh=False):
|
||||
'''
|
||||
Return a list of groups
|
||||
|
||||
Args:
|
||||
|
||||
refresh (bool):
|
||||
Refresh the info for all groups in ``__context__``. If False only
|
||||
the groups in ``__context__`` wil be returned. If True, the
|
||||
``__context__`` will be refreshed with current data and returned.
|
||||
Default is False
|
||||
|
||||
Returns:
|
||||
list: A list of groups on the machine
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' group.getent
|
||||
salt '*' group.list_groups
|
||||
'''
|
||||
if 'group.list_groups' in __context__ and not refresh:
|
||||
return __context__['group.getent']
|
||||
|
|
|
@ -3,8 +3,13 @@
|
|||
Management of user groups
|
||||
=========================
|
||||
|
||||
The group module is used to create and manage unix group settings, groups
|
||||
can be either present or absent:
|
||||
The group module is used to create and manage group settings, groups can be
|
||||
either present or absent. User/Group names can be passed to the ``adduser``,
|
||||
``deluser``, and ``members`` parameters. ``adduser`` and ``deluser`` can be used
|
||||
together but not with ``members``.
|
||||
|
||||
In Windows, if no domain is specified in the user or group name (ie:
|
||||
`DOMAIN\username``) the module will assume a local user or group.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
|
@ -36,6 +41,10 @@ import sys
|
|||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
import salt.utils.win_functions
|
||||
|
||||
|
||||
def _changes(name,
|
||||
gid=None,
|
||||
|
@ -50,6 +59,18 @@ def _changes(name,
|
|||
if not lgrp:
|
||||
return False
|
||||
|
||||
# User and Domain names are not case sensitive in Windows. Let's make them
|
||||
# all lower case so we can compare properly
|
||||
if salt.utils.is_windows():
|
||||
if lgrp['members']:
|
||||
lgrp['members'] = [user.lower() for user in lgrp['members']]
|
||||
if members:
|
||||
members = [salt.utils.win_functions.get_sam_name(user) for user in members]
|
||||
if addusers:
|
||||
addusers = [salt.utils.win_functions.get_sam_name(user) for user in addusers]
|
||||
if delusers:
|
||||
delusers = [salt.utils.win_functions.get_sam_name(user) for user in delusers]
|
||||
|
||||
change = {}
|
||||
if gid:
|
||||
if lgrp['gid'] != gid:
|
||||
|
@ -57,7 +78,7 @@ def _changes(name,
|
|||
|
||||
if members:
|
||||
# -- if new member list if different than the current
|
||||
if set(lgrp['members']) ^ set(members):
|
||||
if set(lgrp['members']).symmetric_difference(members):
|
||||
change['members'] = members
|
||||
|
||||
if addusers:
|
||||
|
@ -82,28 +103,55 @@ def present(name,
|
|||
'''
|
||||
Ensure that a group is present
|
||||
|
||||
name
|
||||
The name of the group to manage
|
||||
Args:
|
||||
|
||||
gid
|
||||
The group id to assign to the named group; if left empty, then the next
|
||||
available group id will be assigned
|
||||
name (str):
|
||||
The name of the group to manage
|
||||
|
||||
system
|
||||
Whether or not the named group is a system group. This is essentially
|
||||
the '-r' option of 'groupadd'.
|
||||
gid (str):
|
||||
The group id to assign to the named group; if left empty, then the
|
||||
next available group id will be assigned. Ignored on Windows
|
||||
|
||||
addusers
|
||||
List of additional users to be added as a group members.
|
||||
system (bool):
|
||||
Whether or not the named group is a system group. This is essentially
|
||||
the '-r' option of 'groupadd'. Ignored on Windows
|
||||
|
||||
delusers
|
||||
Ensure these user are removed from the group membership.
|
||||
addusers (list):
|
||||
List of additional users to be added as a group members. Cannot
|
||||
conflict with names in delusers. Cannot be used in conjunction with
|
||||
members.
|
||||
|
||||
members
|
||||
Replace existing group members with a list of new members.
|
||||
delusers (list):
|
||||
Ensure these user are removed from the group membership. Cannot
|
||||
conflict with names in addusers. Cannot be used in conjunction with
|
||||
members.
|
||||
|
||||
Note: Options 'members' and 'addusers/delusers' are mutually exclusive and
|
||||
can not be used together.
|
||||
members (list):
|
||||
Replace existing group members with a list of new members. Cannot be
|
||||
used in conjunction with addusers or delusers.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Adds DOMAIN\db_admins and Administrators to the local db_admin group
|
||||
# Removes Users
|
||||
db_admin:
|
||||
group.present:
|
||||
- addusers:
|
||||
- DOMAIN\db_admins
|
||||
- Administrators
|
||||
- delusers:
|
||||
- Users
|
||||
|
||||
# Ensures only DOMAIN\domain_admins and the local Administrator are
|
||||
# members of the local Administrators group. All other users are
|
||||
# removed
|
||||
Administrators:
|
||||
group.present:
|
||||
- members:
|
||||
- DOMAIN\domain_admins
|
||||
- Administrator
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
|
@ -233,8 +281,17 @@ def absent(name):
|
|||
'''
|
||||
Ensure that the named group is absent
|
||||
|
||||
name
|
||||
The name of the group to remove
|
||||
Args:
|
||||
name (str):
|
||||
The name of the group to remove
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Removes the local group `db_admin`
|
||||
db_admin:
|
||||
group.absent
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
|
|
|
@ -4,6 +4,9 @@ Various functions to be used by windows during start up and to monkey patch
|
|||
missing functions in other modules
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
import platform
|
||||
|
||||
# Import Salt Libs
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
# Import 3rd Party Libs
|
||||
|
@ -138,3 +141,19 @@ def get_current_user():
|
|||
return False
|
||||
|
||||
return user_name
|
||||
|
||||
|
||||
def get_sam_name(username):
|
||||
'''
|
||||
Gets the SAM name for a user. It basically prefixes a username without a
|
||||
backslash with the computer name. If the username contains a backslash, it
|
||||
is returned as is.
|
||||
|
||||
Everything is returned lower case
|
||||
|
||||
i.e. salt.utils.fix_local_user('Administrator') would return 'computername\administrator'
|
||||
'''
|
||||
if '\\' not in username:
|
||||
username = '{0}\\{1}'.format(platform.node(), username)
|
||||
|
||||
return username.lower()
|
||||
|
|
Loading…
Add table
Reference in a new issue