mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge branch '2017.7' into '2018.3'
Conflicts: - salt/ext/win_inet_pton.py - salt/pillar/git_pillar.py - tests/integration/cli/test_batch.py - tests/integration/modules/test_archive.py - tests/integration/modules/test_pkg.py - tests/integration/states/test_file.py - tests/support/case.py - tests/whitelist.txt
This commit is contained in:
commit
ac406c49a7
12 changed files with 164 additions and 91 deletions
|
@ -1242,6 +1242,7 @@ class Minion(MinionBase):
|
|||
'minutes': self.opts['mine_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2,
|
||||
'run_on_start': True,
|
||||
'return_job': self.opts.get('mine_return_job', False)
|
||||
}
|
||||
}, persist=True)
|
||||
|
@ -3626,6 +3627,7 @@ class ProxyMinion(Minion):
|
|||
'minutes': self.opts['mine_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2,
|
||||
'run_on_start': True,
|
||||
'return_job': self.opts.get('mine_return_job', False)
|
||||
}
|
||||
}, persist=True)
|
||||
|
|
|
@ -144,7 +144,7 @@ The corresponding Pillar top file would look like this:
|
|||
|
||||
.. code-block:: yaml
|
||||
|
||||
{{saltenv}}:
|
||||
"{{saltenv}}":
|
||||
'*':
|
||||
- bar
|
||||
|
||||
|
|
|
@ -37,13 +37,25 @@ def grains(tgt=None, tgt_type='glob', **kwargs):
|
|||
The ``expr_form`` argument has been renamed to ``tgt_type``, earlier
|
||||
releases must use ``expr_form``.
|
||||
|
||||
Return cached grains of the targeted minions
|
||||
Return cached grains of the targeted minions.
|
||||
|
||||
tgt
|
||||
Target to match minion ids.
|
||||
|
||||
.. versionchanged:: 2017.7.5,2018.3.0
|
||||
The ``tgt`` argument is now required to display cached grains. If
|
||||
not used, the function will not return grains. This optional
|
||||
argument will become mandatory in the Salt ``Sodium`` release.
|
||||
|
||||
tgt_type
|
||||
The type of targeting to use for matching, such as ``glob``, ``list``,
|
||||
etc.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt-run cache.grains
|
||||
salt-run cache.grains '*'
|
||||
'''
|
||||
if 'expr_form' in kwargs:
|
||||
salt.utils.versions.warn_until(
|
||||
|
@ -54,6 +66,16 @@ def grains(tgt=None, tgt_type='glob', **kwargs):
|
|||
)
|
||||
tgt_type = kwargs.pop('expr_form')
|
||||
|
||||
if tgt is None:
|
||||
# Change ``tgt=None`` to ``tgt`` (mandatory kwarg) in Salt Sodium.
|
||||
# This behavior was changed in PR #45588 to fix Issue #45489.
|
||||
salt.utils.warn_until(
|
||||
'Sodium',
|
||||
'Detected missing \'tgt\' option. Cached grains will not be returned '
|
||||
'without a specified \'tgt\'. This option will be required starting in '
|
||||
'Salt Sodium and this warning will be removed.'
|
||||
)
|
||||
|
||||
pillar_util = salt.utils.master.MasterPillarUtil(tgt, tgt_type,
|
||||
use_cached_grains=True,
|
||||
grains_fallback=False,
|
||||
|
|
|
@ -591,10 +591,19 @@ class LogLevelMixIn(six.with_metaclass(MixInMeta, object)):
|
|||
)
|
||||
)
|
||||
|
||||
def _logfile_callback(option, opt, value, parser, *args, **kwargs):
|
||||
if not os.path.dirname(value):
|
||||
# if the path is only a file name (no parent directory), assume current directory
|
||||
value = os.path.join(os.path.curdir, value)
|
||||
setattr(parser.values, self._logfile_config_setting_name_, value)
|
||||
|
||||
group.add_option(
|
||||
'--log-file',
|
||||
dest=self._logfile_config_setting_name_,
|
||||
default=None,
|
||||
action='callback',
|
||||
type='string',
|
||||
callback=_logfile_callback,
|
||||
help='Log file path. Default: \'{0}\'.'.format(
|
||||
self._default_logging_logfile_
|
||||
)
|
||||
|
|
|
@ -40,17 +40,17 @@ class GrainsTargetingTest(ShellCase):
|
|||
if item != 'minion:':
|
||||
os_grain = item.strip()
|
||||
|
||||
ret = self.run_salt('-G \'os:{0}\' test.ping'.format(os_grain))
|
||||
ret = self.run_salt('-G "os:{0}" test.ping'.format(os_grain))
|
||||
self.assertEqual(sorted(ret), sorted(test_ret))
|
||||
|
||||
def test_grains_targeting_minion_id_running(self):
|
||||
'''
|
||||
Tests return of each running test minion targeting with minion id grain
|
||||
'''
|
||||
minion = self.run_salt('-G \'id:minion\' test.ping')
|
||||
minion = self.run_salt('-G "id:minion" test.ping')
|
||||
self.assertEqual(sorted(minion), sorted(['minion:', ' True']))
|
||||
|
||||
sub_minion = self.run_salt('-G \'id:sub_minion\' test.ping')
|
||||
sub_minion = self.run_salt('-G "id:sub_minion" test.ping')
|
||||
self.assertEqual(sorted(sub_minion), sorted(['sub_minion:', ' True']))
|
||||
|
||||
@flaky
|
||||
|
@ -71,7 +71,7 @@ class GrainsTargetingTest(ShellCase):
|
|||
# ping disconnected minion and ensure it times out and returns with correct message
|
||||
try:
|
||||
ret = ''
|
||||
for item in self.run_salt('-t 1 -G \'id:disconnected\' test.ping', timeout=40):
|
||||
for item in self.run_salt('-t 1 -G "id:disconnected" test.ping', timeout=40):
|
||||
if item != 'disconnected:':
|
||||
ret = item.strip()
|
||||
assert ret == test_ret
|
||||
|
|
|
@ -53,12 +53,12 @@ class ArchiveTest(ModuleCase):
|
|||
|
||||
:param str arch_fmt: The archive format used in the test
|
||||
'''
|
||||
# Setup artifact paths
|
||||
self._set_artifact_paths(arch_fmt)
|
||||
|
||||
# Remove the artifacts if any present
|
||||
if any([os.path.exists(f) for f in (self.src, self.arch, self.dst)]):
|
||||
self._tear_down()
|
||||
self._set_artifact_paths(arch_fmt)
|
||||
|
||||
# Create source
|
||||
os.makedirs(self.src)
|
||||
|
@ -104,19 +104,32 @@ class ArchiveTest(ModuleCase):
|
|||
del self.arch
|
||||
del self.src_file
|
||||
|
||||
def _assert_artifacts_in_ret(self, ret, file_only=False):
|
||||
def _assert_artifacts_in_ret(self, ret, file_only=False, unix_sep=False):
|
||||
'''
|
||||
Assert that the artifact source files are printed in the source command
|
||||
output
|
||||
'''
|
||||
|
||||
def normdir(path):
|
||||
normdir = os.path.normcase(os.path.abspath(path))
|
||||
if salt.utils.is_windows():
|
||||
# Remove the drive portion of path
|
||||
if len(normdir) >= 2 and normdir[1] == ':':
|
||||
normdir = normdir.split(':', 1)[1]
|
||||
normdir = normdir.lstrip(os.path.sep)
|
||||
# Unzipped paths might have unix line endings
|
||||
if unix_sep:
|
||||
normdir = normdir.replace(os.path.sep, '/')
|
||||
return normdir
|
||||
|
||||
# Try to find source directory and file in output lines
|
||||
dir_in_ret = None
|
||||
file_in_ret = None
|
||||
for line in ret:
|
||||
if self.src.lstrip('/') in line \
|
||||
and not self.src_file.lstrip('/') in line:
|
||||
if normdir(self.src) in line \
|
||||
and not normdir(self.src_file) in line:
|
||||
dir_in_ret = True
|
||||
if self.src_file.lstrip('/') in line:
|
||||
if normdir(self.src_file) in line:
|
||||
file_in_ret = True
|
||||
|
||||
# Assert number of lines, reporting of source directory and file
|
||||
|
@ -283,7 +296,7 @@ class ArchiveTest(ModuleCase):
|
|||
# Test create archive
|
||||
ret = self.run_function('archive.unzip', [self.arch, self.dst])
|
||||
self.assertTrue(isinstance(ret, list), six.text_type(ret))
|
||||
self._assert_artifacts_in_ret(ret)
|
||||
self._assert_artifacts_in_ret(ret, unix_sep=True if six.PY2 else False)
|
||||
|
||||
self._tear_down()
|
||||
|
||||
|
|
|
@ -316,6 +316,7 @@ class MatchTest(ShellCase, ShellCaseCommonTestsMixin):
|
|||
data = '\n'.join(data)
|
||||
self.assertIn('minion', data)
|
||||
|
||||
@flaky
|
||||
def test_salt_documentation(self):
|
||||
'''
|
||||
Test to see if we're supporting --doc
|
||||
|
|
|
@ -30,7 +30,8 @@ from tests.support.helpers import (
|
|||
with_tempdir,
|
||||
with_tempfile,
|
||||
Webserver,
|
||||
destructiveTest
|
||||
destructiveTest,
|
||||
dedent,
|
||||
)
|
||||
from tests.support.mixins import SaltReturnAssertsMixin
|
||||
|
||||
|
@ -2531,64 +2532,57 @@ class FileTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
class BlockreplaceTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
marker_start = '# start'
|
||||
marker_end = '# end'
|
||||
content = six.text_type(os.linesep.join([
|
||||
'Line 1 of block',
|
||||
'Line 2 of block',
|
||||
''
|
||||
]))
|
||||
without_block = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
with_non_matching_block = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# start',
|
||||
'No match here',
|
||||
'# end',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
with_non_matching_block_and_marker_end_not_after_newline = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# start',
|
||||
'No match here# end',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
with_matching_block = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# start',
|
||||
'Line 1 of block',
|
||||
'Line 2 of block',
|
||||
'# end',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
with_matching_block_and_extra_newline = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# start',
|
||||
'Line 1 of block',
|
||||
'Line 2 of block',
|
||||
'',
|
||||
'# end',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
with_matching_block_and_marker_end_not_after_newline = six.text_type(os.linesep.join([
|
||||
'Hello world!',
|
||||
'',
|
||||
'# start',
|
||||
'Line 1 of block',
|
||||
'Line 2 of block# end',
|
||||
'# comment here',
|
||||
''
|
||||
]))
|
||||
content = dedent(six.text_type('''\
|
||||
Line 1 of block
|
||||
Line 2 of block
|
||||
'''))
|
||||
without_block = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# comment here
|
||||
'''))
|
||||
with_non_matching_block = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# start
|
||||
No match here
|
||||
# end
|
||||
# comment here
|
||||
'''))
|
||||
with_non_matching_block_and_marker_end_not_after_newline = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# start
|
||||
No match here# end
|
||||
# comment here
|
||||
'''))
|
||||
with_matching_block = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# start
|
||||
Line 1 of block
|
||||
Line 2 of block
|
||||
# end
|
||||
# comment here
|
||||
'''))
|
||||
with_matching_block_and_extra_newline = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# start
|
||||
Line 1 of block
|
||||
Line 2 of block
|
||||
|
||||
# end
|
||||
# comment here
|
||||
'''))
|
||||
with_matching_block_and_marker_end_not_after_newline = dedent(six.text_type('''\
|
||||
Hello world!
|
||||
|
||||
# start
|
||||
Line 1 of block
|
||||
Line 2 of block# end
|
||||
# comment here
|
||||
'''))
|
||||
content_explicit_posix_newlines = ('Line 1 of block\n'
|
||||
'Line 2 of block\n')
|
||||
content_explicit_windows_newlines = ('Line 1 of block\r\n'
|
||||
|
|
|
@ -260,25 +260,26 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
or not logged. If it is None, then the return code of the subprocess
|
||||
determines whether or not to log results.
|
||||
'''
|
||||
|
||||
import salt.utils
|
||||
|
||||
script_path = self.get_script_path(script)
|
||||
if not os.path.isfile(script_path):
|
||||
return False
|
||||
|
||||
python_path = os.environ.get('PYTHONPATH', None)
|
||||
|
||||
if sys.platform.startswith('win'):
|
||||
cmd = 'set PYTHONPATH='
|
||||
if salt.utils.is_windows():
|
||||
cmd = 'python '
|
||||
else:
|
||||
cmd = 'PYTHONPATH='
|
||||
python_path = os.environ.get('PYTHONPATH', None)
|
||||
if python_path is not None:
|
||||
cmd += '{0}:'.format(python_path)
|
||||
|
||||
if python_path is not None:
|
||||
cmd += '{0}:'.format(python_path)
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
cmd += '{0} '.format(':'.join(sys.path[1:]))
|
||||
else:
|
||||
cmd += '{0} '.format(':'.join(sys.path[0:]))
|
||||
cmd += 'python{0}.{1} '.format(*sys.version_info)
|
||||
if sys.version_info[0] < 3:
|
||||
cmd += '{0} '.format(':'.join(sys.path[1:]))
|
||||
else:
|
||||
cmd += '{0} '.format(':'.join(sys.path[0:]))
|
||||
cmd += 'python{0}.{1} '.format(*sys.version_info)
|
||||
cmd += '{0} '.format(script_path)
|
||||
cmd += '{0} '.format(arg_str)
|
||||
|
||||
|
@ -287,7 +288,7 @@ class ShellTestCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
|||
popen_kwargs = {
|
||||
'shell': True,
|
||||
'stdout': tmp_file,
|
||||
'universal_newlines': True
|
||||
'universal_newlines': True,
|
||||
}
|
||||
|
||||
if catch_stderr is True:
|
||||
|
|
|
@ -27,6 +27,7 @@ import string
|
|||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import textwrap
|
||||
import threading
|
||||
import time
|
||||
import tornado.ioloop
|
||||
|
@ -206,7 +207,7 @@ def flaky(caller=None, condition=True):
|
|||
try:
|
||||
return caller(cls)
|
||||
except Exception as exc:
|
||||
if attempt == 4:
|
||||
if attempt >= 3:
|
||||
raise exc
|
||||
backoff_time = attempt ** 2
|
||||
log.info('Found Exception. Waiting %s seconds to retry.', backoff_time)
|
||||
|
@ -1607,3 +1608,17 @@ def this_user():
|
|||
if salt.utils.platform.is_windows():
|
||||
return salt.utils.win_functions.get_current_user(with_domain=False)
|
||||
return pwd.getpwuid(os.getuid())[0]
|
||||
|
||||
|
||||
def dedent(text, linesep=os.linesep):
|
||||
'''
|
||||
A wrapper around textwrap.dedent that also sets line endings.
|
||||
'''
|
||||
linesep = salt.utils.to_unicode(linesep)
|
||||
unicode_text = textwrap.dedent(salt.utils.to_unicode(text))
|
||||
clean_text = linesep.join(unicode_text.splitlines())
|
||||
if unicode_text.endswith(u'\n'):
|
||||
clean_text += linesep
|
||||
if not isinstance(text, six.text_type):
|
||||
return salt.utils.to_bytes(clean_text)
|
||||
return clean_text
|
||||
|
|
|
@ -139,13 +139,17 @@ class WinServiceTestCase(TestCase, LoaderModuleMockMixin):
|
|||
'''
|
||||
mock_true = MagicMock(return_value=True)
|
||||
mock_false = MagicMock(return_value=False)
|
||||
mock_info = MagicMock(side_effect=[{'Status': 'Running'},
|
||||
{'Status': 'Stop Pending'},
|
||||
{'Status': 'Stopped'}])
|
||||
mock_info = MagicMock(side_effect=[{'Status': 'Stopped'}])
|
||||
|
||||
with patch.dict(win_service.__salt__, {'cmd.run': MagicMock(return_value="service was stopped")}):
|
||||
with patch.dict(win_service.__salt__, {'cmd.run': MagicMock(return_value="service was stopped")}), \
|
||||
patch.object(win32serviceutil, 'StopService', mock_true), \
|
||||
patch.object(win_service, '_status_wait', mock_info):
|
||||
self.assertTrue(win_service.stop('spongebob'))
|
||||
|
||||
mock_info = MagicMock(side_effect=[{'Status': 'Running', 'Status_WaitHint': 0},
|
||||
{'Status': 'Stop Pending', 'Status_WaitHint': 0},
|
||||
{'Status': 'Stopped'}])
|
||||
|
||||
with patch.dict(win_service.__salt__, {'cmd.run': MagicMock(return_value="service was stopped")}), \
|
||||
patch.object(win32serviceutil, 'StopService', mock_true), \
|
||||
patch.object(win_service, 'info', mock_info), \
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
integration.cli.test_batch
|
||||
integration.cli.test_custom_module
|
||||
integration.cli.test_grains
|
||||
integration.client.test_kwarg
|
||||
integration.client.test_runner
|
||||
integration.client.test_standard
|
||||
integration.client.test_syndic
|
||||
integration.doc.test_man
|
||||
integration.grains.test_core
|
||||
integration.loader.test_ext_grains
|
||||
integration.loader.test_ext_modules
|
||||
integration.logging.test_jid_logging
|
||||
integration.minion.test_blackout
|
||||
integration.minion.test_pillar
|
||||
integration.minion.test_timeout
|
||||
integration.modules.test_aliases
|
||||
integration.modules.test_win_autoruns
|
||||
integration.modules.test_archive
|
||||
integration.modules.test_beacons
|
||||
integration.modules.test_cmdmod
|
||||
integration.modules.test_config
|
||||
integration.modules.test_cp
|
||||
integration.modules.test_cmdmod
|
||||
integration.modules.test_data
|
||||
integration.modules.test_disk
|
||||
integration.modules.test_win_firewall
|
||||
|
@ -30,6 +41,7 @@ integration.modules.test_sysmod
|
|||
integration.modules.test_system
|
||||
integration.modules.test_test
|
||||
integration.modules.test_useradd
|
||||
integration.modules.test_win_autoruns
|
||||
integration.modules.test_win_dns_client
|
||||
integration.modules.test_win_pkg
|
||||
integration.reactor.test_reactor
|
||||
|
|
Loading…
Add table
Reference in a new issue