mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 01:18:58 +00:00
commit
98b868c573
@ -26,19 +26,6 @@ from salt.exceptions import SaltInvocationError
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
try:
|
||||
from shlex import quote as _cmd_quote # pylint: disable=E0611
|
||||
except ImportError:
|
||||
from pipes import quote as _cmd_quote
|
||||
|
||||
from salt.exceptions import (
|
||||
SaltInvocationError
|
||||
)
|
||||
|
||||
try:
|
||||
from shlex import quote as _cmd_quote # pylint: disable=E0611
|
||||
except ImportError:
|
||||
from pipes import quote as _cmd_quote
|
||||
|
||||
# Set up logging
|
||||
log = logging.getLogger(__name__)
|
||||
@ -92,29 +79,30 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def _check_gpg():
|
||||
def _gpg():
|
||||
'''
|
||||
Looks to see if gpg binary is present on the system.
|
||||
Returns the path to the gpg binary
|
||||
'''
|
||||
# Get the path to the gpg binary.
|
||||
if salt.utils.which('gpg'):
|
||||
return __virtualname__
|
||||
return (False, 'The gpg execution module cannot be loaded: '
|
||||
'gpg binary is not in the path.')
|
||||
return salt.utils.which('gpg')
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Makes sure that python-gnupg and gpg are available.
|
||||
'''
|
||||
if _check_gpg() and HAS_LIBS:
|
||||
if not _gpg():
|
||||
return (False, 'The gpg execution module cannot be loaded: '
|
||||
'gpg binary is not in the path.')
|
||||
if HAS_LIBS:
|
||||
gnupg_version = distutils.version.LooseVersion(gnupg.__version__)
|
||||
if gnupg_version >= '1.3.1':
|
||||
global GPG_1_3_1
|
||||
GPG_1_3_1 = True
|
||||
return __virtualname__
|
||||
return (False, 'The gpg execution module cannot be loaded; either the'
|
||||
' gnupg module is not installed or the gpg binary is not in the path.')
|
||||
|
||||
return (False, 'The gpg execution module cannot be loaded; the'
|
||||
' gnupg python module is not installed.')
|
||||
|
||||
|
||||
def _create_gpg(user=None, gnupghome=None):
|
||||
@ -850,15 +838,18 @@ def trust_key(keyid=None,
|
||||
if trust_level not in _VALID_TRUST_LEVELS:
|
||||
return 'ERROR: Valid trust levels - {0}'.format(','.join(_VALID_TRUST_LEVELS))
|
||||
|
||||
cmd = 'echo "{0}:{1}" | {2} --import-ownertrust'.format(_cmd_quote(fingerprint),
|
||||
_cmd_quote(NUM_TRUST_DICT[trust_level]),
|
||||
_cmd_quote(_check_gpg()))
|
||||
stdin = '{0}:{1}\n'.format(fingerprint, NUM_TRUST_DICT[trust_level])
|
||||
cmd = [_gpg(), '--import-ownertrust']
|
||||
_user = user
|
||||
|
||||
if user == 'salt':
|
||||
homeDir = os.path.join(salt.syspaths.CONFIG_DIR, 'gpgkeys')
|
||||
cmd = '{0} --homedir {1}'.format(cmd, homeDir)
|
||||
cmd.extend([' --homedir', homeDir])
|
||||
_user = 'root'
|
||||
res = __salt__['cmd.run_all'](cmd, runas=_user, python_shell=True)
|
||||
res = __salt__['cmd.run_all'](cmd,
|
||||
stdin=stdin,
|
||||
runas=_user,
|
||||
python_shell=False)
|
||||
|
||||
if not res['retcode'] == 0:
|
||||
ret['res'] = False
|
||||
|
@ -18,6 +18,7 @@ from salt.ext.six import string_types
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.decorators as decorators
|
||||
from salt.utils.locales import sdecode
|
||||
from salt.exceptions import CommandExecutionError, SaltInvocationError
|
||||
|
||||
@ -115,7 +116,8 @@ def add(name,
|
||||
_dscl([name_path, 'RealName', fullname])
|
||||
|
||||
# Make sure home directory exists
|
||||
__salt__['file.mkdir'](name)
|
||||
if createhome:
|
||||
__salt__['file.mkdir'](home, user=uid, group=gid)
|
||||
|
||||
# dscl buffers changes, sleep before setting group membership
|
||||
time.sleep(1)
|
||||
@ -124,7 +126,7 @@ def add(name,
|
||||
return True
|
||||
|
||||
|
||||
def delete(name, *args):
|
||||
def delete(name, remove=False, force=False):
|
||||
'''
|
||||
Remove a user from the minion
|
||||
|
||||
@ -134,12 +136,19 @@ def delete(name, *args):
|
||||
|
||||
salt '*' user.delete foo
|
||||
'''
|
||||
### NOTE: *args isn't used here but needs to be included in this function
|
||||
### for compatibility with the user.absent state
|
||||
if salt.utils.contains_whitespace(name):
|
||||
raise SaltInvocationError('Username cannot contain whitespace')
|
||||
if not info(name):
|
||||
return True
|
||||
|
||||
# force is added for compatibility with user.absent state function
|
||||
if force:
|
||||
log.warn('force option is unsupported on MacOS, ignoring')
|
||||
|
||||
# remove home directory from filesystem
|
||||
if remove:
|
||||
__salt__['file.remove'](info(name)['home'])
|
||||
|
||||
# Remove from any groups other than primary group. Needs to be done since
|
||||
# group membership is managed separately from users and an entry for the
|
||||
# user will persist even after the user is removed.
|
||||
@ -396,6 +405,22 @@ def _format_info(data):
|
||||
'fullname': data.pw_gecos}
|
||||
|
||||
|
||||
@decorators.which('id')
|
||||
def primary_group(name):
|
||||
'''
|
||||
Return the primary group of the named user
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.primary_group saltadmin
|
||||
'''
|
||||
return __salt__['cmd.run'](['id', '-g', '-n', name])
|
||||
|
||||
|
||||
def list_groups(name):
|
||||
'''
|
||||
Return a list of groups the named user belongs to
|
||||
|
@ -14,6 +14,7 @@ import copy
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.decorators as decorators
|
||||
from salt.ext import six
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
@ -574,6 +575,22 @@ def _format_info(data):
|
||||
'homephone': gecos_field[3]}
|
||||
|
||||
|
||||
@decorators.which('id')
|
||||
def primary_group(name):
|
||||
'''
|
||||
Return the primary group of the named user
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.primary_group saltadmin
|
||||
'''
|
||||
return __salt__['cmd.run'](['id', '-g', '-n', name])
|
||||
|
||||
|
||||
def list_groups(name):
|
||||
'''
|
||||
Return a list of groups the named user belongs to
|
||||
|
@ -858,6 +858,41 @@ def path_join(*parts):
|
||||
))
|
||||
|
||||
|
||||
def abs_readlink(path):
|
||||
'''
|
||||
Return the absolute path. If path is a link, dereference it first.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import os
|
||||
>>> os.makedirs('/tmp/dir')
|
||||
>>> os.chdir('/tmp/dir')
|
||||
>>> open('/tmp/dir/target', 'w').close()
|
||||
>>> os.symlink('target', 'link1')
|
||||
>>> os.symlink('../dir/target', 'link2')
|
||||
>>> os.symlink('/tmp/dir/target', 'link3')
|
||||
>>> abs_readlink('/tmp/dir/target')
|
||||
'/tmp/dir/target'
|
||||
>>> abs_readlink('/tmp/dir/link1')
|
||||
'/tmp/dir/target'
|
||||
>>> abs_readlink('/tmp/dir/link2')
|
||||
'/tmp/dir/target'
|
||||
>>> abs_readlink('/tmp/dir/link3')
|
||||
'/tmp/dir/target'
|
||||
>>> from subprocess import call
|
||||
>>> call(['rm', '-r', '/tmp/dir'])
|
||||
'''
|
||||
if os.path.islink(path):
|
||||
base, lname = os.path.split(os.path.abspath(path))
|
||||
target = os.readlink(path)
|
||||
if target.startswith(os.sep):
|
||||
return os.path.abspath(target)
|
||||
else: # target path is relative to supplied path
|
||||
return os.path.abspath(os.path.join(base, target))
|
||||
else:
|
||||
return os.path.abspath(path)
|
||||
|
||||
|
||||
def pem_finger(path=None, key=None, sum_type='sha256'):
|
||||
'''
|
||||
Pass in either a raw pem string, or the path on disk to the location of a
|
||||
|
@ -78,10 +78,7 @@ if salt.utils.is_windows():
|
||||
import win32api
|
||||
|
||||
|
||||
if platform.uname()[0] == 'Darwin':
|
||||
SYS_TMP_DIR = '/tmp'
|
||||
else:
|
||||
SYS_TMP_DIR = os.environ.get('TMPDIR', tempfile.gettempdir())
|
||||
SYS_TMP_DIR = salt.utils.abs_readlink(os.environ.get('TMPDIR', tempfile.gettempdir()))
|
||||
|
||||
# Gentoo Portage prefers ebuild tests are rooted in ${TMPDIR}
|
||||
TMP = os.path.join(SYS_TMP_DIR, 'salt-tests-tmpdir')
|
||||
|
@ -12,7 +12,11 @@ from __future__ import absolute_import
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
SYS_TMP_DIR = tempfile.gettempdir()
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
|
||||
|
||||
SYS_TMP_DIR = salt.utils.abs_readlink(os.environ.get('TMPDIR', tempfile.gettempdir()))
|
||||
# This tempdir path is defined on tests.integration.__init__
|
||||
TMP = os.path.join(SYS_TMP_DIR, 'salt-tests-tmpdir')
|
||||
|
||||
|
@ -18,27 +18,24 @@ import salt.utils
|
||||
import salt.ext.six as six
|
||||
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'No mtab on Windows')
|
||||
@skipIf(salt.utils.is_darwin(), 'No mtab on Darwin')
|
||||
class DiskModuleVirtualizationTest(integration.ModuleCase):
|
||||
'''
|
||||
Test to make sure we return a clean result under Docker. Refs #8976
|
||||
|
||||
This is factored into its own class so that we can have some certainty that setUp() and tearDown() are run.
|
||||
'''
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'No mtab on Windows')
|
||||
def setUp(self):
|
||||
# Make /etc/mtab unreadable
|
||||
if os.path.isfile('/etc/mtab'):
|
||||
shutil.move('/etc/mtab', '/tmp/mtab')
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'No mtab on Windows')
|
||||
def test_no_mtab(self):
|
||||
ret = self.run_function('disk.usage')
|
||||
self.assertDictEqual(ret, {})
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(salt.utils.is_windows(), 'No mtab on Windows')
|
||||
def tearDown(self):
|
||||
if os.path.isfile('/tmp/mtab'):
|
||||
shutil.move('/tmp/mtab', '/etc/mtab')
|
||||
@ -56,12 +53,23 @@ class DiskModuleTest(integration.ModuleCase):
|
||||
self.assertTrue(isinstance(ret, dict))
|
||||
if not isinstance(ret, dict):
|
||||
return
|
||||
for key, val in six.iteritems(ret):
|
||||
self.assertTrue('filesystem' in val)
|
||||
self.assertTrue('1K-blocks' in val)
|
||||
self.assertTrue('used' in val)
|
||||
self.assertTrue('available' in val)
|
||||
self.assertTrue('capacity' in val)
|
||||
if salt.utils.is_darwin():
|
||||
for key, val in six.iteritems(ret):
|
||||
self.assertTrue('filesystem' in val)
|
||||
self.assertTrue('512-blocks' in val)
|
||||
self.assertTrue('used' in val)
|
||||
self.assertTrue('available' in val)
|
||||
self.assertTrue('capacity' in val)
|
||||
self.assertTrue('iused' in val)
|
||||
self.assertTrue('ifree' in val)
|
||||
self.assertTrue('%iused' in val)
|
||||
else:
|
||||
for key, val in six.iteritems(ret):
|
||||
self.assertTrue('filesystem' in val)
|
||||
self.assertTrue('1K-blocks' in val)
|
||||
self.assertTrue('used' in val)
|
||||
self.assertTrue('available' in val)
|
||||
self.assertTrue('capacity' in val)
|
||||
|
||||
def test_inodeusage(self):
|
||||
'''
|
||||
@ -81,4 +89,4 @@ class DiskModuleTest(integration.ModuleCase):
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(DiskModuleTest)
|
||||
run_tests([DiskModuleVirtualizationTest, DiskModuleTest])
|
||||
|
@ -38,9 +38,13 @@ def __random_string(size=6):
|
||||
# Create user strings for tests
|
||||
ADD_USER = __random_string()
|
||||
DEL_USER = __random_string()
|
||||
PRIMARY_GROUP_USER = __random_string()
|
||||
CHANGE_USER = __random_string()
|
||||
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
class MacUserModuleTest(integration.ModuleCase):
|
||||
'''
|
||||
Integration tests for the mac_user module
|
||||
@ -59,9 +63,6 @@ class MacUserModuleTest(integration.ModuleCase):
|
||||
)
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_mac_user_add(self, grains=None):
|
||||
'''
|
||||
Tests the add function
|
||||
@ -74,9 +75,6 @@ class MacUserModuleTest(integration.ModuleCase):
|
||||
self.run_function('user.delete', [ADD_USER])
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_mac_user_delete(self, grains=None):
|
||||
'''
|
||||
Tests the delete function
|
||||
@ -94,9 +92,26 @@ class MacUserModuleTest(integration.ModuleCase):
|
||||
except CommandExecutionError:
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def test_mac_user_primary_group(self, grains=None):
|
||||
'''
|
||||
Tests the primary_group function
|
||||
'''
|
||||
|
||||
# Create a user to test primary group function
|
||||
if self.run_function('user.add', [PRIMARY_GROUP_USER]) is not True:
|
||||
self.run_function('user.delete', [PRIMARY_GROUP_USER])
|
||||
self.skipTest('Failed to create a user')
|
||||
|
||||
try:
|
||||
# Test mac_user.primary_group
|
||||
primary_group = self.run_function('user.primary_group', [PRIMARY_GROUP_USER])
|
||||
uid_info = self.run_function('user.info', [PRIMARY_GROUP_USER])
|
||||
self.assertIn(primary_group, uid_info['groups'])
|
||||
|
||||
except AssertionError:
|
||||
self.run_function('user.delete', [PRIMARY_GROUP_USER])
|
||||
raise
|
||||
|
||||
def test_mac_user_changes(self, grains=None):
|
||||
'''
|
||||
Tests mac_user functions that change user properties
|
||||
@ -107,7 +122,7 @@ class MacUserModuleTest(integration.ModuleCase):
|
||||
self.skipTest('Failed to create a user')
|
||||
|
||||
try:
|
||||
# Test mac_user.chudi
|
||||
# Test mac_user.chuid
|
||||
self.run_function('user.chuid', [CHANGE_USER, 4376])
|
||||
uid_info = self.run_function('user.info', [CHANGE_USER])
|
||||
self.assertEqual(uid_info['uid'], 4376)
|
||||
@ -141,9 +156,6 @@ class MacUserModuleTest(integration.ModuleCase):
|
||||
self.run_function('user.delete', [CHANGE_USER])
|
||||
raise
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'You must be logged in as root to run this test')
|
||||
@requires_system_grains
|
||||
def tearDown(self, grains=None):
|
||||
'''
|
||||
Clean up after tests
|
||||
|
@ -16,12 +16,18 @@ from salttesting.helpers import (
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import integration
|
||||
|
||||
# Import 3rd-party libs
|
||||
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
|
||||
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'you must be root to run these tests')
|
||||
# Only run on linux for now until or if we can figure out a way to use
|
||||
# __grains__ inside of useradd.__virtual__
|
||||
@skipIf(not salt.utils.is_linux(), 'These tests can only be run on linux')
|
||||
class UseraddModuleTest(integration.ModuleCase):
|
||||
|
||||
def setUp(self):
|
||||
@ -40,8 +46,6 @@ class UseraddModuleTest(integration.ModuleCase):
|
||||
for x in range(size)
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
@skipIf(os.geteuid() != 0, 'you must be root to run this test')
|
||||
@requires_system_grains
|
||||
def test_groups_includes_primary(self, grains=None):
|
||||
# Let's create a user, which usually creates the group matching the
|
||||
@ -85,6 +89,27 @@ class UseraddModuleTest(integration.ModuleCase):
|
||||
self.run_function('user.delete', [uname, True, True])
|
||||
raise
|
||||
|
||||
def test_linux_user_primary_group(self, grains=None):
|
||||
'''
|
||||
Tests the primary_group function
|
||||
'''
|
||||
name = 'saltyuser'
|
||||
|
||||
# Create a user to test primary group function
|
||||
if self.run_function('user.add', [name]) is not True:
|
||||
self.run_function('user.delete', [name])
|
||||
self.skipTest('Failed to create a user')
|
||||
|
||||
try:
|
||||
# Test useradd.primary_group
|
||||
primary_group = self.run_function('user.primary_group', [name])
|
||||
uid_info = self.run_function('user.info', [name])
|
||||
self.assertIn(primary_group, uid_info['groups'])
|
||||
|
||||
except:
|
||||
self.run_function('user.delete', [name])
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
@ -31,7 +31,7 @@ class EnabledTest(integration.ModuleCase):
|
||||
'''
|
||||
ensure that python_shell defaults to True for cmd.run
|
||||
'''
|
||||
enabled_ret = '3\nsaltines'
|
||||
enabled_ret = '3\nsaltines' # the result of running self.cmd in a shell
|
||||
ret = self.run_function('cmd.run', [self.cmd])
|
||||
self.assertEqual(ret, enabled_ret)
|
||||
|
||||
@ -52,12 +52,12 @@ class EnabledTest(integration.ModuleCase):
|
||||
state_filename = state_name + '.sls'
|
||||
state_file = os.path.join(STATE_DIR, state_filename)
|
||||
|
||||
enabled_ret = '3 saltines'
|
||||
enabled_ret = '3 saltines' # the result of running self.cmd in a shell
|
||||
ret_key = 'test_|-shell_enabled_|-{0}_|-configurable_test_state'.format(enabled_ret)
|
||||
|
||||
try:
|
||||
salt.utils.fopen(state_file, 'w').write(textwrap.dedent('''\
|
||||
{{% set shell_enabled = salt['cmd.run']("{0}") %}}
|
||||
{{% set shell_enabled = salt['cmd.run']("{0}").strip() %}}
|
||||
|
||||
shell_enabled:
|
||||
test.configurable_test_state:
|
||||
@ -77,6 +77,7 @@ class EnabledTest(integration.ModuleCase):
|
||||
state_filename = state_name + '.sls'
|
||||
state_file = os.path.join(STATE_DIR, state_filename)
|
||||
|
||||
# the result of running self.cmd not in a shell
|
||||
disabled_ret = ('first second third | wc -l ; export SALTY_VARIABLE=saltines '
|
||||
'&& echo $SALTY_VARIABLE ; echo duh &> /dev/null')
|
||||
ret_key = 'test_|-shell_enabled_|-{0}_|-configurable_test_state'.format(disabled_ret)
|
||||
|
@ -142,14 +142,14 @@ class CMDTest(integration.ModuleCase,
|
||||
state_filename = state_name + '.sls'
|
||||
state_file = os.path.join(STATE_DIR, state_filename)
|
||||
|
||||
saltines_key = 'cmd_|-saltines_|-/bin/true_|-run'
|
||||
saltines_key = 'cmd_|-saltines_|-echo_|-run'
|
||||
biscuits_key = 'cmd_|-biscuits_|-echo hello_|-wait'
|
||||
|
||||
try:
|
||||
salt.utils.fopen(state_file, 'w').write(textwrap.dedent('''\
|
||||
saltines:
|
||||
cmd.run:
|
||||
- name: /bin/true
|
||||
- name: echo
|
||||
- cwd: /
|
||||
- stateful: True
|
||||
|
||||
|
@ -1831,7 +1831,9 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
|
||||
self.assertEqual(pwd.getpwuid(onestats.st_uid).pw_name, user)
|
||||
self.assertEqual(pwd.getpwuid(twostats.st_uid).pw_name, 'root')
|
||||
self.assertEqual(grp.getgrgid(onestats.st_gid).gr_name, group)
|
||||
self.assertEqual(grp.getgrgid(twostats.st_gid).gr_name, 'root')
|
||||
if salt.utils.which('id'):
|
||||
root_group = self.run_function('user.primary_group', ['root'])
|
||||
self.assertEqual(grp.getgrgid(twostats.st_gid).gr_name, root_group)
|
||||
finally:
|
||||
if os.path.isdir(tmp_dir):
|
||||
shutil.rmtree(tmp_dir)
|
||||
|
@ -30,7 +30,8 @@ _PKG_TARGETS = {
|
||||
'Debian': ['python-plist', 'apg'],
|
||||
'RedHat': ['xz-devel', 'zsh-html'],
|
||||
'FreeBSD': ['aalib', 'pth'],
|
||||
'Suse': ['aalib', 'python-pssh']
|
||||
'Suse': ['aalib', 'python-pssh'],
|
||||
'MacOS': ['libpng', 'jpeg'],
|
||||
}
|
||||
|
||||
_PKG_TARGETS_32 = {
|
||||
|
@ -246,4 +246,4 @@ class SSHAuthStateTests(integration.ModuleCase,
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(SSHKnownHostsStateTest)
|
||||
run_tests([SSHKnownHostsStateTest, SSHAuthStateTests])
|
||||
|
@ -22,6 +22,7 @@ from salttesting.helpers import (
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import integration
|
||||
|
||||
|
||||
@ -107,8 +108,12 @@ class UserTest(integration.ModuleCase,
|
||||
If you run the test and it fails, please fix the code it's testing to
|
||||
work on your operating system.
|
||||
'''
|
||||
# MacOS users' primary group defaults to staff (20), not the name of
|
||||
# user
|
||||
gid_from_name = False if grains['os_family'] == 'MacOS' else True
|
||||
|
||||
ret = self.run_state('user.present', name='salt_test',
|
||||
gid_from_name=True, home='/var/lib/salt_test')
|
||||
gid_from_name=gid_from_name, home='/var/lib/salt_test')
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
||||
ret = self.run_function('user.info', ['salt_test'])
|
||||
@ -118,6 +123,8 @@ class UserTest(integration.ModuleCase,
|
||||
self.assertTrue(os.path.isdir('/var/lib/salt_test'))
|
||||
if grains['os_family'] in ('Suse',):
|
||||
self.assertEqual(group_name, 'users')
|
||||
elif grains['os_family'] == 'MacOS':
|
||||
self.assertEqual(group_name, 'staff')
|
||||
else:
|
||||
self.assertEqual(group_name, 'salt_test')
|
||||
|
||||
@ -186,9 +193,11 @@ class UserTest(integration.ModuleCase,
|
||||
ret = self.run_function('user.info', ['salt_test'])
|
||||
self.assertReturnNonEmptySaltType(ret)
|
||||
self.assertEqual('', ret['fullname'])
|
||||
self.assertEqual('', ret['roomnumber'])
|
||||
self.assertEqual('', ret['workphone'])
|
||||
self.assertEqual('', ret['homephone'])
|
||||
# MacOS does not supply the following GECOS fields
|
||||
if not salt.utils.is_darwin():
|
||||
self.assertEqual('', ret['roomnumber'])
|
||||
self.assertEqual('', ret['workphone'])
|
||||
self.assertEqual('', ret['homephone'])
|
||||
|
||||
ret = self.run_state('user.absent', name='salt_test')
|
||||
self.assertSaltTrueReturn(ret)
|
||||
|
@ -40,7 +40,17 @@ try:
|
||||
except OSError as err:
|
||||
print('Failed to change directory to salt\'s source: {0}'.format(err))
|
||||
|
||||
REQUIRED_OPEN_FILES = 3072
|
||||
# Soft and hard limits on max open filehandles
|
||||
MAX_OPEN_FILES = {
|
||||
'integration': {
|
||||
'soft_limit': 3072,
|
||||
'hard_limit': 4096,
|
||||
},
|
||||
'unit': {
|
||||
'soft_limit': 1024,
|
||||
'hard_limit': 2048,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
@ -292,7 +302,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
|
||||
def start_daemons_only(self):
|
||||
if not salt.utils.is_windows():
|
||||
self.prep_filehandles()
|
||||
self.set_filehandle_limits('integration')
|
||||
try:
|
||||
print_header(
|
||||
' * Setting up Salt daemons for interactive use',
|
||||
@ -335,32 +345,51 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
def prep_filehandles(self):
|
||||
smax_open_files, hmax_open_files = resource.getrlimit(
|
||||
resource.RLIMIT_NOFILE
|
||||
)
|
||||
if smax_open_files < REQUIRED_OPEN_FILES:
|
||||
def set_filehandle_limits(self, limits='integration'):
|
||||
'''
|
||||
Set soft and hard limits on open file handles at required thresholds
|
||||
for integration tests or unit tests
|
||||
'''
|
||||
# Get current limits
|
||||
prev_soft, prev_hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
|
||||
# Get required limits
|
||||
min_soft = MAX_OPEN_FILES[limits]['soft_limit']
|
||||
min_hard = MAX_OPEN_FILES[limits]['hard_limit']
|
||||
|
||||
# Check minimum required limits
|
||||
set_limits = False
|
||||
if prev_soft < min_soft:
|
||||
soft = min_soft
|
||||
set_limits = True
|
||||
else:
|
||||
soft = prev_soft
|
||||
|
||||
if prev_hard < min_hard:
|
||||
hard = min_hard
|
||||
set_limits = True
|
||||
else:
|
||||
hard = prev_hard
|
||||
|
||||
# Increase limits
|
||||
if set_limits:
|
||||
print(
|
||||
' * Max open files setting is too low({0}) for running the '
|
||||
'tests'.format(smax_open_files)
|
||||
' * Max open files settings is too low (soft: {0}, hard: {1}) '
|
||||
'for running the tests'.format(prev_soft, prev_hard)
|
||||
)
|
||||
print(
|
||||
' * Trying to raise the limit to {0}'.format(REQUIRED_OPEN_FILES)
|
||||
' * Trying to raise the limits to soft: '
|
||||
'{0}, hard: {1}'.format(soft, hard)
|
||||
)
|
||||
if hmax_open_files < 4096:
|
||||
hmax_open_files = 4096 # Decent default?
|
||||
try:
|
||||
resource.setrlimit(
|
||||
resource.RLIMIT_NOFILE,
|
||||
(REQUIRED_OPEN_FILES, hmax_open_files)
|
||||
)
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard))
|
||||
except Exception as err:
|
||||
print(
|
||||
'ERROR: Failed to raise the max open files setting -> '
|
||||
'ERROR: Failed to raise the max open files settings -> '
|
||||
'{0}'.format(err)
|
||||
)
|
||||
print('Please issue the following command on your console:')
|
||||
print(' ulimit -n {0}'.format(REQUIRED_OPEN_FILES))
|
||||
print(' ulimit -n {0}'.format(soft))
|
||||
self.exit()
|
||||
finally:
|
||||
print('~' * getattr(self.options, 'output_columns', PNUM))
|
||||
@ -401,7 +430,7 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
# We don't need the tests daemon running
|
||||
return [True]
|
||||
if not salt.utils.is_windows():
|
||||
self.prep_filehandles()
|
||||
self.set_filehandle_limits('integration')
|
||||
|
||||
try:
|
||||
print_header(
|
||||
@ -480,6 +509,9 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
|
||||
status = []
|
||||
if self.options.unit:
|
||||
# MacOS needs more open filehandles for running unit test suite
|
||||
self.set_filehandle_limits('unit')
|
||||
|
||||
results = self.run_suite(
|
||||
os.path.join(TEST_DIR, 'unit'), 'Unit', '*_test.py'
|
||||
)
|
||||
|
@ -37,6 +37,8 @@ class TestBlockdevModule(TestCase):
|
||||
ret = blockdev.tune('/dev/sda', **kwargs)
|
||||
self.assertTrue(ret)
|
||||
|
||||
@skipIf(not salt.utils.which('sync'), 'sync not found')
|
||||
@skipIf(not salt.utils.which('mkfs'), 'mkfs not found')
|
||||
def test_format(self):
|
||||
'''
|
||||
unit tests for blockdev.format
|
||||
|
@ -7,6 +7,7 @@ from __future__ import absolute_import
|
||||
# Import Salt Testing Libs
|
||||
from salttesting import TestCase, skipIf
|
||||
from salttesting.mock import (
|
||||
mock_open,
|
||||
MagicMock,
|
||||
patch,
|
||||
NO_MOCK,
|
||||
@ -87,23 +88,27 @@ class BtrfsTestCase(TestCase):
|
||||
ret = [{'range': '/dev/sda1',
|
||||
'mount_point': False,
|
||||
'log': False, 'passed': True}]
|
||||
mock = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertListEqual(btrfs.defragment('/dev/sda1'), ret)
|
||||
mock_run = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}):
|
||||
mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0')
|
||||
with patch.object(salt.utils, 'fopen', mock_file):
|
||||
self.assertListEqual(btrfs.defragment('/dev/sda1'), ret)
|
||||
|
||||
@patch('salt.utils.fsutils._is_device', MagicMock(return_value=True))
|
||||
def test_defragment_error(self):
|
||||
'''
|
||||
Test if it gives device not mount error
|
||||
'''
|
||||
mock = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}):
|
||||
self.assertRaises(CommandExecutionError, btrfs.defragment,
|
||||
'/dev/sda1')
|
||||
mock_run = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}):
|
||||
mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0')
|
||||
with patch.object(salt.utils, 'fopen', mock_file):
|
||||
self.assertRaises(CommandExecutionError, btrfs.defragment,
|
||||
'/dev/sda1')
|
||||
|
||||
# 'features' function tests: 1
|
||||
|
||||
@ -158,13 +163,15 @@ class BtrfsTestCase(TestCase):
|
||||
'''
|
||||
Test if it create a file system on the specified device.
|
||||
'''
|
||||
mock = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
mock_cmd = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
mock_info = MagicMock(return_value=[])
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock,
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_cmd,
|
||||
'btrfs.info': mock_info}):
|
||||
self.assertDictEqual(btrfs.mkfs('/dev/sda1'), {'log': 'Salt'})
|
||||
mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0')
|
||||
with patch.object(salt.utils, 'fopen', mock_file):
|
||||
self.assertDictEqual(btrfs.mkfs('/dev/sda1'), {'log': 'Salt'})
|
||||
|
||||
def test_mkfs_error(self):
|
||||
'''
|
||||
@ -304,14 +311,16 @@ class BtrfsTestCase(TestCase):
|
||||
'''
|
||||
Test if it gives migration error
|
||||
'''
|
||||
mock = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock}):
|
||||
mock = MagicMock(return_value={'/dev/sda1': {'type': 'ext4'}})
|
||||
with patch.object(salt.utils.fsutils, '_blkid_output', mock):
|
||||
self.assertRaises(CommandExecutionError, btrfs.convert,
|
||||
'/dev/sda1')
|
||||
mock_run = MagicMock(return_value={'retcode': 1,
|
||||
'stderr': '',
|
||||
'stdout': 'Salt'})
|
||||
with patch.dict(btrfs.__salt__, {'cmd.run_all': mock_run}):
|
||||
mock_blk = MagicMock(return_value={'/dev/sda1': {'type': 'ext4'}})
|
||||
with patch.object(salt.utils.fsutils, '_blkid_output', mock_blk):
|
||||
mock_file = mock_open(read_data='/dev/sda1 / ext4 rw,data=ordered 0 0')
|
||||
with patch.object(salt.utils, 'fopen', mock_file):
|
||||
self.assertRaises(CommandExecutionError, btrfs.convert,
|
||||
'/dev/sda1')
|
||||
|
||||
# 'add' function tests: 1
|
||||
|
||||
|
@ -97,6 +97,7 @@ class LinuxSysctlTestCase(TestCase):
|
||||
1, config=None)
|
||||
|
||||
@patch('os.path.isfile', MagicMock(return_value=False))
|
||||
@patch('os.path.exists', MagicMock(return_value=True))
|
||||
def test_persist_no_conf_success(self):
|
||||
'''
|
||||
Tests successful add of config file when previously not one
|
||||
@ -120,6 +121,7 @@ class LinuxSysctlTestCase(TestCase):
|
||||
'#\n# Kernel sysctl configuration\n#\n')
|
||||
|
||||
@patch('os.path.isfile', MagicMock(return_value=True))
|
||||
@patch('os.path.exists', MagicMock(return_value=True))
|
||||
def test_persist_read_conf_success(self):
|
||||
'''
|
||||
Tests sysctl.conf read success
|
||||
|
@ -106,12 +106,13 @@ class MountTestCase(TestCase):
|
||||
'''
|
||||
Remove the mount point from the fstab
|
||||
'''
|
||||
mock = MagicMock(return_value={})
|
||||
with patch.object(mount, 'fstab', mock):
|
||||
self.assertTrue(mount.rm_fstab('name', 'device'))
|
||||
mock_fstab = MagicMock(return_value={})
|
||||
with patch.object(mount, 'fstab', mock_fstab):
|
||||
with patch('salt.utils.fopen', mock_open()):
|
||||
self.assertTrue(mount.rm_fstab('name', 'device'))
|
||||
|
||||
mock = MagicMock(return_value={'name': 'name'})
|
||||
with patch.object(mount, 'fstab', mock):
|
||||
mock_fstab = MagicMock(return_value={'name': 'name'})
|
||||
with patch.object(mount, 'fstab', mock_fstab):
|
||||
with patch('salt.utils.fopen', mock_open()) as m_open:
|
||||
helper_open = m_open()
|
||||
helper_open.write.assertRaises(CommandExecutionError,
|
||||
|
@ -13,9 +13,15 @@ from salttesting.mock import MagicMock, patch, call, Mock
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
# Import Salt libs
|
||||
from salt.modules import ps
|
||||
import salt.ext.six as six
|
||||
|
||||
HAS_PSUTIL = ps.__virtual__()
|
||||
ps_virtual = ps.__virtual__()
|
||||
if ps_virtual is True or isinstance(ps_virtual, six.string_types):
|
||||
HAS_PSUTIL = True
|
||||
else:
|
||||
HAS_PSUTIL = False
|
||||
HAS_PSUTIL_VERSION = False
|
||||
|
||||
# Import 3rd-party libs
|
||||
|
@ -63,8 +63,10 @@ class PwGroupTestCase(TestCase):
|
||||
'''
|
||||
Tests for return info on all groups
|
||||
'''
|
||||
mock = MagicMock(return_value={'group.getent': 1})
|
||||
with patch.dict(pw_group.__context__, mock):
|
||||
mock_getent = [{'passwd': 'x',
|
||||
'gid': 0,
|
||||
'name': 'root'}]
|
||||
with patch.dict(pw_group.__context__, {'group.getent': mock_getent}):
|
||||
self.assertDictContainsSubset({'passwd': 'x',
|
||||
'gid': 0,
|
||||
'name': 'root'}, pw_group.getent()[0])
|
||||
|
@ -51,6 +51,7 @@ class GPGTestCase(TestCase):
|
||||
with patch.dict(gpg.__salt__, {'config.get': MagicMock(return_value=False)}):
|
||||
self.assertEqual(gpg._get_key_dir(), def_dir)
|
||||
|
||||
@patch('salt.utils.which', MagicMock())
|
||||
def test__decrypt_ciphertext(self):
|
||||
'''
|
||||
test _decrypt_ciphertext
|
||||
|
@ -7,7 +7,7 @@ import pprint
|
||||
|
||||
# Import Salt Testing libs
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.helpers import destructiveTest, ensure_in_syspath
|
||||
from salttesting.mock import (
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
@ -959,11 +959,12 @@ class FileTestCase(TestCase):
|
||||
|
||||
# 'comment' function tests: 1
|
||||
|
||||
@destructiveTest
|
||||
def test_comment(self):
|
||||
'''
|
||||
Test to comment out specified lines in a file.
|
||||
'''
|
||||
name = '/etc/fstab'
|
||||
name = '/etc/aliases' if salt.utils.is_darwin() else '/etc/fstab'
|
||||
regex = 'bind 127.0.0.1'
|
||||
|
||||
ret = {'name': name,
|
||||
@ -1003,7 +1004,7 @@ class FileTestCase(TestCase):
|
||||
'file.comment_line': mock_t}):
|
||||
with patch.dict(filestate.__opts__, {'test': True}):
|
||||
comt = ('File {0} is set to be updated'.format(name))
|
||||
ret.update({'comment': comt, 'result': None, 'pchanges': {'/etc/fstab': 'updated'}})
|
||||
ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}})
|
||||
self.assertDictEqual(filestate.comment(name, regex), ret)
|
||||
|
||||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
@ -1016,11 +1017,12 @@ class FileTestCase(TestCase):
|
||||
|
||||
# 'uncomment' function tests: 1
|
||||
|
||||
@destructiveTest
|
||||
def test_uncomment(self):
|
||||
'''
|
||||
Test to uncomment specified commented lines in a file
|
||||
'''
|
||||
name = '/etc/fstab'
|
||||
name = '/etc/aliases' if salt.utils.is_darwin() else '/etc/fstab'
|
||||
regex = 'bind 127.0.0.1'
|
||||
|
||||
ret = {'name': name,
|
||||
@ -1058,7 +1060,7 @@ class FileTestCase(TestCase):
|
||||
|
||||
with patch.dict(filestate.__opts__, {'test': True}):
|
||||
comt = ('File {0} is set to be updated'.format(name))
|
||||
ret.update({'comment': comt, 'result': None, 'pchanges': {'/etc/fstab': 'updated'}, })
|
||||
ret.update({'comment': comt, 'result': None, 'pchanges': {name: 'updated'}, })
|
||||
self.assertDictEqual(filestate.uncomment(name, regex), ret)
|
||||
|
||||
with patch.dict(filestate.__opts__, {'test': False}):
|
||||
|
@ -74,6 +74,7 @@ class BaseTCPReqCase(TestCase):
|
||||
del cls.server_channel
|
||||
|
||||
|
||||
@skipIf(salt.utils.is_darwin(), 'hanging test suite on MacOS')
|
||||
class ClearReqTestCases(BaseTCPReqCase, ReqChannelMixin):
|
||||
'''
|
||||
Test all of the clear msg stuff
|
||||
@ -90,6 +91,7 @@ class ClearReqTestCases(BaseTCPReqCase, ReqChannelMixin):
|
||||
raise tornado.gen.Return((payload, {'fun': 'send_clear'}))
|
||||
|
||||
|
||||
@skipIf(salt.utils.is_darwin(), 'hanging test suite on MacOS')
|
||||
class AESReqTestCases(BaseTCPReqCase, ReqChannelMixin):
|
||||
def setUp(self):
|
||||
self.channel = salt.transport.client.ReqChannel.factory(self.minion_opts)
|
||||
|
Loading…
Reference in New Issue
Block a user