mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Change how members are retrieved in win_groupadd
This is a solution that works for the other functions that interact with group objects, making it a better overall solution to be used widely in win_groupadd. This also updates the mocking in the tests such that we use a more comprehensive fake class, and more intelligent mocking of get_sam_name using a lambda.
This commit is contained in:
parent
6ab82394be
commit
5ce14df82c
@ -42,6 +42,20 @@ def _get_computer_object():
|
||||
return nt.GetObject('', 'WinNT://.,computer')
|
||||
|
||||
|
||||
def _get_group_object(name):
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
return nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
|
||||
|
||||
def _get_username(member):
|
||||
'''
|
||||
Resolve the username from the member object returned from a group query
|
||||
'''
|
||||
return member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower()
|
||||
|
||||
|
||||
def add(name, **kwargs):
|
||||
'''
|
||||
Add the specified group
|
||||
@ -147,14 +161,9 @@ def info(name):
|
||||
salt '*' group.info foo
|
||||
'''
|
||||
groupObj = _get_group_object(name)
|
||||
existing_members = _get_group_members(groupObj)
|
||||
try:
|
||||
gr_name = groupObj.Name
|
||||
gr_mem = []
|
||||
for member in existing_members:
|
||||
gr_mem.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace'))
|
||||
gr_mem = [_get_username(x) for x in groupObj.members()]
|
||||
except pywintypes.com_error:
|
||||
return False
|
||||
|
||||
@ -199,13 +208,8 @@ def getent(refresh=False):
|
||||
results = nt.GetObject('', 'WinNT://.')
|
||||
results.Filter = ['group']
|
||||
for result in results:
|
||||
member_list = []
|
||||
for member in result.members():
|
||||
member_list.append(
|
||||
member.AdsPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace'))
|
||||
group = {'gid': __salt__['file.group_to_gid'](result.name),
|
||||
'members': member_list,
|
||||
'members': [_get_username(x) for x in result.members()],
|
||||
'name': result.name,
|
||||
'passwd': 'x'}
|
||||
ret.append(group)
|
||||
@ -213,21 +217,6 @@ def getent(refresh=False):
|
||||
return ret
|
||||
|
||||
|
||||
def _get_group_object(name):
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
return nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
|
||||
|
||||
def _get_group_members(groupObj):
|
||||
existingMembers = []
|
||||
for member in groupObj.members():
|
||||
existingMembers.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
return existingMembers
|
||||
|
||||
|
||||
def adduser(name, username, **kwargs):
|
||||
'''
|
||||
Add a user to a group
|
||||
@ -256,10 +245,11 @@ def adduser(name, username, **kwargs):
|
||||
'comment': ''}
|
||||
|
||||
groupObj = _get_group_object(name)
|
||||
existingMembers = _get_group_members(groupObj)
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
username = salt.utils.win_functions.get_sam_name(username)
|
||||
|
||||
try:
|
||||
if salt.utils.win_functions.get_sam_name(username) not in existingMembers:
|
||||
if username not in existingMembers:
|
||||
if not __opts__['test']:
|
||||
groupObj.Add('WinNT://' + username.replace('\\', '/'))
|
||||
|
||||
@ -309,7 +299,7 @@ def deluser(name, username, **kwargs):
|
||||
'comment': ''}
|
||||
|
||||
groupObj = _get_group_object(name)
|
||||
existingMembers = _get_group_members(groupObj)
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
|
||||
try:
|
||||
if salt.utils.win_functions.get_sam_name(username) in existingMembers:
|
||||
@ -368,10 +358,8 @@ def members(name, members_list, **kwargs):
|
||||
ret['comment'].append('Members is not a list object')
|
||||
return ret
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
try:
|
||||
groupObj = nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
groupObj = _get_group_object(name)
|
||||
except pywintypes.com_error as com_err:
|
||||
if len(com_err.excepinfo) >= 2:
|
||||
friendly_error = com_err.excepinfo[2].rstrip('\r\n')
|
||||
@ -380,12 +368,7 @@ def members(name, members_list, **kwargs):
|
||||
'Failure accessing group {0}. {1}'
|
||||
).format(name, friendly_error))
|
||||
return ret
|
||||
existingMembers = []
|
||||
for member in groupObj.members():
|
||||
existingMembers.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
existingMembers.sort()
|
||||
members_list.sort()
|
||||
|
||||
|
@ -19,6 +19,7 @@ from tests.support.mock import (
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.modules.win_groupadd as win_groupadd
|
||||
import salt.utils.win_functions
|
||||
|
||||
# Import Other Libs
|
||||
# pylint: disable=unused-import
|
||||
@ -32,6 +33,37 @@ except ImportError:
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
class MockMember(object):
|
||||
def __init__(self, name):
|
||||
self.ADSPath = name
|
||||
|
||||
|
||||
class MockGroupObj(object):
|
||||
def __init__(self, ads_users):
|
||||
self._members = [MockMember(x) for x in ads_users]
|
||||
|
||||
def members(self):
|
||||
return self._members
|
||||
|
||||
def Add(self):
|
||||
'''
|
||||
This should be a no-op unless we want to test raising an error, in
|
||||
which case this should be overridden in a subclass.
|
||||
'''
|
||||
pass
|
||||
|
||||
def Remove(self):
|
||||
'''
|
||||
This should be a no-op unless we want to test raising an error, in
|
||||
which case this should be overridden in a subclass.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
if not NO_MOCK:
|
||||
sam_mock = MagicMock(side_effect=lambda x: 'HOST\\' + x)
|
||||
|
||||
|
||||
@skipIf(not HAS_WIN_LIBS, 'win_groupadd unit tests can only be run if win32com, pythoncom, and pywintypes are installed')
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
@ -151,21 +183,14 @@ class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'''
|
||||
Test if it return information about a group.
|
||||
'''
|
||||
members = MagicMock(return_value=['HOST\\steve'])
|
||||
with patch.object(win_groupadd, '_get_group_object', Mock()), \
|
||||
patch.object(win_groupadd, '_get_group_members', members):
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj(['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock):
|
||||
self.assertDictEqual(win_groupadd.info('salt'),
|
||||
{'gid': None,
|
||||
'members': ['user1'],
|
||||
'members': ['HOST\\steve'],
|
||||
'passwd': None,
|
||||
'name': 'salt'})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 1):
|
||||
self.assertFalse(win_groupadd.info('dc=salt'))
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 2):
|
||||
self.assertFalse(win_groupadd.info('dc=salt'))
|
||||
|
||||
# 'getent' function tests: 1
|
||||
|
||||
def test_getent(self):
|
||||
@ -175,73 +200,70 @@ class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
with patch.dict(win_groupadd.__context__, {'group.getent': True}):
|
||||
self.assertTrue(win_groupadd.getent())
|
||||
|
||||
# 'adduser' function tests: 1
|
||||
# 'adduser' function tests: 3
|
||||
|
||||
def test_adduser(self):
|
||||
'''
|
||||
Test adding a user to a group
|
||||
'''
|
||||
members = MagicMock(return_value=['HOST\\steve'])
|
||||
with patch.object(win_groupadd, '_get_group_object', Mock()),\
|
||||
patch.object(win_groupadd, '_get_group_members', members),\
|
||||
patch('salt.utils.win_functions.get_sam_name', return_value='HOST\\spongebob'):
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj(['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'spongebob'),
|
||||
{'changes': {'Users Added': ['spongebob']},
|
||||
{'changes': {'Users Added': ['HOST\\spongebob']},
|
||||
'comment': '',
|
||||
'name': 'foo',
|
||||
'result': True})
|
||||
|
||||
def test_add_user_already_exists(self):
|
||||
def test_adduser_already_exists(self):
|
||||
'''
|
||||
Test adding a user that already exists
|
||||
'''
|
||||
members = MagicMock(return_value=['HOST\\steve'])
|
||||
with patch.object(win_groupadd, '_get_group_object', Mock()), \
|
||||
patch.object(win_groupadd, '_get_group_members', members), \
|
||||
patch('salt.utils.win_functions.get_sam_name', return_value='HOST\\spongebob'):
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj(['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'spongebob'),
|
||||
{'changes': {'Users Added': ['spongebob']},
|
||||
'comment': '',
|
||||
win_groupadd.adduser('foo', 'HOST\\steve'),
|
||||
{'changes': {'Users Added': []},
|
||||
'comment': 'User HOST\\steve is already a member of foo',
|
||||
'name': 'foo',
|
||||
'result': True})
|
||||
'result': None})
|
||||
|
||||
def test_add_user_error(self):
|
||||
def test_adduser_error(self):
|
||||
'''
|
||||
Test adding a user and encountering an error
|
||||
'''
|
||||
# Create mock group object
|
||||
class GroupObj(object):
|
||||
# Create mock group object with mocked Add function which raises the
|
||||
# exception we need in order to test the error case.
|
||||
class GroupObj(MockGroupObj):
|
||||
def Add(self, name):
|
||||
raise pywintypes.com_error(-2147352567, 'Exception occurred.', (0, None, 'C', None, 0, -2146788248), None)
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj())
|
||||
members = MagicMock(return_value=['HOST\\steve'])
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock):
|
||||
with patch.object(win_groupadd, '_get_group_members', members):
|
||||
comt = ('Failed to add username to group foo. C')
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'username'),
|
||||
{'changes': {'Users Added': []},
|
||||
'name': 'foo',
|
||||
'comment': comt,
|
||||
'result': False})
|
||||
groupobj_mock = MagicMock(return_value=GroupObj(['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'username'),
|
||||
{'changes': {'Users Added': []},
|
||||
'name': 'foo',
|
||||
'comment': 'Failed to add HOST\\username to group foo. C',
|
||||
'result': False})
|
||||
|
||||
# 'deluser' function tests: 1
|
||||
# 'deluser' function tests: 3
|
||||
|
||||
def test_deluser(self):
|
||||
'''
|
||||
Test removing a user from a group
|
||||
'''
|
||||
# Test removing a user
|
||||
members = MagicMock(return_value=['HOST\\spongebob'])
|
||||
with patch.object(win_groupadd, '_get_group_object', Mock()), \
|
||||
patch.object(win_groupadd, '_get_group_members', members), \
|
||||
patch('salt.utils.win_functions.get_sam_name', return_value='HOST\\spongebob'):
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj(['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
ret = {'changes': {'Users Removed': ['spongebob']},
|
||||
'comment': '',
|
||||
'name': 'foo', 'result': True}
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
self.assertDictEqual(win_groupadd.deluser('foo', 'spongebob'), ret)
|
||||
|
||||
def test_deluser_no_user(self):
|
||||
@ -249,15 +271,13 @@ class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
Test removing a user from a group and that user is not a member of the
|
||||
group
|
||||
'''
|
||||
|
||||
# Test removing a user that's not in the group
|
||||
members = MagicMock(return_value=['HOST\\steve'])
|
||||
with patch.object(win_groupadd, '_get_group_object', Mock()), \
|
||||
patch.object(win_groupadd, '_get_group_members', members), \
|
||||
patch('salt.utils.win_functions.get_sam_name', return_value='HOST\\spongebob'):
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj(['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
ret = {'changes': {'Users Removed': []},
|
||||
'comment': 'User username is not a member of foo',
|
||||
'name': 'foo', 'result': None}
|
||||
'comment': 'User HOST\\spongebob is not a member of foo',
|
||||
'name': 'foo',
|
||||
'result': None}
|
||||
self.assertDictEqual(win_groupadd.deluser('foo', 'username'), ret)
|
||||
|
||||
def test_deluser_error(self):
|
||||
@ -268,18 +288,14 @@ class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
def Remove(self, name):
|
||||
raise pywintypes.com_error(-2147352567, 'Exception occurred.', (0, None, 'C', None, 0, -2146788248), None)
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj())
|
||||
|
||||
members = MagicMock(return_value=['HOST\\spongebob'])
|
||||
groupobj_mock = MagicMock(return_value=GroupObj(['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(win_groupadd, '_get_group_members', members), \
|
||||
patch('salt.utils.win_functions.get_sam_name', return_value='HOST\\spongebob'):
|
||||
comt = ('Failed to remove spongebob from group foo. C')
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.deluser('foo', 'spongebob'),
|
||||
{'changes': {'Users Removed': []},
|
||||
'name': 'foo',
|
||||
'comment': comt,
|
||||
'comment': 'Failed to remove spongebob from group foo. C',
|
||||
'result': False})
|
||||
|
||||
# 'members' function tests: 1
|
||||
|
Loading…
Reference in New Issue
Block a user