mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +00:00
260 lines
11 KiB
Python
260 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
'''
|
|
:codeauthor: Rahul Handay <rahulha@saltstack.com>
|
|
'''
|
|
|
|
# Import Python Libs
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
import logging
|
|
|
|
# Import Salt Testing Libs
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.unit import TestCase, skipIf
|
|
from tests.support.mock import (
|
|
Mock,
|
|
MagicMock,
|
|
patch,
|
|
NO_MOCK,
|
|
NO_MOCK_REASON
|
|
)
|
|
|
|
# Import Salt Libs
|
|
import salt.states.user as user
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
|
class UserTestCase(TestCase, LoaderModuleMockMixin):
|
|
'''
|
|
Validate the user state
|
|
'''
|
|
def setup_loader_modules(self):
|
|
return {user: {}}
|
|
|
|
def test_present(self):
|
|
'''
|
|
Test to ensure that the named user is present with
|
|
the specified properties
|
|
'''
|
|
ret = {'name': 'salt',
|
|
'changes': {},
|
|
'result': False,
|
|
'comment': ''}
|
|
mock_false = MagicMock(return_value=False)
|
|
mock_empty_list = MagicMock(return_value=[])
|
|
with patch.dict(user.__grains__, {"kernel": 'Linux'}):
|
|
with patch.dict(user.__salt__, {'group.info': mock_false,
|
|
'user.info': mock_empty_list,
|
|
"user.chkey": mock_empty_list,
|
|
'user.add': mock_false}):
|
|
ret.update({'comment': 'The following group(s) are'
|
|
' not present: salt'})
|
|
self.assertDictEqual(user.present('salt', groups=['salt']), ret)
|
|
|
|
mock_false = MagicMock(side_effect=[{'key': 'value'}, {'key': 'value'},
|
|
{'key': 'value'}, False, False])
|
|
with patch.object(user, '_changes', mock_false):
|
|
with patch.dict(user.__opts__, {"test": True}):
|
|
ret.update(
|
|
{'comment': 'The following user attributes are set '
|
|
'to be changed:\n'
|
|
'key: value\n',
|
|
'result': None})
|
|
self.assertDictEqual(user.present('salt'), ret)
|
|
|
|
with patch.dict(user.__opts__, {"test": False}):
|
|
# pylint: disable=repr-flag-used-in-string
|
|
comment = (
|
|
'These values could not be changed: {0!r}'
|
|
.format({'key': 'value'})
|
|
)
|
|
# pylint: enable=repr-flag-used-in-string
|
|
ret.update({'comment': comment, 'result': False})
|
|
self.assertDictEqual(user.present('salt'), ret)
|
|
|
|
with patch.dict(user.__opts__, {"test": True}):
|
|
ret.update({'comment': 'User salt set to'
|
|
' be added', 'result': None})
|
|
self.assertDictEqual(user.present('salt'), ret)
|
|
|
|
with patch.dict(user.__opts__, {"test": False}):
|
|
ret.update({'comment': 'Failed to create new'
|
|
' user salt', 'result': False})
|
|
self.assertDictEqual(user.present('salt'), ret)
|
|
|
|
def test_present_invalid_uid_change(self):
|
|
mock_info = MagicMock(side_effect=[
|
|
{'uid': 5000,
|
|
'gid': 5000,
|
|
'groups': ['foo'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar'}
|
|
])
|
|
dunder_salt = {'user.info': mock_info,
|
|
'file.group_to_gid': MagicMock(side_effect=['foo']),
|
|
'file.gid_to_group': MagicMock(side_effect=[5000])}
|
|
# side_effect used because these mocks should only be called once
|
|
with patch.dict(user.__grains__, {'kernel': 'Linux'}), \
|
|
patch.dict(user.__salt__, dunder_salt):
|
|
ret = user.present('foo', uid=5001)
|
|
# State should have failed
|
|
self.assertFalse(ret['result'])
|
|
# Only one of uid/gid should have been flagged in the comment
|
|
self.assertEqual(ret['comment'].count('not permitted'), 1)
|
|
|
|
def test_present_invalid_gid_change(self):
|
|
mock_info = MagicMock(side_effect=[
|
|
{'uid': 5000,
|
|
'gid': 5000,
|
|
'groups': ['foo'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar'}
|
|
])
|
|
dunder_salt = {'user.info': mock_info,
|
|
'file.group_to_gid': MagicMock(side_effect=['foo']),
|
|
'file.gid_to_group': MagicMock(side_effect=[5000])}
|
|
# side_effect used because these mocks should only be called once
|
|
with patch.dict(user.__grains__, {'kernel': 'Linux'}), \
|
|
patch.dict(user.__salt__, dunder_salt):
|
|
ret = user.present('foo', gid=5001)
|
|
# State should have failed
|
|
self.assertFalse(ret['result'])
|
|
# Only one of uid/gid should have been flagged in the comment
|
|
self.assertEqual(ret['comment'].count('not permitted'), 1)
|
|
|
|
def test_present_invalid_uid_gid_change(self):
|
|
mock_info = MagicMock(side_effect=[
|
|
{'uid': 5000,
|
|
'gid': 5000,
|
|
'groups': ['foo'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar'}
|
|
])
|
|
dunder_salt = {'user.info': mock_info,
|
|
'file.group_to_gid': MagicMock(side_effect=['foo']),
|
|
'file.gid_to_group': MagicMock(side_effect=[5000])}
|
|
# side_effect used because these mocks should only be called once
|
|
with patch.dict(user.__grains__, {'kernel': 'Linux'}), \
|
|
patch.dict(user.__salt__, dunder_salt):
|
|
ret = user.present('foo', uid=5001, gid=5001)
|
|
# State should have failed
|
|
self.assertFalse(ret['result'])
|
|
# Both the uid and gid should have been flagged in the comment
|
|
self.assertEqual(ret['comment'].count('not permitted'), 2)
|
|
|
|
def test_present_uid_gid_change(self):
|
|
before = {'uid': 5000,
|
|
'gid': 5000,
|
|
'groups': ['foo'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar'}
|
|
after = {'uid': 5001,
|
|
'gid': 5001,
|
|
'groups': ['othergroup'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar'}
|
|
# user.info should be called 4 times. Once the first time that
|
|
# _changes() is called, once before and after changes are applied (to
|
|
# get the before/after for the changes dict, and one last time to
|
|
# confirm that no changes still need to be made.
|
|
mock_info = MagicMock(side_effect=[before, before, after, after])
|
|
mock_group_to_gid = MagicMock(side_effect=['foo', 'othergroup'])
|
|
mock_gid_to_group = MagicMock(side_effect=[5000, 5001])
|
|
dunder_salt = {'user.info': mock_info,
|
|
'user.chuid': Mock(),
|
|
'user.chgid': Mock(),
|
|
'file.group_to_gid': mock_group_to_gid,
|
|
'file.gid_to_group': mock_gid_to_group}
|
|
# side_effect used because these mocks should only be called once
|
|
with patch.dict(user.__grains__, {'kernel': 'Linux'}), \
|
|
patch.dict(user.__salt__, dunder_salt), \
|
|
patch.dict(user.__opts__, {'test': False}), \
|
|
patch('os.path.isdir', MagicMock(return_value=True)):
|
|
ret = user.present(
|
|
'foo',
|
|
uid=5001,
|
|
gid=5001,
|
|
allow_uid_change=True,
|
|
allow_gid_change=True)
|
|
self.assertEqual(
|
|
ret,
|
|
{'comment': 'Updated user foo',
|
|
'changes': {'gid': 5001,
|
|
'uid': 5001,
|
|
'groups': ['othergroup']},
|
|
'name': 'foo',
|
|
'result': True}
|
|
)
|
|
|
|
def test_absent(self):
|
|
'''
|
|
Test to ensure that the named user is absent
|
|
'''
|
|
ret = {'name': 'salt',
|
|
'changes': {},
|
|
'result': None,
|
|
'comment': ''}
|
|
mock = MagicMock(side_effect=[True, True, False])
|
|
mock1 = MagicMock(return_value=False)
|
|
with patch.dict(user.__salt__, {'user.info': mock,
|
|
'user.delete': mock1,
|
|
'group.info': mock1}):
|
|
with patch.dict(user.__opts__, {"test": True}):
|
|
ret.update({'comment': 'User salt set for removal'})
|
|
self.assertDictEqual(user.absent('salt'), ret)
|
|
|
|
with patch.dict(user.__opts__, {"test": False}):
|
|
ret.update({'comment': 'Failed to remove user salt',
|
|
'result': False})
|
|
self.assertDictEqual(user.absent('salt'), ret)
|
|
|
|
ret.update({'comment': 'User salt is not present',
|
|
'result': True})
|
|
self.assertDictEqual(user.absent('salt'), ret)
|
|
|
|
def test_changes(self):
|
|
'''
|
|
Test salt.states.user._changes
|
|
'''
|
|
mock_info = MagicMock(
|
|
return_value={
|
|
'uid': 5000,
|
|
'gid': 5000,
|
|
'groups': ['foo'],
|
|
'home': '/home/foo',
|
|
'fullname': 'Foo Bar',
|
|
}
|
|
)
|
|
shadow_info = MagicMock(
|
|
return_value={
|
|
'min': 2,
|
|
'max': 88888,
|
|
'inact': 77,
|
|
'warn': 14,
|
|
}
|
|
)
|
|
shadow_hash = MagicMock(return_value='abcd')
|
|
dunder_salt = {'user.info': mock_info,
|
|
'shadow.info': shadow_info,
|
|
'shadow.default_hash': shadow_hash,
|
|
'file.group_to_gid': MagicMock(side_effect=['foo']),
|
|
'file.gid_to_group': MagicMock(side_effect=[5000])}
|
|
|
|
def mock_exists(*args):
|
|
return True
|
|
|
|
# side_effect used because these mocks should only be called once
|
|
with patch.dict(user.__grains__, {'kernel': 'Linux'}), \
|
|
patch.dict(user.__salt__, dunder_salt), \
|
|
patch.dict(user.__opts__, {"test": False}), \
|
|
patch('os.path.isdir', mock_exists):
|
|
ret = user._changes('foo', maxdays=999999, inactdays=0, warndays=7)
|
|
assert ret == {
|
|
'maxdays': 999999,
|
|
'mindays': 0,
|
|
'fullname': '',
|
|
'warndays': 7,
|
|
'inactdays': 0
|
|
}
|