Merge pull request #44153 from rallytime/merge-develop

[develop] Merge forward from 2017.7 to develop
This commit is contained in:
Mike Place 2017-10-18 10:51:14 -06:00 committed by GitHub
commit 990a454f99
10 changed files with 76 additions and 59 deletions

View File

@ -6,7 +6,7 @@ Introduced in Salt version ``2017.7.0`` it is now possible to run select states
in parallel. This is accomplished very easily by adding the ``parallel: True``
option to your state declaration:
.. code_block:: yaml
.. code-block:: yaml
nginx:
service.running:
@ -24,7 +24,7 @@ state to finish.
Given this example:
.. code_block:: yaml
.. code-block:: yaml
sleep 10:
cmd.run:
@ -74,16 +74,16 @@ also complete.
Things to be Careful of
=======================
Parallel States does not prevent you from creating parallel conflicts on your
Parallel States do not prevent you from creating parallel conflicts on your
system. This means that if you start multiple package installs using Salt then
the package manager will block or fail. If you attempt to manage the same file
with multiple states in parallel then the result can produce an unexpected
file.
Make sure that the states you choose to run in parallel do not conflict, or
else, like in and parallel programming environment, the outcome may not be
else, like in any parallel programming environment, the outcome may not be
what you expect. Doing things like just making all states run in parallel
will almost certinly result in unexpected behavior.
will almost certainly result in unexpected behavior.
With that said, running states in parallel should be safe the vast majority
of the time and the most likely culprit for unexpected behavior is running

View File

@ -14,23 +14,33 @@ CVE-2017-14695 Directory traversal vulnerability in minion id validation in Salt
CVE-2017-14696 Remote Denial of Service with a specially crafted authentication request. Credit for discovering the security flaw goes to: Julian Brost (julian@0x4a42.net)
Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs):
Known Issues
============
On 2017.7.2 when using salt-api and cherrypy version 5.6.0, issue `#43581`_ will occur when starting the salt-api service. We have patched the cherry-py packages for python-cherrypy-5.6.0-2 from repo.saltstack.com. If you are using python-cherrypy-5.6.0-1 please ensure to run `yum install python-cherrypy` to install the new patched version.
*Generated at: 2017-09-26T21:06:19Z*
Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs):
Statistics:
*Generated at: 2017-10-02T21:10:14Z*
- Total Merges: **326**
- Total Issue references: **133**
- Total PR references: **389**
Statistics
==========
Changes:
- Total Merges: **328**
- Total Issue references: **134**
- Total PR references: **391**
Changes
=======
- **PR** `#43868`_: (*rallytime*) Back-port `#43847`_ to 2017.7.2
* Fix to module.run
- **PR** `#43756`_: (*gtmanfred*) split build and install for pkg osx
@ *2017-09-26T20:51:28Z*
* 88414d5 Merge pull request `#43756`_ from gtmanfred/2017.7.2
* f7df41f split build and install for pkg osx
- **PR** `#43585`_: (*rallytime*) Back-port `#43330`_ to 2017.7.2
@ *2017-09-19T17:33:34Z*
@ -3110,6 +3120,12 @@ Changes:
.. _`#480`: https://github.com/saltstack/salt/issues/480
.. _`#495`: https://github.com/saltstack/salt/issues/495
.. _`#43581`: https://github.com/saltstack/salt/issues/43581
.. _`#43756`: https://github.com/saltstack/salt/pull/43756
.. _`#43847`: https://github.com/saltstack/salt/pull/43847
.. _`#43868`: https://github.com/saltstack/salt/pull/43868
.. _`#475`: https://github.com/saltstack/salt/issues/475
.. _`#480`: https://github.com/saltstack/salt/issues/480
.. _`#495`: https://github.com/saltstack/salt/issues/495
.. _`bp-37424`: https://github.com/saltstack/salt/pull/37424
.. _`bp-39366`: https://github.com/saltstack/salt/pull/39366
.. _`bp-41543`: https://github.com/saltstack/salt/pull/41543

View File

@ -27,7 +27,7 @@ Installing Dependencies
=======================
Both pygit2_ and GitPython_ are supported Python interfaces to git. If
compatible versions of both are installed, pygit2_ will preferred. In these
compatible versions of both are installed, pygit2_ will be preferred. In these
cases, GitPython_ can be forced using the :conf_master:`gitfs_provider`
parameter in the master config file.

View File

@ -88,7 +88,8 @@ sudo $PKGRESOURCES/build_env.sh $PYVER
echo -n -e "\033]0;Build: Install Salt\007"
sudo rm -rf $SRCDIR/build
sudo rm -rf $SRCDIR/dist
sudo $PYTHON $SRCDIR/setup.py build -e "$PYTHON -E -s" install
sudo $PYTHON $SRCDIR/setup.py build -e "$PYTHON -E -s"
sudo $PYTHON $SRCDIR/setup.py install
############################################################################
# Build Package

View File

@ -132,7 +132,7 @@ def version(*names, **kwargs):
return __salt__['pkg_resource.version'](*names, **kwargs)
def refresh_db(failhard=False):
def refresh_db(failhard=False, **kwargs): # pylint: disable=unused-argument
'''
Updates the opkg database to latest packages based upon repositories
@ -514,7 +514,7 @@ def purge(name=None, pkgs=None, **kwargs): # pylint: disable=unused-argument
return remove(name=name, pkgs=pkgs)
def upgrade(refresh=True):
def upgrade(refresh=True, **kwargs): # pylint: disable=unused-argument
'''
Upgrades all packages via ``opkg upgrade``
@ -803,7 +803,7 @@ def list_pkgs(versions_as_list=False, **kwargs):
return ret
def list_upgrades(refresh=True):
def list_upgrades(refresh=True, **kwargs): # pylint: disable=unused-argument
'''
List all available package upgrades.
@ -976,7 +976,7 @@ def info_installed(*names, **kwargs):
return ret
def upgrade_available(name):
def upgrade_available(name, **kwargs): # pylint: disable=unused-argument
'''
Check whether or not an upgrade is available for a given package
@ -989,7 +989,7 @@ def upgrade_available(name):
return latest_version(name) != ''
def version_cmp(pkg1, pkg2, ignore_epoch=False):
def version_cmp(pkg1, pkg2, ignore_epoch=False, **kwargs): # pylint: disable=unused-argument
'''
Do a cmp-style comparison on two packages. Return -1 if pkg1 < pkg2, 0 if
pkg1 == pkg2, and 1 if pkg1 > pkg2. Return None if there was a problem
@ -1038,7 +1038,7 @@ def version_cmp(pkg1, pkg2, ignore_epoch=False):
return None
def list_repos():
def list_repos(**kwargs): # pylint: disable=unused-argument
'''
Lists all repos on /etc/opkg/*.conf
@ -1075,7 +1075,7 @@ def list_repos():
return repos
def get_repo(alias):
def get_repo(alias, **kwargs): # pylint: disable=unused-argument
'''
Display a repo from the /etc/opkg/*.conf
@ -1146,7 +1146,7 @@ def _mod_repo_in_file(alias, repostr, filepath):
fhandle.writelines(output)
def del_repo(alias):
def del_repo(alias, **kwargs): # pylint: disable=unused-argument
'''
Delete a repo from /etc/opkg/*.conf
@ -1260,7 +1260,7 @@ def mod_repo(alias, **kwargs):
refresh_db()
def file_list(*packages):
def file_list(*packages, **kwargs): # pylint: disable=unused-argument
'''
List the files that belong to a package. Not specifying any packages will
return a list of _every_ file on the system's package database (not
@ -1281,7 +1281,7 @@ def file_list(*packages):
return {'errors': output['errors'], 'files': files}
def file_dict(*packages):
def file_dict(*packages, **kwargs): # pylint: disable=unused-argument
'''
List the files that belong to a package, grouped by package. Not
specifying any packages will return a list of _every_ file on the system's
@ -1323,7 +1323,7 @@ def file_dict(*packages):
return {'errors': errors, 'packages': ret}
def owner(*paths):
def owner(*paths, **kwargs): # pylint: disable=unused-argument
'''
Return the name of the package that owns the file. Multiple file paths can
be passed. Like :mod:`pkg.version <salt.modules.opkg.version`, if a single

View File

@ -159,7 +159,7 @@ def formatted(name, fs_type='ext4', force=False, **kwargs):
ret['result'] = None
return ret
__salt__['disk.format_'](name, fs_type, force=force, **kwargs)
__salt__['disk.format'](name, fs_type, force=force, **kwargs)
# Repeat fstype check up to 10 times with 3s sleeping between each
# to avoid detection failing although mkfs has succeeded

View File

@ -206,8 +206,13 @@ def wrap_tmpl_func(render_str):
if six.PY2:
output = output.encode(SLS_ENCODING)
if salt.utils.platform.is_windows():
newline = False
if output.endswith(('\n', os.linesep)):
newline = True
# Write out with Windows newlines
output = os.linesep.join(output.splitlines())
if newline:
output += os.linesep
except SaltRenderError as exc:
log.error("Rendering exception occurred: {0}".format(exc))
@ -331,7 +336,7 @@ def render_jinja_tmpl(tmplstr, context, tmplpath=None):
# http://jinja.pocoo.org/docs/api/#unicode
tmplstr = tmplstr.decode(SLS_ENCODING)
if tmplstr.endswith('\n'):
if tmplstr.endswith(os.linesep):
newline = True
if not saltenv:
@ -441,7 +446,7 @@ def render_jinja_tmpl(tmplstr, context, tmplpath=None):
# Workaround a bug in Jinja that removes the final newline
# (https://github.com/mitsuhiko/jinja2/issues/75)
if newline:
output += '\n'
output += os.linesep
return output

View File

@ -100,7 +100,7 @@ class BlockdevTestCase(TestCase, LoaderModuleMockMixin):
# Test state return when block device format fails
with patch.dict(blockdev.__salt__, {'cmd.run': MagicMock(return_value=mock_ext4),
'disk.format_': MagicMock(return_value=True)}):
'disk.format': MagicMock(return_value=True)}):
comt = ('Failed to format {0}'.format(name))
ret.update({'comment': comt, 'result': False})
with patch.object(salt.utils.path, 'which',

View File

@ -33,6 +33,7 @@ from salt.utils.jinja import (
)
from salt.utils.templates import JINJA, render_jinja_tmpl
from salt.utils.odict import OrderedDict
import salt.utils.stringutils
# Import 3rd party libs
import yaml
@ -176,12 +177,9 @@ class TestGetTemplate(TestCase):
with salt.utils.files.fopen(fn_) as fp_:
out = render_jinja_tmpl(
fp_.read(),
dict(
opts=self.local_opts,
saltenv='test',
salt=self.local_salt
))
self.assertEqual(out, 'world\n')
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
)
self.assertEqual(out, 'world' + os.linesep)
def test_fallback_noloader(self):
'''
@ -192,12 +190,9 @@ class TestGetTemplate(TestCase):
with salt.utils.files.fopen(filename) as fp_:
out = render_jinja_tmpl(
fp_.read(),
dict(
opts=self.local_opts,
saltenv='test',
salt=self.local_salt
))
self.assertEqual(out, 'Hey world !a b !\n')
dict(opts=self.local_opts, saltenv='test', salt=self.local_salt)
)
self.assertEqual(out, 'Hey world !a b !' + os.linesep)
def test_saltenv(self):
'''
@ -216,7 +211,7 @@ class TestGetTemplate(TestCase):
'file_roots': self.local_opts['file_roots'],
'pillar_roots': self.local_opts['pillar_roots']},
a='Hi', b='Salt', saltenv='test', salt=self.local_salt))
self.assertEqual(out, 'Hey world !Hi Salt !\n')
self.assertEqual(out, 'Hey world !Hi Salt !' + os.linesep)
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
def test_macro_additional_log_for_generalexc(self):
@ -225,7 +220,7 @@ class TestGetTemplate(TestCase):
more output from trace.
'''
expected = r'''Jinja error:.*division.*
.*/macrogeneral\(2\):
.*macrogeneral\(2\):
---
\{% macro mymacro\(\) -%\}
\{\{ 1/0 \}\} <======================
@ -249,7 +244,7 @@ class TestGetTemplate(TestCase):
more output from trace.
'''
expected = r'''Jinja variable 'b' is undefined
.*/macroundefined\(2\):
.*macroundefined\(2\):
---
\{% macro mymacro\(\) -%\}
\{\{b.greetee\}\} <-- error is here <======================
@ -272,7 +267,7 @@ class TestGetTemplate(TestCase):
If we failed in a macro, get more output from trace.
'''
expected = r'''Jinja syntax error: expected token .*end.*got '-'.*
.*/macroerror\(2\):
.*macroerror\(2\):
---
# macro
\{% macro mymacro\(greeting, greetee='world'\) -\} <-- error is here <======================
@ -302,7 +297,7 @@ class TestGetTemplate(TestCase):
'file_roots': self.local_opts['file_roots'],
'pillar_roots': self.local_opts['pillar_roots']},
a='Hi', b='Sàlt', saltenv='test', salt=self.local_salt))
self.assertEqual(out, u'Hey world !Hi Sàlt !\n')
self.assertEqual(out, salt.utils.stringutils.to_unicode('Hey world !Hi Sàlt !' + os.linesep))
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
filename = os.path.join(TEMPLATES_DIR, 'files', 'test', 'non_ascii')
@ -313,7 +308,7 @@ class TestGetTemplate(TestCase):
'file_roots': self.local_opts['file_roots'],
'pillar_roots': self.local_opts['pillar_roots']},
a='Hi', b='Sàlt', saltenv='test', salt=self.local_salt))
self.assertEqual(u'Assunção\n', out)
self.assertEqual(u'Assunção' + os.linesep, out)
self.assertEqual(fc.requests[0]['path'], 'salt://macro')
@skipIf(HAS_TIMELIB is False, 'The `timelib` library is not installed.')
@ -376,8 +371,8 @@ class TestGetTemplate(TestCase):
with salt.utils.files.fopen(out['data']) as fp:
result = fp.read()
if six.PY2:
result = result.decode('utf-8')
self.assertEqual(u'Assunção\n', result)
result = salt.utils.stringutils.to_unicode(result)
self.assertEqual(salt.utils.stringutils.to_unicode('Assunção' + os.linesep), result)
def test_get_context_has_enough_context(self):
template = '1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf'

View File

@ -439,7 +439,7 @@ class PillarTestCase(TestCase):
def _setup_test_topfile_mocks(self, Matcher, get_file_client,
nodegroup_order, glob_order):
# Write a simple topfile and two pillar state files
self.top_file = tempfile.NamedTemporaryFile(dir=TMP)
self.top_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
s = '''
base:
group:
@ -456,19 +456,19 @@ base:
'''.format(nodegroup_order=nodegroup_order, glob_order=glob_order)
self.top_file.write(salt.utils.stringutils.to_bytes(s))
self.top_file.flush()
self.ssh_file = tempfile.NamedTemporaryFile(dir=TMP)
self.ssh_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
self.ssh_file.write(b'''
ssh:
foo
''')
self.ssh_file.flush()
self.ssh_minion_file = tempfile.NamedTemporaryFile(dir=TMP)
self.ssh_minion_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
self.ssh_minion_file.write(b'''
ssh:
bar
''')
self.ssh_minion_file.flush()
self.generic_file = tempfile.NamedTemporaryFile(dir=TMP)
self.generic_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
self.generic_file.write(b'''
generic:
key1:
@ -478,7 +478,7 @@ generic:
sub_key1: []
''')
self.generic_file.flush()
self.generic_minion_file = tempfile.NamedTemporaryFile(dir=TMP)
self.generic_minion_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
self.generic_minion_file.write(b'''
generic:
key1:
@ -507,7 +507,7 @@ generic:
client.get_state.side_effect = get_state
def _setup_test_include_mocks(self, Matcher, get_file_client):
self.top_file = top_file = tempfile.NamedTemporaryFile(dir=TMP)
self.top_file = top_file = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
top_file.write(b'''
base:
'*':
@ -518,21 +518,21 @@ base:
- test
''')
top_file.flush()
self.init_sls = init_sls = tempfile.NamedTemporaryFile(dir=TMP)
self.init_sls = init_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
init_sls.write(b'''
include:
- test.sub1
- test.sub2
''')
init_sls.flush()
self.sub1_sls = sub1_sls = tempfile.NamedTemporaryFile(dir=TMP)
self.sub1_sls = sub1_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
sub1_sls.write(b'''
p1:
- value1_1
- value1_2
''')
sub1_sls.flush()
self.sub2_sls = sub2_sls = tempfile.NamedTemporaryFile(dir=TMP)
self.sub2_sls = sub2_sls = tempfile.NamedTemporaryFile(dir=TMP, delete=False)
sub2_sls.write(b'''
p1:
- value1_3