Merge branch '2018.3' into '2019.2'

Conflicts:
  - tests/unit/transport/test_ipc.py
This commit is contained in:
Ch3LL 2019-04-12 12:31:57 -04:00
commit 294156743a
No known key found for this signature in database
GPG Key ID: 132B55A7C13EFA73
10 changed files with 161 additions and 111 deletions

View File

@ -119,7 +119,8 @@ def need_deployment():
if dstat.st_uid != euid:
# Attack detected, try again
need_deployment()
if dstat.st_mode != 16832:
# AIX has non-POSIX bit 0o240700, isolate to 0o40700
if dstat.st_mode & ~65536 != 16832:
# Attack detected
need_deployment()
# If SUDOing then also give the super user group write permissions

View File

@ -291,7 +291,12 @@ def list_(narrow=None,
result = __salt__['cmd.run_all'](cmd, python_shell=False)
if result['retcode'] != 0:
# Chocolatey introduced Enhanced Exit Codes starting with version 0.10.12
# Exit Code 2 means there were no results, but is not a failure
# This may start to effect other functions in the future as Chocolatey
# moves more functions to this new paradigm
# https://github.com/chocolatey/choco/issues/1758
if result['retcode'] not in [0, 2]:
raise CommandExecutionError(
'Running chocolatey failed: {0}'.format(result['stdout'])
)

View File

@ -1168,7 +1168,7 @@ def list_repos(**kwargs): # pylint: disable=unused-argument
return repos
def get_repo(alias, **kwargs): # pylint: disable=unused-argument
def get_repo(repo, **kwargs): # pylint: disable=unused-argument
'''
Display a repo from the ``/etc/opkg/*.conf``
@ -1176,19 +1176,19 @@ def get_repo(alias, **kwargs): # pylint: disable=unused-argument
.. code-block:: bash
salt '*' pkg.get_repo alias
salt '*' pkg.get_repo repo
'''
repos = list_repos()
if repos:
for source in six.itervalues(repos):
for sub in source:
if sub['name'] == alias:
if sub['name'] == repo:
return sub
return {}
def _del_repo_from_file(alias, filepath):
def _del_repo_from_file(repo, filepath):
'''
Remove a repo from filepath
'''
@ -1201,30 +1201,30 @@ def _del_repo_from_file(alias, filepath):
if line.startswith('#'):
line = line[1:]
cols = salt.utils.args.shlex_split(line.strip())
if alias != cols[1]:
if repo != cols[1]:
output.append(salt.utils.stringutils.to_str(line))
with salt.utils.files.fopen(filepath, 'w') as fhandle:
fhandle.writelines(output)
def _add_new_repo(alias, uri, compressed, enabled=True):
def _add_new_repo(repo, uri, compressed, enabled=True):
'''
Add a new repo entry
'''
repostr = '# ' if not enabled else ''
repostr += 'src/gz ' if compressed else 'src '
if ' ' in alias:
repostr += '"' + alias + '" '
if ' ' in repo:
repostr += '"' + repo + '" '
else:
repostr += alias + ' '
repostr += repo + ' '
repostr += uri + '\n'
conffile = os.path.join(OPKG_CONFDIR, alias + '.conf')
conffile = os.path.join(OPKG_CONFDIR, repo + '.conf')
with salt.utils.files.fopen(conffile, 'a') as fhandle:
fhandle.write(salt.utils.stringutils.to_str(repostr))
def _mod_repo_in_file(alias, repostr, filepath):
def _mod_repo_in_file(repo, repostr, filepath):
'''
Replace a repo entry in filepath with repostr
'''
@ -1234,7 +1234,7 @@ def _mod_repo_in_file(alias, repostr, filepath):
cols = salt.utils.args.shlex_split(
salt.utils.stringutils.to_unicode(line).strip()
)
if alias not in cols:
if repo not in cols:
output.append(line)
else:
output.append(salt.utils.stringutils.to_str(repostr + '\n'))
@ -1242,7 +1242,7 @@ def _mod_repo_in_file(alias, repostr, filepath):
fhandle.writelines(output)
def del_repo(alias, **kwargs): # pylint: disable=unused-argument
def del_repo(repo, **kwargs): # pylint: disable=unused-argument
'''
Delete a repo from ``/etc/opkg/*.conf``
@ -1253,21 +1253,22 @@ def del_repo(alias, **kwargs): # pylint: disable=unused-argument
.. code-block:: bash
salt '*' pkg.del_repo alias
salt '*' pkg.del_repo repo
'''
refresh = salt.utils.data.is_true(kwargs.get('refresh', True))
repos = list_repos()
if repos:
deleted_from = dict()
for repo in repos:
source = repos[repo][0]
if source['name'] == alias:
for repository in repos:
source = repos[repository][0]
if source['name'] == repo:
deleted_from[source['file']] = 0
_del_repo_from_file(alias, source['file'])
_del_repo_from_file(repo, source['file'])
if deleted_from:
ret = ''
for repo in repos:
source = repos[repo][0]
for repository in repos:
source = repos[repository][0]
if source['file'] in deleted_from:
deleted_from[source['file']] += 1
for repo_file, count in six.iteritems(deleted_from):
@ -1279,22 +1280,22 @@ def del_repo(alias, **kwargs): # pylint: disable=unused-argument
os.remove(repo_file)
except OSError:
pass
ret += msg.format(alias, repo_file)
# explicit refresh after a repo is deleted
refresh_db()
ret += msg.format(repo, repo_file)
if refresh:
refresh_db()
return ret
return "Repo {0} doesn't exist in the opkg repo lists".format(alias)
return "Repo {0} doesn't exist in the opkg repo lists".format(repo)
def mod_repo(alias, **kwargs):
def mod_repo(repo, **kwargs):
'''
Modify one or more values for a repo. If the repo does not exist, it will
be created, so long as uri is defined.
The following options are available to modify a repo definition:
alias
repo
alias by which opkg refers to the repo.
uri
the URI to the repo.
@ -1310,8 +1311,8 @@ def mod_repo(alias, **kwargs):
.. code-block:: bash
salt '*' pkg.mod_repo alias uri=http://new/uri
salt '*' pkg.mod_repo alias enabled=False
salt '*' pkg.mod_repo repo uri=http://new/uri
salt '*' pkg.mod_repo repo enabled=False
'''
repos = list_repos()
found = False
@ -1319,9 +1320,9 @@ def mod_repo(alias, **kwargs):
if 'uri' in kwargs:
uri = kwargs['uri']
for repo in repos:
source = repos[repo][0]
if source['name'] == alias:
for repository in repos:
source = repos[repository][0]
if source['name'] == repo:
found = True
repostr = ''
if 'enabled' in kwargs and not kwargs['enabled']:
@ -1330,13 +1331,13 @@ def mod_repo(alias, **kwargs):
repostr += 'src/gz ' if kwargs['compressed'] else 'src'
else:
repostr += 'src/gz' if source['compressed'] else 'src'
repo_alias = kwargs['alias'] if 'alias' in kwargs else alias
repo_alias = kwargs['alias'] if 'alias' in kwargs else repo
if ' ' in repo_alias:
repostr += ' "{0}"'.format(repo_alias)
else:
repostr += ' {0}'.format(repo_alias)
repostr += ' {0}'.format(kwargs['uri'] if 'uri' in kwargs else source['uri'])
_mod_repo_in_file(alias, repostr, source['file'])
_mod_repo_in_file(repo, repostr, source['file'])
elif uri and source['uri'] == uri:
raise CommandExecutionError(
'Repository \'{0}\' already exists as \'{1}\'.'.format(uri, source['name']))
@ -1345,12 +1346,12 @@ def mod_repo(alias, **kwargs):
# Need to add a new repo
if 'uri' not in kwargs:
raise CommandExecutionError(
'Repository \'{0}\' not found and no URI passed to create one.'.format(alias))
'Repository \'{0}\' not found and no URI passed to create one.'.format(repo))
# If compressed is not defined, assume True
compressed = kwargs['compressed'] if 'compressed' in kwargs else True
# If enabled is not defined, assume True
enabled = kwargs['enabled'] if 'enabled' in kwargs else True
_add_new_repo(alias, kwargs['uri'], compressed, enabled)
_add_new_repo(repo, kwargs['uri'], compressed, enabled)
if 'refresh' in kwargs:
refresh_db()

View File

@ -205,22 +205,23 @@ def get_zone():
Returns:
str: Timezone in unix format
Raises:
CommandExecutionError: If timezone could not be gathered
CLI Example:
.. code-block:: bash
salt '*' timezone.get_zone
'''
cmd = ['tzutil', '/g']
res = __salt__['cmd.run_all'](cmd, python_shell=False)
if res['retcode'] or not res['stdout']:
raise CommandExecutionError('tzutil encountered an error getting '
'timezone',
info=res)
return mapper.get_unix(res['stdout'].lower(), 'Unknown')
win_zone = __utils__['reg.read_value'](
hive='HKLM',
key='SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation',
vname='TimeZoneKeyName')['vdata']
# Some data may have null characters. We only need the first portion up to
# the first null character. See the following:
# https://github.com/saltstack/salt/issues/51940
# https://stackoverflow.com/questions/27716746/hklm-system-currentcontrolset-control-timezoneinformation-timezonekeyname-corrup
if '\0' in win_zone:
win_zone = win_zone.split('\0')[0]
return mapper.get_unix(win_zone.lower(), 'Unknown')
def get_offset():

View File

@ -777,6 +777,11 @@ def extracted(name,
ret['comment'] = exc.strerror
return ret
if not source_match:
ret['result'] = False
ret['comment'] = 'Invalid source "{0}"'.format(source)
return ret
urlparsed_source = _urlparse(source_match)
urlparsed_scheme = urlparsed_source.scheme
urlparsed_path = os.path.join(

View File

@ -316,9 +316,8 @@ class IPCClient(object):
if self.stream is None:
with salt.utils.asynchronous.current_ioloop(self.io_loop):
self.stream = IOStream(
socket.socket(sock_type, socket.SOCK_STREAM),
socket.socket(sock_type, socket.SOCK_STREAM)
)
try:
log.trace('IPCClient: Connecting to socket: %s', self.socket_path)
yield self.stream.connect(sock_addr)

View File

@ -1611,11 +1611,19 @@ class Pygit2(GitProvider):
'''
Clean stale local refs so they don't appear as fileserver environments
'''
try:
if pygit2.GIT_FETCH_PRUNE:
# Don't need to clean anything, pygit2 can do it by itself
return []
except AttributeError:
# However, only in 0.26.2 and newer
pass
if self.credentials is not None:
log.debug(
'pygit2 does not support detecting stale refs for '
'authenticated remotes, saltenvs will not reflect '
'branches/tags removed from remote \'%s\'', self.id
'The installed version of pygit2 (%s) does not support '
'detecting stale refs for authenticated remotes, saltenvs '
'will not reflect branches/tags removed from remote \'%s\'',
PYGIT2_VERSION, self.id
)
return []
return super(Pygit2, self).clean_stale_refs()
@ -1721,6 +1729,11 @@ class Pygit2(GitProvider):
else:
if self.credentials is not None:
origin.credentials = self.credentials
try:
fetch_kwargs['prune'] = pygit2.GIT_FETCH_PRUNE
except AttributeError:
# pruning only available in pygit2 >= 0.26.2
pass
try:
fetch_results = origin.fetch(**fetch_kwargs)
except GitError as exc:
@ -2573,7 +2586,8 @@ class GitBase(object):
LIBGIT2_VERSION
)
)
if not salt.utils.path.which('git'):
if not getattr(pygit2, 'GIT_FETCH_PRUNE', False) \
and not salt.utils.path.which('git'):
errors.append(
'The git command line utility is required when using the '
'\'pygit2\' {0}_provider.'.format(self.role)

View File

@ -45,6 +45,14 @@ def _load_libcrypto():
# two checks below
lib = glob.glob('/opt/local/lib/libcrypto.so*') + glob.glob('/opt/tools/lib/libcrypto.so*')
lib = lib[0] if len(lib) > 0 else None
if not lib and salt.utils.platform.is_aix():
if os.path.isdir('/opt/salt/lib'):
# preference for Salt installed fileset
lib = glob.glob('/opt/salt/lib/libcrypto.so*')
lib = lib[0] if len(lib) > 0 else None
else:
lib = glob.glob('/opt/freeware/lib/libcrypto.so*')
lib = lib[0] if len(lib) > 0 else None
if lib:
return cdll.LoadLibrary(lib)
raise OSError('Cannot locate OpenSSL libcrypto')

View File

@ -111,35 +111,72 @@ class MineTest(ModuleCase):
['grains.items']
)
)
# Smoke testing that grains should now exist in the mine
ret_grains = self.run_function(
'mine.get',
['minion', 'grains.items']
)
self.assertEqual(ret_grains['minion']['id'], 'minion')
self.assertTrue(
self.run_function(
'mine.send',
['test.arg', 'foo=bar', 'fnord=roscivs'],
)
)
ret_args = self.run_function(
'mine.get',
['minion', 'test.arg']
)
expected = {
'minion': {
'args': [],
'kwargs': {
'fnord': 'roscivs',
'foo': 'bar',
},
},
}
# Smoke testing that test.arg exists in the mine
self.assertDictEqual(ret_args, expected)
self.assertTrue(
self.run_function(
'mine.send',
['test.echo', 'foo']
)
)
ret_grains = self.run_function(
'mine.get',
['minion', 'grains.items']
)
self.assertEqual(ret_grains['minion']['id'], 'minion')
ret_echo = self.run_function(
'mine.get',
['minion', 'test.echo']
)
# Smoke testing that we were also able to set test.echo in the mine
self.assertEqual(ret_echo['minion'], 'foo')
self.assertTrue(
self.run_function(
'mine.delete',
['grains.items']
['test.arg']
)
)
ret_grains_deleted = self.run_function(
ret_arg_deleted = self.run_function(
'mine.get',
['minion', 'grains.items']
['minion', 'test.arg']
)
# Now comes the real test - did we obliterate test.arg from the mine?
# We could assert this a different way, but there shouldn't be any
# other tests that are setting this mine value, so this should
# definitely avoid any race conditions.
self.assertFalse(
ret_arg_deleted.get('minion', {})
.get('kwargs', {})
.get('fnord', None) == 'roscivs',
'{} contained "fnord":"roscivs", which should be gone'.format(
ret_arg_deleted,
)
)
self.assertEqual(ret_grains_deleted.get('minion', None), None)
ret_echo_stays = self.run_function(
'mine.get',
['minion', 'test.echo']
)
# Of course, one more health check - we want targeted removal.
# This isn't horseshoes or hand grenades - test.arg should go away
# but test.echo should still be available.
self.assertEqual(ret_echo_stays['minion'], 'foo')

View File

@ -7,7 +7,7 @@ from __future__ import absolute_import, print_function, unicode_literals
# Import Salt Libs
import salt.modules.win_timezone as win_timezone
from salt.exceptions import CommandExecutionError
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import MagicMock, patch
@ -26,31 +26,26 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
def test_get_zone(self):
'''
Test if it get current timezone (i.e. Asia/Calcutta)
Test if it gets current timezone (i.e. Asia/Calcutta)
'''
mock_read_ok = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_read = MagicMock(side_effect=[{'vdata': 'India Standard Time'},
{'vdata': 'Indian Standard Time'}])
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_ok}):
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertEqual(win_timezone.get_zone(), 'Asia/Calcutta')
mock_read_error = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'Indian Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_error}):
self.assertEqual(win_timezone.get_zone(), 'Unknown')
mock_read_fatal = MagicMock(return_value={'pid': 78,
'retcode': 1,
'stderr': '',
'stdout': ''})
def test_get_zone_null_terminated(self):
'''
Test if it handles instances where the registry contains null values
'''
mock_read = MagicMock(side_effect=[
{'vdata': 'India Standard Time\0\0\0\0'},
{'vdata': 'Indian Standard Time\0\0some more junk data\0\0'}])
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read_fatal}):
self.assertRaises(CommandExecutionError, win_timezone.get_zone)
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertEqual(win_timezone.get_zone(), 'Asia/Calcutta')
self.assertEqual(win_timezone.get_zone(), 'Unknown')
# 'get_offset' function tests: 1
@ -58,16 +53,9 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
'''
Test if it get current numeric timezone offset from UCT (i.e. +0530)
'''
# time = ('(UTC+05:30) Chennai, Kolkata, Mumbai, \
# New Delhi\nIndia Standard Time')
# mock_cmd = MagicMock(side_effect=['India Standard Time', time])
# with patch.dict(win_timezone.__salt__, {'cmd.run': mock_cmd}):
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertEqual(win_timezone.get_offset(), '+0530')
# 'get_zonecode' function tests: 1
@ -76,12 +64,9 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
'''
Test if it get current timezone (i.e. PST, MDT, etc)
'''
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertEqual(win_timezone.get_zonecode(), 'IST')
# 'set_zone' function tests: 1
@ -90,17 +75,14 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
'''
Test if it unlinks, then symlinks /etc/localtime to the set timezone.
'''
mock_write = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': ''})
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_cmd = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': ''})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_write}), \
patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_cmd}), \
patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertTrue(win_timezone.set_zone('Asia/Calcutta'))
@ -112,12 +94,9 @@ class WinTimezoneTestCase(TestCase, LoaderModuleMockMixin):
the one set in /etc/localtime. Returns True if they match,
and False if not. Mostly useful for running state checks.
'''
mock_read = MagicMock(return_value={'pid': 78,
'retcode': 0,
'stderr': '',
'stdout': 'India Standard Time'})
mock_read = MagicMock(return_value={'vdata': 'India Standard Time'})
with patch.dict(win_timezone.__salt__, {'cmd.run_all': mock_read}):
with patch.dict(win_timezone.__utils__, {'reg.read_value': mock_read}):
self.assertTrue(win_timezone.zone_compare('Asia/Calcutta'))
# 'get_hwclock' function tests: 1