Accepting request 569868 from systemsmanagement:saltstack:testing

- Fix the usage of custom macros on the spec file.

- Fix RES7: different dependency names for python-PyYAML
  and python-MarkupSafe

- Build both python2 and python3 binaries together.

- Bugfix: errors in external pillar causes crash instead of report
  of them (bsc#1068446)
- Fix 'user.present' when 'gid_from_name' is set but group does
  not exist.
- Added:
 * bugfix-the-logic-according-to-the-exact-described-pu.patch
 * return-error-when-gid_from_name-and-group-does-not-e.patch

- Fix "No service execution module loaded" issue (bsc#1065792)
- Set SHELL environment variable
  Added:
  * fix-bsc-1065792.patch
  * set-shell-environment-variable-64.patch

- Removed unnecessary logging on shutdown (bsc#1050003)
- Renamed patch that adds grain fqdns
  Changed:
  * catching-error-when-pidfile-cannot-be-deleted
  Removed:
  * fix-for-pidfile-removal-logging
  Renamed:
  * add-fqdns-grains -> feat-add-grain-for-all-fqdns

OBS-URL: https://build.opensuse.org/request/show/569868
OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=107
This commit is contained in:
Pablo Suárez Hernández 2018-01-26 13:46:21 +00:00 committed by Git OBS Bridge
parent 01ad8e1de6
commit b17d3e3575
31 changed files with 1921 additions and 168 deletions

View File

@ -0,0 +1,26 @@
From 2a88378d88c2f56b152ef048214728995476244a Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Tue, 17 Oct 2017 16:52:33 +0200
Subject: [PATCH] Activate all beacons sources: config/pillar/grains
---
salt/minion.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/minion.py b/salt/minion.py
index 33cbb8fa0a..10b608cc7a 100644
--- a/salt/minion.py
+++ b/salt/minion.py
@@ -404,7 +404,7 @@ class MinionBase(object):
the pillar or grains changed
'''
if 'config.merge' in functions:
- b_conf = functions['config.merge']('beacons', self.opts['beacons'], omit_opts=True)
+ b_conf = functions['config.merge']('beacons', self.opts['beacons'])
if b_conf:
return self.beacons.process(b_conf, self.opts['grains']) # pylint: disable=no-member
return []
--
2.15.1

View File

@ -0,0 +1,26 @@
From a94f7d5739fd38529ebf23a89e6afc164739dd8d Mon Sep 17 00:00:00 2001
From: Hubert Mantel <mantel@suse.de>
Date: Mon, 27 Nov 2017 13:55:13 +0100
Subject: [PATCH] avoid excessive syslogging by watchdog cronjob (#58)
---
pkg/suse/salt-minion | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkg/suse/salt-minion b/pkg/suse/salt-minion
index 2e418094ed..73a91ebd62 100755
--- a/pkg/suse/salt-minion
+++ b/pkg/suse/salt-minion
@@ -55,7 +55,7 @@ WATCHDOG_CRON="/etc/cron.d/salt-minion"
set_watchdog() {
if [ ! -f $WATCHDOG_CRON ]; then
- echo -e '* * * * * root /usr/bin/salt-daemon-watcher --with-init\n' > $WATCHDOG_CRON
+ echo -e '-* * * * * root /usr/bin/salt-daemon-watcher --with-init\n' > $WATCHDOG_CRON
# Kick the watcher for 1 minute immediately, because cron will wake up only afterwards
/usr/bin/salt-daemon-watcher --with-init & disown
fi
--
2.15.1

View File

@ -1,7 +1,7 @@
From 49a4e807fb1cb844cec7b7c11b37f6c276f899e4 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Mon, 9 Oct 2017 17:57:48 +0200
Subject: [PATCH 5/6] Bugfix: always return a string "list" on unknown job
Subject: [PATCH] Bugfix: always return a string "list" on unknown job
target type.
---
@ -64,5 +64,6 @@ index 3f4ef296a2..4dbf0d2c6f 100644
if 'metadata' in job:
--
2.14.2
2.15.1

View File

@ -0,0 +1,316 @@
From 0e1cac43dd8211186d6794602f6da77f612850a7 Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Tue, 21 Nov 2017 12:53:11 +0100
Subject: [PATCH] Bugfix the logic according to the exact described
purpose of the function.
Rename function from ambiguous name
Fix and clarify docstring.
Remove unused variable (no exception, within the try/finally block)
Bugfix: do not pull '_errors' from unchecked objects
Bugfix: unit test mistakenly expects pillar errors as a string, while it is a list
Fix unit test: wrong error types in side effect
Add unit test for _get_pillar_errors when external and internal pillars are clean
Add unit test for _get_pillar_errors when external pillar has errors and internal is clean
Add unit test for _get_pillar_errors when both external and internal pillars contains errors
Add unit test for _get_pillar_errors when external pillar is clean and internal contains errors
Use variable, instead of direct value
---
salt/modules/state.py | 82 +++++++++++++++++++---------------------
tests/unit/modules/test_state.py | 75 +++++++++++++++++++++++++++++++-----
2 files changed, 103 insertions(+), 54 deletions(-)
diff --git a/salt/modules/state.py b/salt/modules/state.py
index fa5b997ef7..31ffc25dfe 100644
--- a/salt/modules/state.py
+++ b/salt/modules/state.py
@@ -99,17 +99,16 @@ def _set_retcode(ret, highstate=None):
__context__['retcode'] = 2
-def _check_pillar(kwargs, pillar=None):
+def _get_pillar_errors(kwargs, pillar=None):
'''
- Check the pillar for errors, refuse to run the state if there are errors
- in the pillar and return the pillar errors
+ Checks all pillars (external and internal) for errors.
+ Return an error message, if anywhere or None.
+
+ :param kwargs: dictionary of options
+ :param pillar: external pillar
+ :return: None or an error message
'''
- if kwargs.get('force'):
- return True
- pillar_dict = pillar if pillar is not None else __pillar__
- if '_errors' in pillar_dict:
- return False
- return True
+ return None if kwargs.get('force') else (pillar or {}).get('_errors', __pillar__.get('_errors')) or None
def _wait(jid):
@@ -411,10 +410,10 @@ def template(tem, queue=False, **kwargs):
context=__context__,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
if not tem.endswith('.sls'):
tem = '{sls}.sls'.format(sls=tem)
@@ -872,11 +871,10 @@ def highstate(test=None, queue=False, **kwargs):
mocked=kwargs.get('mock', False),
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- err = ['Pillar failed to render with the following messages:']
- err += __pillar__['_errors']
- return err
+ return ['Pillar failed to render with the following messages:'] + errors
st_.push_active()
ret = {}
@@ -1071,11 +1069,10 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
mocked=kwargs.get('mock', False),
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- err = ['Pillar failed to render with the following messages:']
- err += __pillar__['_errors']
- return err
+ return ['Pillar failed to render with the following messages:'] + errors
orchestration_jid = kwargs.get('orchestration_jid')
umask = os.umask(0o77)
@@ -1090,7 +1087,6 @@ def sls(mods, test=None, exclude=None, queue=False, **kwargs):
mods = mods.split(',')
st_.push_active()
- ret = {}
try:
high_, errors = st_.render_highstate({opts['environment']: mods})
@@ -1197,11 +1193,10 @@ def top(topfn, test=None, queue=False, **kwargs):
pillar_enc=pillar_enc,
context=__context__,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- err = ['Pillar failed to render with the following messages:']
- err += __pillar__['_errors']
- return err
+ return ['Pillar failed to render with the following messages:'] + errors
st_.push_active()
st_.opts['state_top'] = salt.utils.url.create(topfn)
@@ -1259,10 +1254,10 @@ def show_highstate(queue=False, **kwargs):
pillar_enc=pillar_enc,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
st_.push_active()
try:
@@ -1293,10 +1288,10 @@ def show_lowstate(queue=False, **kwargs):
st_ = salt.state.HighState(opts,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
st_.push_active()
try:
@@ -1394,11 +1389,10 @@ def sls_id(id_, mods, test=None, queue=False, **kwargs):
st_ = salt.state.HighState(opts,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- err = ['Pillar failed to render with the following messages:']
- err += __pillar__['_errors']
- return err
+ return ['Pillar failed to render with the following messages:'] + errors
if isinstance(mods, six.string_types):
split_mods = mods.split(',')
@@ -1474,10 +1468,10 @@ def show_low_sls(mods, test=None, queue=False, **kwargs):
st_ = salt.state.HighState(opts, initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
if isinstance(mods, six.string_types):
mods = mods.split(',')
@@ -1561,10 +1555,10 @@ def show_sls(mods, test=None, queue=False, **kwargs):
pillar_enc=pillar_enc,
initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
if isinstance(mods, six.string_types):
mods = mods.split(',')
@@ -1610,10 +1604,10 @@ def show_top(queue=False, **kwargs):
st_ = salt.state.HighState(opts, initial_pillar=_get_initial_pillar(opts))
- if not _check_pillar(kwargs, st_.opts['pillar']):
+ errors = _get_pillar_errors(kwargs, pillar=st_.opts['pillar'])
+ if errors:
__context__['retcode'] = 5
- raise CommandExecutionError('Pillar failed to render',
- info=st_.opts['pillar']['_errors'])
+ raise CommandExecutionError('Pillar failed to render', info=errors)
errors = []
top_ = st_.get_top()
diff --git a/tests/unit/modules/test_state.py b/tests/unit/modules/test_state.py
index 7f4f361c26..e5d10493da 100644
--- a/tests/unit/modules/test_state.py
+++ b/tests/unit/modules/test_state.py
@@ -695,9 +695,9 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch.object(state, '_check_queue', mock):
self.assertEqual(state.top("reverse_top.sls"), "A")
- mock = MagicMock(side_effect=[False, True, True])
- with patch.object(state, '_check_pillar', mock):
- with patch.dict(state.__pillar__, {"_errors": "E"}):
+ mock = MagicMock(side_effect=[['E'], None, None])
+ with patch.object(state, '_get_pillar_errors', mock):
+ with patch.dict(state.__pillar__, {"_errors": ['E']}):
self.assertListEqual(state.top("reverse_top.sls"), ret)
with patch.dict(state.__opts__, {"test": "A"}):
@@ -854,14 +854,10 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
True),
["A"])
- mock = MagicMock(side_effect=[False,
- True,
- True,
- True,
- True])
- with patch.object(state, '_check_pillar', mock):
+ mock = MagicMock(side_effect=[['E', '1'], None, None, None, None])
+ with patch.object(state, '_get_pillar_errors', mock):
with patch.dict(state.__context__, {"retcode": 5}):
- with patch.dict(state.__pillar__, {"_errors": "E1"}):
+ with patch.dict(state.__pillar__, {"_errors": ['E', '1']}):
self.assertListEqual(state.sls("core,edit.vim dev",
None,
None,
@@ -979,3 +975,62 @@ class StateTestCase(TestCase, LoaderModuleMockMixin):
with patch('salt.utils.fopen', mock_open()):
self.assertTrue(state.pkg("/tmp/state_pkg.tgz",
0, "md5"))
+
+ def test_get_pillar_errors_CC(self):
+ '''
+ Test _get_pillar_errors function.
+ CC: External clean, Internal clean
+ :return:
+ '''
+ for int_pillar, ext_pillar in [({'foo': 'bar'}, {'fred': 'baz'}),
+ ({'foo': 'bar'}, None),
+ ({}, {'fred': 'baz'})]:
+ with patch('salt.modules.state.__pillar__', int_pillar):
+ for opts, res in [({'force': True}, None),
+ ({'force': False}, None),
+ ({}, None)]:
+ assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
+
+ def test_get_pillar_errors_EC(self):
+ '''
+ Test _get_pillar_errors function.
+ EC: External erroneous, Internal clean
+ :return:
+ '''
+ errors = ['failure', 'everywhere']
+ for int_pillar, ext_pillar in [({'foo': 'bar'}, {'fred': 'baz', '_errors': errors}),
+ ({}, {'fred': 'baz', '_errors': errors})]:
+ with patch('salt.modules.state.__pillar__', int_pillar):
+ for opts, res in [({'force': True}, None),
+ ({'force': False}, errors),
+ ({}, errors)]:
+ assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
+
+ def test_get_pillar_errors_EE(self):
+ '''
+ Test _get_pillar_errors function.
+ CC: External erroneous, Internal erroneous
+ :return:
+ '''
+ errors = ['failure', 'everywhere']
+ for int_pillar, ext_pillar in [({'foo': 'bar', '_errors': errors}, {'fred': 'baz', '_errors': errors})]:
+ with patch('salt.modules.state.__pillar__', int_pillar):
+ for opts, res in [({'force': True}, None),
+ ({'force': False}, errors),
+ ({}, errors)]:
+ assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
+
+ def test_get_pillar_errors_CE(self):
+ '''
+ Test _get_pillar_errors function.
+ CC: External clean, Internal erroneous
+ :return:
+ '''
+ errors = ['failure', 'everywhere']
+ for int_pillar, ext_pillar in [({'foo': 'bar', '_errors': errors}, {'fred': 'baz'}),
+ ({'foo': 'bar', '_errors': errors}, None)]:
+ with patch('salt.modules.state.__pillar__', int_pillar):
+ for opts, res in [({'force': True}, None),
+ ({'force': False}, errors),
+ ({}, errors)]:
+ assert res == state._get_pillar_errors(kwargs=opts, pillar=ext_pillar)
--
2.15.1

View File

@ -0,0 +1,115 @@
From 16dc0e5ef2c86a315a0d09fb186dd1616df1444e Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Wed, 6 Sep 2017 10:16:51 +0200
Subject: [PATCH] Catching error when PIDfile cannot be deleted
Usually the PIDfile is locate in /run. If Salt is not started with root
permissions, it is not able to delete the PIDfile in /run. It should
be safe to just ignore this error, since Salt overwrites the PIDfile on
the next start.
---
salt/utils/parsers.py | 8 +++++-
tests/unit/utils/test_parsers.py | 54 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py
index 925ec9f4e4..d8c5068874 100644
--- a/salt/utils/parsers.py
+++ b/salt/utils/parsers.py
@@ -966,7 +966,13 @@ class DaemonMixIn(six.with_metaclass(MixInMeta, object)):
# We've loaded and merged options into the configuration, it's safe
# to query about the pidfile
if self.check_pidfile():
- os.unlink(self.config['pidfile'])
+ try:
+ os.unlink(self.config['pidfile'])
+ except OSError as err:
+ # This happens when running salt-master as a non-root user
+ # and can be ignored, since salt-master is able to
+ # overwrite the PIDfile on the next start.
+ pass
def set_pidfile(self):
from salt.utils.process import set_pidfile
diff --git a/tests/unit/utils/test_parsers.py b/tests/unit/utils/test_parsers.py
index 43488e894c..8168b3e6e3 100644
--- a/tests/unit/utils/test_parsers.py
+++ b/tests/unit/utils/test_parsers.py
@@ -5,6 +5,7 @@
# Import python libs
from __future__ import absolute_import
+import logging
# Import Salt Testing Libs
from tests.support.unit import skipIf, TestCase
@@ -21,6 +22,7 @@ import salt.utils.parsers
import salt.log.setup as log
import salt.config
import salt.syspaths
+from salt.utils.parsers import DaemonMixIn
class ErrorMock(object): # pylint: disable=too-few-public-methods
@@ -958,5 +960,57 @@ class SaltAPIParserTestCase(LogSettingsParserTests):
self.addCleanup(delattr, self, 'parser')
+@skipIf(NO_MOCK, NO_MOCK_REASON)
+class DaemonMixInTestCase(TestCase):
+ '''
+ Tests the PIDfile deletion in the DaemonMixIn.
+ '''
+
+ def setUp(self):
+ '''
+ Setting up
+ '''
+ # Set PID
+ self.pid = '/some/fake.pid'
+
+ # Setup mixin
+ self.mixin = salt.utils.parsers.DaemonMixIn()
+ self.mixin.config = {}
+ self.mixin.config['pidfile'] = self.pid
+
+ # logger
+ self.logger = logging.getLogger('salt.utils.parsers')
+
+ def test_pid_file_deletion(self):
+ '''
+ PIDfile deletion without exception.
+ '''
+ with patch('os.unlink', MagicMock()) as os_unlink:
+ with patch('os.path.isfile', MagicMock(return_value=True)):
+ with patch.object(self.logger, 'info') as mock_logger:
+ self.mixin._mixin_before_exit()
+ assert mock_logger.call_count == 0
+ assert os_unlink.call_count == 1
+
+
# Hide the class from unittest framework when it searches for TestCase classes in the module
del LogSettingsParserTests
+
+
+if __name__ == '__main__':
+ from integration import run_tests # pylint: disable=import-error,wrong-import-position
+ run_tests(MasterOptionParserTestCase,
+ MinionOptionParserTestCase,
+ ProxyMinionOptionParserTestCase,
+ SyndicOptionParserTestCase,
+ SaltCMDOptionParserTestCase,
+ SaltCPOptionParserTestCase,
+ SaltKeyOptionParserTestCase,
+ SaltCallOptionParserTestCase,
+ SaltRunOptionParserTestCase,
+ SaltSSHOptionParserTestCase,
+ SaltCloudParserTestCase,
+ SPMParserTestCase,
+ SaltAPIParserTestCase,
+ DaemonMixInTestCase,
+ needs_daemon=False)
--
2.13.6

View File

@ -0,0 +1,117 @@
From b31d8f3898149209097e01bbeefbfb70b5a0c395 Mon Sep 17 00:00:00 2001
From: Michael Calmer <mc@suse.de>
Date: Fri, 15 Dec 2017 09:53:10 +0100
Subject: [PATCH] cherrypy read() reads bytes from the wire and write
them into contents var
adapt tests to reflect reality
When CherryPy run with python3 it reads "bytes" from the wire.
In case of python2 BytesIO == StringIO, so nothing should change.
This change will do the same to make unit tests reflect reality.
---
salt/netapi/rest_cherrypy/app.py | 25 +++++++------------------
tests/support/cptestcase.py | 6 ++++--
2 files changed, 11 insertions(+), 20 deletions(-)
diff --git a/salt/netapi/rest_cherrypy/app.py b/salt/netapi/rest_cherrypy/app.py
index 4099416a28..67e0bad07a 100644
--- a/salt/netapi/rest_cherrypy/app.py
+++ b/salt/netapi/rest_cherrypy/app.py
@@ -505,6 +505,7 @@ import salt
import salt.auth
import salt.utils
import salt.utils.event
+from salt.ext.six import BytesIO
# Import salt-api libs
import salt.netapi
@@ -830,18 +831,6 @@ def urlencoded_processor(entity):
:param entity: raw POST data
'''
- if six.PY3:
- # https://github.com/cherrypy/cherrypy/pull/1572
- contents = six.StringIO()
- entity.fp.read(fp_out=contents)
- contents.seek(0)
- body_str = contents.read()
- body_bytes = salt.utils.to_bytes(body_str)
- body_bytes = six.BytesIO(body_bytes)
- body_bytes.seek(0)
- # Patch fp
- entity.fp = body_bytes
- del contents
# First call out to CherryPy's default processor
cherrypy._cpreqbody.process_urlencoded(entity)
cherrypy._cpreqbody.process_urlencoded(entity)
@@ -860,10 +849,10 @@ def json_processor(entity):
body = entity.fp.read()
else:
# https://github.com/cherrypy/cherrypy/pull/1572
- contents = six.StringIO()
+ contents = BytesIO()
body = entity.fp.read(fp_out=contents)
contents.seek(0)
- body = contents.read()
+ body = salt.utils.to_unicode(contents.read())
del contents
try:
cherrypy.serving.request.unserialized_data = json.loads(body)
@@ -884,10 +873,10 @@ def yaml_processor(entity):
body = entity.fp.read()
else:
# https://github.com/cherrypy/cherrypy/pull/1572
- contents = six.StringIO()
+ contents = BytesIO()
body = entity.fp.read(fp_out=contents)
contents.seek(0)
- body = contents.read()
+ body = salt.utils.to_unicode(contents.read())
try:
cherrypy.serving.request.unserialized_data = yaml.safe_load(body)
except ValueError:
@@ -910,10 +899,10 @@ def text_processor(entity):
body = entity.fp.read()
else:
# https://github.com/cherrypy/cherrypy/pull/1572
- contents = six.StringIO()
+ contents = BytesIO()
body = entity.fp.read(fp_out=contents)
contents.seek(0)
- body = contents.read()
+ body = salt.utils.to_unicode(contents.read())
try:
cherrypy.serving.request.unserialized_data = json.loads(body)
except ValueError:
diff --git a/tests/support/cptestcase.py b/tests/support/cptestcase.py
index ea2845f46d..75785b8eb1 100644
--- a/tests/support/cptestcase.py
+++ b/tests/support/cptestcase.py
@@ -38,9 +38,11 @@ from tests.support.case import TestCase
# pylint: disable=import-error
import cherrypy # pylint: disable=3rd-party-module-not-gated
import salt.ext.six as six
-from salt.ext.six.moves import StringIO
+from salt.ext.six import BytesIO
# pylint: enable=import-error
+import salt.utils
+
# Not strictly speaking mandatory but just makes sense
cherrypy.config.update({'environment': "test_suite"})
@@ -92,7 +94,7 @@ class BaseCherryPyTestCase(TestCase):
fd = None
if body is not None:
h['content-length'] = '{0}'.format(len(body))
- fd = StringIO(body)
+ fd = BytesIO(salt.utils.to_bytes(body))
if headers is not None:
h.update(headers)
--
2.15.1

View File

@ -2,7 +2,7 @@ From 1949261a504fd01e057b41126d78f142f4977204 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Fri, 6 Oct 2017 17:12:15 +0100
Subject: [PATCH 6/6] Enable '--with-salt-version' parameter for setup.py
Subject: [PATCH] Enable '--with-salt-version' parameter for setup.py
script
---
@ -71,5 +71,6 @@ index effdc2f230..519f753401 100755
self.salt_version = __version__ # pylint: disable=undefined-variable
self.description = 'Portable, distributed, remote execution and configuration management system'
--
2.14.2
2.15.1

0
fake-fix.patch Normal file
View File

View File

@ -0,0 +1,119 @@
From ba9f26cf00b0a767b7b25f156553a9e783aa895d Mon Sep 17 00:00:00 2001
From: Michele Bologna <michele.bologna@suse.com>
Date: Thu, 14 Dec 2017 18:20:02 +0100
Subject: [PATCH] Feat: add grain for all FQDNs
This PR adds a grain named fqdns to the grains.
fqdns represents all the FQDNs known for the system on all available interfaces (excluding lo).
Note: hostname != FQDN
hostname is the UNIX name of the machine. A machine can have one and only one hostname.
FQDN is host.domain that resolves to an IP address that the machines is answering to.
A machine can have 1+ FQDNs.
Upstream PR:
https://github.com/saltstack/salt/pull/45060
---
salt/grains/core.py | 27 +++++++++++++++++++++++++++
tests/integration/modules/test_grains.py | 1 +
tests/unit/grains/test_core.py | 28 ++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
diff --git a/salt/grains/core.py b/salt/grains/core.py
index a7e1a22d2a..04b73f9120 100644
--- a/salt/grains/core.py
+++ b/salt/grains/core.py
@@ -1756,6 +1756,33 @@ def append_domain():
return grain
+def fqdns():
+ '''
+ Return all known FQDNs for the system by enumerating all interfaces and
+ then trying to reverse resolve them (excluding 'lo' interface).
+ '''
+ # Provides:
+ # fqdns
+
+ grains = {}
+ fqdns = set()
+
+ addresses = salt.utils.network.ip_addrs(include_loopback=False,
+ interface_data=_INTERFACES)
+ addresses.extend(salt.utils.network.ip_addrs6(include_loopback=False,
+ interface_data=_INTERFACES))
+
+ for ip in addresses:
+ try:
+ fqdns.add(socket.gethostbyaddr(ip)[0])
+ except (socket.error, socket.herror,
+ socket.gaierror, socket.timeout) as e:
+ log.error("Exception during resolving address: " + str(e))
+
+ grains['fqdns'] = list(fqdns)
+ return grains
+
+
def ip_fqdn():
'''
Return ip address and FQDN grains
diff --git a/tests/integration/modules/test_grains.py b/tests/integration/modules/test_grains.py
index 7d46315e42..1db90ab532 100644
--- a/tests/integration/modules/test_grains.py
+++ b/tests/integration/modules/test_grains.py
@@ -51,6 +51,7 @@ class TestModulesGrains(ModuleCase):
'cpuarch',
'domain',
'fqdn',
+ 'fqdns',
'gid',
'groupname',
'host',
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
index 6ee4257863..4f1412de76 100644
--- a/tests/unit/grains/test_core.py
+++ b/tests/unit/grains/test_core.py
@@ -6,6 +6,7 @@
# Import Python libs
from __future__ import absolute_import
import os
+import socket
# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
@@ -462,3 +463,30 @@ PATCHLEVEL = 3
self.assertEqual(os_grains.get('osrelease'), os_release_map['osrelease'])
self.assertListEqual(list(os_grains.get('osrelease_info')), os_release_map['osrelease_info'])
self.assertEqual(os_grains.get('osmajorrelease'), os_release_map['osmajorrelease'])
+
+ @skipIf(not salt.utils.is_linux(), 'System is not Linux')
+ def test_fqdns_return(self):
+ '''
+ test the return for a dns grain. test for issue:
+ https://github.com/saltstack/salt/issues/41230
+ '''
+ reverse_resolv_mock = [('foo.bar.baz', [], ['1.2.3.4']),
+ ('rinzler.evil-corp.com', [], ['5.6.7.8']),
+ ('foo.bar.baz', [], ['fe80::a8b2:93ff:fe00:0']),
+ ('bluesniff.foo.bar', [], ['fe80::a8b2:93ff:dead:beef'])]
+ ret = {'fqdns': ['rinzler.evil-corp.com', 'foo.bar.baz', 'bluesniff.foo.bar']}
+ self._run_fqdns_test(reverse_resolv_mock, ret)
+
+ def _run_fqdns_test(self, reverse_resolv_mock, ret):
+ with patch.object(salt.utils, 'is_windows', MagicMock(return_value=False)):
+ with patch('salt.utils.network.ip_addrs',
+ MagicMock(return_value=['1.2.3.4', '5.6.7.8'])),\
+ patch('salt.utils.network.ip_addrs6',
+ MagicMock(return_value=['fe80::a8b2:93ff:fe00:0', 'fe80::a8b2:93ff:dead:beef'])):
+ with patch.object(socket, 'gethostbyaddr', side_effect=reverse_resolv_mock):
+ fqdns = core.fqdns()
+ self.assertEqual(fqdns, ret)
+
+if __name__ == '__main__':
+ from integration import run_tests
+ run_tests(CoreGrainsTestCase, needs_daemon=False)
--
2.13.6

25
fix-bsc-1065792.patch Normal file
View File

@ -0,0 +1,25 @@
From e6b1c05fb9e38e54ad30a540a32cd8491fee286b Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Thu, 14 Dec 2017 16:21:40 +0100
Subject: [PATCH] Fix bsc#1065792
---
salt/states/service.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/salt/states/service.py b/salt/states/service.py
index ff5300df6a..eaa9474f78 100644
--- a/salt/states/service.py
+++ b/salt/states/service.py
@@ -80,6 +80,7 @@ def __virtual__():
Only make these states available if a service provider has been detected or
assigned for this minion
'''
+ __salt__._load_all()
if 'service.start' in __salt__:
return __virtualname__
else:
--
2.15.1

View File

@ -0,0 +1,253 @@
From 01c4d8875a8be8b0707b0088ccf186c4cd137448 Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Wed, 23 Aug 2017 21:31:28 +0200
Subject: [PATCH] Fix for delete_deployment in Kubernetes module
The Kubernetes module function delete_deployment() uses
api_instance.delete_namespaced_deployment() from the Kubernetes lib. This
method from the Kubernetes lib returns immediately without giving a success
or failure indication, which lets Salt mark the job as failed even though we
don't know if it failed or not.
To actually get a result I've implemented a polling via show_deployment() to
check if the deployment got removed.
If a time limit is hit, we are returning with an error, otherwise it is a
success.
Since Windows has no signal.alarm implementation, we are here falling back to
loop counting.
---
salt/exceptions.py | 6 ++
salt/modules/kubernetes.py | 44 +++++++++++-
tests/unit/modules/test_kubernetes.py | 126 ++++++++++++++++++++++++++++++++++
3 files changed, 175 insertions(+), 1 deletion(-)
create mode 100644 tests/unit/modules/test_kubernetes.py
diff --git a/salt/exceptions.py b/salt/exceptions.py
index 256537dd77..00111df104 100644
--- a/salt/exceptions.py
+++ b/salt/exceptions.py
@@ -265,6 +265,12 @@ class SaltCacheError(SaltException):
'''
+class TimeoutError(SaltException):
+ '''
+ Thrown when an opration cannot be completet within a given time limit.
+ '''
+
+
class SaltReqTimeoutError(SaltException):
'''
Thrown when a salt master request call fails to return within the timeout
diff --git a/salt/modules/kubernetes.py b/salt/modules/kubernetes.py
index 2e17b11444..890659c1c8 100644
--- a/salt/modules/kubernetes.py
+++ b/salt/modules/kubernetes.py
@@ -40,11 +40,15 @@ import base64
import logging
import yaml
import tempfile
+import signal
+from time import sleep
+from contextlib import contextmanager
from salt.exceptions import CommandExecutionError
from salt.ext.six import iteritems
import salt.utils
import salt.utils.templates
+from salt.ext.six.moves import range # pylint: disable=import-error
try:
import kubernetes # pylint: disable=import-self
@@ -78,6 +82,21 @@ def __virtual__():
return False, 'python kubernetes library not found'
+if not salt.utils.is_windows():
+ @contextmanager
+ def _time_limit(seconds):
+ def signal_handler(signum, frame):
+ raise TimeoutException
+ signal.signal(signal.SIGALRM, signal_handler)
+ signal.alarm(seconds)
+ try:
+ yield
+ finally:
+ signal.alarm(0)
+
+ POLLING_TIME_LIMIT = 30
+
+
# pylint: disable=no-member
def _setup_conn(**kwargs):
'''
@@ -692,7 +711,30 @@ def delete_deployment(name, namespace='default', **kwargs):
name=name,
namespace=namespace,
body=body)
- return api_response.to_dict()
+ mutable_api_response = api_response.to_dict()
+ if not salt.utils.is_windows():
+ try:
+ with _time_limit(POLLING_TIME_LIMIT):
+ while show_deployment(name, namespace) is not None:
+ sleep(1)
+ else: # pylint: disable=useless-else-on-loop
+ mutable_api_response['code'] = 200
+ except TimeoutException:
+ pass
+ else:
+ # Windows has not signal.alarm implementation, so we are just falling
+ # back to loop-counting.
+ for i in range(60):
+ if show_deployment(name, namespace) is None:
+ mutable_api_response['code'] = 200
+ break
+ else:
+ sleep(1)
+ if mutable_api_response['code'] != 200:
+ log.warning('Reached polling time limit. Deployment is not yet '
+ 'deleted, but we are backing off. Sorry, but you\'ll '
+ 'have to check manually.')
+ return mutable_api_response
except (ApiException, HTTPError) as exc:
if isinstance(exc, ApiException) and exc.status == 404:
return None
diff --git a/tests/unit/modules/test_kubernetes.py b/tests/unit/modules/test_kubernetes.py
new file mode 100644
index 0000000000..493822a93c
--- /dev/null
+++ b/tests/unit/modules/test_kubernetes.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+'''
+ :codeauthor: :email:`Jochen Breuer <jbreuer@suse.de>`
+'''
+
+# Import Python Libs
+from __future__ import absolute_import
+
+# Import Salt Testing Libs
+from salttesting import TestCase, skipIf
+from salttesting.mock import (
+ Mock,
+ patch,
+ NO_MOCK,
+ NO_MOCK_REASON
+)
+
+try:
+ from salt.modules import kubernetes
+except ImportError:
+ kubernetes = False
+
+# Globals
+kubernetes.__salt__ = dict()
+kubernetes.__grains__ = dict()
+kubernetes.__context__ = dict()
+
+
+@skipIf(NO_MOCK, NO_MOCK_REASON)
+@skipIf(kubernetes is False, "Probably Kubernetes client lib is not installed. \
+ Skipping test_kubernetes.py")
+class KubernetesTestCase(TestCase):
+ '''
+ Test cases for salt.modules.kubernetes
+ '''
+
+ def test_nodes(self):
+ '''
+ Test node listing.
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.CoreV1Api.return_value = Mock(
+ **{"list_node.return_value.to_dict.return_value":
+ {'items': [{'metadata': {'name': 'mock_node_name'}}]}}
+ )
+ self.assertEqual(kubernetes.nodes(), ['mock_node_name'])
+ self.assertTrue(kubernetes.kubernetes.client.CoreV1Api().list_node().to_dict.called)
+
+ def test_deployments(self):
+ '''
+ Tests deployment listing.
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.ExtensionsV1beta1Api.return_value = Mock(
+ **{"list_namespaced_deployment.return_value.to_dict.return_value":
+ {'items': [{'metadata': {'name': 'mock_deployment_name'}}]}}
+ )
+ self.assertEqual(kubernetes.deployments(), ['mock_deployment_name'])
+ self.assertTrue(
+ kubernetes.kubernetes.client.ExtensionsV1beta1Api().list_namespaced_deployment().to_dict.called)
+
+ def test_services(self):
+ '''
+ Tests services listing.
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.CoreV1Api.return_value = Mock(
+ **{"list_namespaced_service.return_value.to_dict.return_value":
+ {'items': [{'metadata': {'name': 'mock_service_name'}}]}}
+ )
+ self.assertEqual(kubernetes.services(), ['mock_service_name'])
+ self.assertTrue(kubernetes.kubernetes.client.CoreV1Api().list_namespaced_service().to_dict.called)
+
+ def test_pods(self):
+ '''
+ Tests pods listing.
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.CoreV1Api.return_value = Mock(
+ **{"list_namespaced_pod.return_value.to_dict.return_value":
+ {'items': [{'metadata': {'name': 'mock_pod_name'}}]}}
+ )
+ self.assertEqual(kubernetes.pods(), ['mock_pod_name'])
+ self.assertTrue(kubernetes.kubernetes.client.CoreV1Api().
+ list_namespaced_pod().to_dict.called)
+
+ def test_delete_deployments(self):
+ '''
+ Tests deployment deletion
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch('salt.modules.kubernetes.show_deployment', Mock(return_value=None)):
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.V1DeleteOptions = Mock(return_value="")
+ mock_kubernetes_lib.client.ExtensionsV1beta1Api.return_value = Mock(
+ **{"delete_namespaced_deployment.return_value.to_dict.return_value": {'code': ''}}
+ )
+ self.assertEqual(kubernetes.delete_deployment("test"), {'code': 200})
+ self.assertTrue(
+ kubernetes.kubernetes.client.ExtensionsV1beta1Api().
+ delete_namespaced_deployment().to_dict.called)
+
+ def test_create_deployments(self):
+ '''
+ Tests deployment creation.
+ :return:
+ '''
+ with patch('salt.modules.kubernetes.kubernetes') as mock_kubernetes_lib:
+ with patch.dict(kubernetes.__salt__, {'config.option': Mock(return_value="")}):
+ mock_kubernetes_lib.client.ExtensionsV1beta1Api.return_value = Mock(
+ **{"create_namespaced_deployment.return_value.to_dict.return_value": {}}
+ )
+ self.assertEqual(kubernetes.create_deployment("test", "default", {}, {},
+ None, None, None), {})
+ self.assertTrue(
+ kubernetes.kubernetes.client.ExtensionsV1beta1Api().
+ create_namespaced_deployment().to_dict.called)
--
2.15.1

View File

@ -0,0 +1,162 @@
From 914cabfacd9c1209e3f0e7a613e8cc0d1617580b Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Mon, 11 Dec 2017 09:49:10 +0100
Subject: [PATCH] Fix for wrong version processing
Since version and epoch seem to be split by default now, the yum pkg info
processing should have changed.
* Fixes the version info processing for pkg installation.
* Test for installation with and without diff_attr.
---
salt/modules/yumpkg.py | 28 +++++++++------
tests/unit/modules/test_yumpkg.py | 72 +++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 10 deletions(-)
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
index 8b63bff4a3..027d680bff 100644
--- a/salt/modules/yumpkg.py
+++ b/salt/modules/yumpkg.py
@@ -588,7 +588,6 @@ def version_cmp(pkg1, pkg2, ignore_epoch=False):
salt '*' pkg.version_cmp '0.2-001' '0.2.0.1-002'
'''
-
return __salt__['lowpkg.version_cmp'](pkg1, pkg2, ignore_epoch=ignore_epoch)
@@ -1440,18 +1439,20 @@ def install(name=None,
else:
pkgstr = pkgpath
- # Lambda to trim the epoch from the currently-installed version if
- # no epoch is specified in the specified version
- norm_epoch = lambda x, y: x.split(':', 1)[-1] \
- if ':' not in y \
- else x
cver = old_as_list.get(pkgname, [])
if reinstall and cver:
for ver in cver:
- ver = norm_epoch(ver, version_num)
+ if diff_attr:
+ # Since diff_attr was provided, the version info
+ # is a dict.
+ ver2 = ver['version']
+ else:
+ # No diff_attr was provided, so version is directly
+ # in ver.
+ ver2 = ver
if salt.utils.compare_versions(ver1=version_num,
oper='==',
- ver2=ver,
+ ver2=ver2,
cmp_func=version_cmp):
# This version is already installed, so we need to
# reinstall.
@@ -1462,10 +1463,17 @@ def install(name=None,
to_install.append((pkgname, pkgstr))
else:
for ver in cver:
- ver = norm_epoch(ver, version_num)
+ if diff_attr:
+ # Since diff_attr was provided, the version info
+ # is a dict.
+ ver2 = ver['version']
+ else:
+ # No diff_attr was provided, so version is directly
+ # in ver.
+ ver2 = ver
if salt.utils.compare_versions(ver1=version_num,
oper='>=',
- ver2=ver,
+ ver2=ver2,
cmp_func=version_cmp):
to_install.append((pkgname, pkgstr))
break
diff --git a/tests/unit/modules/test_yumpkg.py b/tests/unit/modules/test_yumpkg.py
index cf754d6289..c5e8d746d5 100644
--- a/tests/unit/modules/test_yumpkg.py
+++ b/tests/unit/modules/test_yumpkg.py
@@ -27,6 +27,78 @@ class YumTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {yumpkg: {'rpm': None}}
+ def test_install_pkg(self):
+ '''
+ Test package installation.
+
+ :return:
+ '''
+ def _add_data(data, key, value):
+ data.setdefault(key, []).append(value)
+
+ rpm_out = [
+ 'python-urlgrabber_|-(none)_|-3.10_|-8.el7_|-noarch_|-(none)_|-1487838471',
+ 'alsa-lib_|-(none)_|-1.1.1_|-1.el7_|-x86_64_|-(none)_|-1487838475',
+ 'gnupg2_|-(none)_|-2.0.22_|-4.el7_|-x86_64_|-(none)_|-1487838477',
+ 'rpm-python_|-(none)_|-4.11.3_|-21.el7_|-x86_64_|-(none)_|-1487838477',
+ 'pygpgme_|-(none)_|-0.3_|-9.el7_|-x86_64_|-(none)_|-1487838478',
+ 'yum_|-(none)_|-3.4.3_|-150.el7.centos_|-noarch_|-(none)_|-1487838479',
+ 'lzo_|-(none)_|-2.06_|-8.el7_|-x86_64_|-(none)_|-1487838479',
+ 'qrencode-libs_|-(none)_|-3.4.1_|-3.el7_|-x86_64_|-(none)_|-1487838480',
+ 'ustr_|-(none)_|-1.0.4_|-16.el7_|-x86_64_|-(none)_|-1487838480',
+ 'shadow-utils_|-2_|-4.1.5.1_|-24.el7_|-x86_64_|-(none)_|-1487838481',
+ 'util-linux_|-(none)_|-2.23.2_|-33.el7_|-x86_64_|-(none)_|-1487838484',
+ 'openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485',
+ 'virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486',
+ ]
+ with patch.dict(yumpkg.__grains__, {'osarch': 'x86_64', 'os': 'RedHat'}), \
+ patch.dict(yumpkg.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \
+ patch.dict(yumpkg.__salt__, {'cmd.run_all': MagicMock(return_value={'retcode': 0})}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=({'python-urlgrabber': '0.0.1'} , 'repository'))}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \
+ patch.dict(yumpkg.__salt__, {'config.get': MagicMock()}), \
+ patch.dict(yumpkg.__salt__, {'lowpkg.version_cmp': MagicMock(return_value=-1)}):
+ pkgs = yumpkg.install(name='python-urlgrabber')
+ self.assertEqual(pkgs, {})
+
+
+ def test_install_pkg_with_diff_attr(self):
+ '''
+ Test package installation with diff_attr.
+
+ :return:
+ '''
+ def _add_data(data, key, value):
+ data.setdefault(key, []).append(value)
+
+ rpm_out = [
+ 'python-urlgrabber_|-(none)_|-3.10_|-8.el7_|-noarch_|-(none)_|-1487838471',
+ 'alsa-lib_|-(none)_|-1.1.1_|-1.el7_|-x86_64_|-(none)_|-1487838475',
+ 'gnupg2_|-(none)_|-2.0.22_|-4.el7_|-x86_64_|-(none)_|-1487838477',
+ 'rpm-python_|-(none)_|-4.11.3_|-21.el7_|-x86_64_|-(none)_|-1487838477',
+ 'pygpgme_|-(none)_|-0.3_|-9.el7_|-x86_64_|-(none)_|-1487838478',
+ 'yum_|-(none)_|-3.4.3_|-150.el7.centos_|-noarch_|-(none)_|-1487838479',
+ 'lzo_|-(none)_|-2.06_|-8.el7_|-x86_64_|-(none)_|-1487838479',
+ 'qrencode-libs_|-(none)_|-3.4.1_|-3.el7_|-x86_64_|-(none)_|-1487838480',
+ 'ustr_|-(none)_|-1.0.4_|-16.el7_|-x86_64_|-(none)_|-1487838480',
+ 'shadow-utils_|-2_|-4.1.5.1_|-24.el7_|-x86_64_|-(none)_|-1487838481',
+ 'util-linux_|-(none)_|-2.23.2_|-33.el7_|-x86_64_|-(none)_|-1487838484',
+ 'openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485',
+ 'virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486',
+ ]
+ with patch.dict(yumpkg.__grains__, {'osarch': 'x86_64', 'os': 'RedHat'}), \
+ patch.dict(yumpkg.__salt__, {'cmd.run': MagicMock(return_value=os.linesep.join(rpm_out))}), \
+ patch.dict(yumpkg.__salt__, {'cmd.run_all': MagicMock(return_value={'retcode': 0})}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.add_pkg': _add_data}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=({'python-urlgrabber': '0.0.1'} , 'repository'))}), \
+ patch.dict(yumpkg.__salt__, {'pkg_resource.format_pkg_list': pkg_resource.format_pkg_list}), \
+ patch.dict(yumpkg.__salt__, {'config.get': MagicMock()}), \
+ patch.dict(yumpkg.__salt__, {'lowpkg.version_cmp': MagicMock(return_value=-1)}):
+ pkgs = yumpkg.install(name='python-urlgrabber', diff_attr=['version', 'epoch', 'release', 'arch'])
+ self.assertEqual(pkgs, {})
+
+
def test_list_pkgs(self):
'''
Test packages listing.
--
2.15.1

View File

@ -0,0 +1,26 @@
From e9635560f2b0a213518c5023e0b6fb4a11e5570d Mon Sep 17 00:00:00 2001
From: Mihai Dinca <mdinca@suse.de>
Date: Fri, 8 Dec 2017 13:34:06 +0100
Subject: [PATCH] Fix salt-master for old psutil
---
salt/utils/psutil_compat.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/utils/psutil_compat.py b/salt/utils/psutil_compat.py
index a32712860a..dee563455b 100644
--- a/salt/utils/psutil_compat.py
+++ b/salt/utils/psutil_compat.py
@@ -26,7 +26,7 @@ else:
# Psuedo "from psutil import *"
_globals = globals()
for attr in psutil.__all__:
- _temp = __import__('psutil', globals(), locals(), [attr], -1)
+ _temp = __import__('psutil', globals(), locals(), [attr], -1 if six.PY2 else 0)
try:
_globals[attr] = getattr(_temp, attr)
except AttributeError:
--
2.15.1

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4033a19f562875d4124d5f18fffb485cbbb1a256996b4a8019ac4f32064657be
size 6413238
oid sha256:6b82846ed4005af7655290cd9bdc62c1d4912d4809acaca2ff37ebff0960b18c
size 1250836

View File

@ -1,7 +1,7 @@
From cb472e1f0fc18a554e0de9e3fe6bbe16557957ee Mon Sep 17 00:00:00 2001
From: Silvio Moioli <smoioli@suse.de>
Date: Wed, 20 Sep 2017 14:33:33 +0200
Subject: [PATCH 4/6] Introduce process_count_max minion configuration
Subject: [PATCH] Introduce process_count_max minion configuration
parameter
This allows users to limit the number of processes or threads a minion
@ -206,5 +206,6 @@ index 535dfeedfc..6c9dca13cd 100644
+ finally:
+ minion.destroy()
--
2.14.2
2.15.1

View File

@ -1,8 +1,8 @@
From ca7031e5223bb3bd35c31211d29177f05ed5e304 Mon Sep 17 00:00:00 2001
From: Silvio Moioli <smoioli@suse.de>
Date: Thu, 13 Jul 2017 15:59:01 +0200
Subject: [PATCH 1/6] list_pkgs: add parameter for returned attribute selection
(bsc#1052264)
Subject: [PATCH] list_pkgs: add parameter for returned attribute
selection (bsc#1052264)
zypper.list_pkgs:
* It adds a new optional parameter to list_pkg in the zypper module to return more data than the version (original reason is that for SUSE Manager integration we also need arch and install_date). Format is the same of existing method info_installed.
@ -787,5 +787,6 @@ index f3403e6e1c..41f3845646 100644
def test_list_patches(self):
'''
--
2.14.2
2.15.1

View File

@ -1,7 +1,7 @@
From 461654496d36a264903057a8255aec4eb700e506 Mon Sep 17 00:00:00 2001
From: Silvio Moioli <smoioli@suse.de>
Date: Wed, 20 Sep 2017 14:32:47 +0200
Subject: [PATCH 3/6] multiprocessing minion option: documentation fixes
Subject: [PATCH] multiprocessing minion option: documentation fixes
---
doc/man/salt.7 | 1 +
@ -42,5 +42,6 @@ index e0f349931c..5c92b932ab 100644
--
2.14.2
2.15.1

View File

@ -0,0 +1,25 @@
From d68365a35dd00cced7cdc6eff2ad8a3b823c26f6 Mon Sep 17 00:00:00 2001
From: Michael Calmer <mc@suse.de>
Date: Thu, 7 Dec 2017 17:30:31 +0100
Subject: [PATCH] older logrotate need su directive
---
pkg/suse/salt-common.logrotate | 1 +
1 file changed, 1 insertion(+)
diff --git a/pkg/suse/salt-common.logrotate b/pkg/suse/salt-common.logrotate
index 0d99d1b801..625670942c 100644
--- a/pkg/suse/salt-common.logrotate
+++ b/pkg/suse/salt-common.logrotate
@@ -8,6 +8,7 @@
}
/var/log/salt/minion {
+ su root root
weekly
missingok
rotate 7
--
2.15.1

View File

@ -0,0 +1,25 @@
From d21ea1062f1cd8da0e604288b369c7ff38919c78 Mon Sep 17 00:00:00 2001
From: Michael Calmer <mc@suse.de>
Date: Tue, 19 Dec 2017 17:07:19 +0100
Subject: [PATCH] python3 compatibility fix - got bytes instead of string
---
salt/netapi/rest_cherrypy/tools/websockets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/salt/netapi/rest_cherrypy/tools/websockets.py b/salt/netapi/rest_cherrypy/tools/websockets.py
index fe4f9def85..44c5e2fa05 100644
--- a/salt/netapi/rest_cherrypy/tools/websockets.py
+++ b/salt/netapi/rest_cherrypy/tools/websockets.py
@@ -54,6 +54,6 @@ class SynchronizingWebsocket(WebSocket):
This ensures completion of the underlying websocket connection
and can be used to synchronize parallel senders.
'''
- if message.data == 'websocket client ready':
+ if message.data.decode('utf-8') == 'websocket client ready':
self.pipe.send(message)
self.send('server received message', False)
--
2.13.6

View File

@ -0,0 +1,123 @@
From 5384cb815764af43f287bcb6ed49a9a68d5cd5c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Wed, 10 Jan 2018 11:59:33 +0000
Subject: [PATCH] Return error when gid_from_name and group does not
exist.
Fixes #45345
Ensure empty string gid is set to None
Make pylint happy
Fix integration tests for 'user.present' state.
Update documentation for 'gid_from_name' parameter
Refactor to prevent logical bug when gid is 0
---
salt/states/user.py | 7 +++++-
tests/integration/states/test_user.py | 42 +++++++++++++++++++++++------------
2 files changed, 34 insertions(+), 15 deletions(-)
diff --git a/salt/states/user.py b/salt/states/user.py
index 8a731cc2a1..737c39f4b4 100644
--- a/salt/states/user.py
+++ b/salt/states/user.py
@@ -240,7 +240,8 @@ def present(name,
gid_from_name
If True, the default group id will be set to the id of the group with
- the same name as the user, Default is ``False``.
+ the same name as the user. If the group does not exist the state will
+ fail. Default is ``False``.
groups
A list of groups to assign the user to, pass a list object. If a group
@@ -455,6 +456,10 @@ def present(name,
if gid_from_name:
gid = __salt__['file.group_to_gid'](name)
+ if gid == '':
+ ret['comment'] = 'Default group with name "{0}" is not present'.format(name)
+ ret['result'] = False
+ return ret
changes = _changes(name,
uid,
diff --git a/tests/integration/states/test_user.py b/tests/integration/states/test_user.py
index 1317f12f97..ae9774a241 100644
--- a/tests/integration/states/test_user.py
+++ b/tests/integration/states/test_user.py
@@ -97,15 +97,25 @@ class UserTest(ModuleCase, SaltReturnAssertsMixin):
home=HOMEDIR)
self.assertSaltTrueReturn(ret)
- def test_user_present_nondefault(self):
+ @requires_system_grains
+ def test_user_present_nondefault(self, grains=None):
'''
This is a DESTRUCTIVE TEST it creates a new user on the on the minion.
'''
ret = self.run_state('user.present', name=self.user_name,
home=self.user_home)
self.assertSaltTrueReturn(ret)
+ ret = self.run_function('user.info', [self.user_name])
+ self.assertReturnNonEmptySaltType(ret)
+ group_name = grp.getgrgid(ret['gid']).gr_name
if not salt.utils.is_darwin():
self.assertTrue(os.path.isdir(self.user_home))
+ 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, self.user_name)
@requires_system_grains
def test_user_present_gid_from_name_default(self, grains=None):
@@ -120,22 +130,26 @@ class UserTest(ModuleCase, SaltReturnAssertsMixin):
# user
gid_from_name = False if grains['os_family'] == 'MacOS' else True
- ret = self.run_state('user.present', name=self.user_name,
+ ret_user_present = self.run_state('user.present', name=self.user_name,
gid_from_name=gid_from_name, home=self.user_home)
- self.assertSaltTrueReturn(ret)
- ret = self.run_function('user.info', [self.user_name])
- self.assertReturnNonEmptySaltType(ret)
- group_name = grp.getgrgid(ret['gid']).gr_name
-
- if not salt.utils.is_darwin():
- self.assertTrue(os.path.isdir(self.user_home))
- if grains['os_family'] in ('Suse',):
- self.assertEqual(group_name, 'users')
- elif grains['os_family'] == 'MacOS':
- self.assertEqual(group_name, 'staff')
+ if gid_from_name:
+ self.assertSaltFalseReturn(ret_user_present)
+ ret_user_present = ret_user_present[next(iter(ret_user_present))]
+ self.assertTrue('is not present' in ret_user_present['comment'])
else:
- self.assertEqual(group_name, self.user_name)
+ self.assertSaltTrueReturn(ret_user_present)
+ ret_user_info = self.run_function('user.info', [self.user_name])
+ self.assertReturnNonEmptySaltType(ret_user_info)
+ group_name = grp.getgrgid(ret_user_info['gid']).gr_name
+ if not salt.utils.is_darwin():
+ self.assertTrue(os.path.isdir(self.user_home))
+ 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, self.user_name)
def test_user_present_gid_from_name(self):
'''
--
2.15.1

View File

@ -1,7 +1,7 @@
From 8f81bee8d8929cc4cd30dabc7cbc92d2cba9760e Mon Sep 17 00:00:00 2001
From: Christian Lanig <clanig@suse.com>
Date: Mon, 27 Nov 2017 13:10:26 +0100
Subject: [PATCH 2/2] Run salt-api as user salt (bsc#1064520)
Subject: [PATCH] Run salt-api as user salt (bsc#1064520)
---
pkg/salt-api.service | 1 +
@ -20,5 +20,6 @@ index 7ca582dfb4..bf513e4dbd 100644
ExecStart=/usr/bin/salt-api
TimeoutStopSec=3
--
2.14.2
2.15.1

View File

@ -1,7 +1,7 @@
From 3902fe4183d169808b9d248b9b963926035ba954 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Klaus=20K=C3=A4mpf?= <kkaempf@suse.de>
Date: Wed, 20 Jan 2016 11:01:06 +0100
Subject: [PATCH 1/2] Run salt master as dedicated salt user
Subject: [PATCH] Run salt master as dedicated salt user
* Minion runs always as a root
---
@ -42,5 +42,6 @@ index 3cd002308e..0d99d1b801 100644
missingok
rotate 7
--
2.14.2
2.15.1

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ff3bc7de5abf01b8acbd144db5811b00867179b2353f5c6f7f19241e2eff2840
size 11471191

View File

@ -1,3 +1,127 @@
-------------------------------------------------------------------
Thu Jan 25 13:04:24 UTC 2018 - pablo.suarezhernandez@suse.com
- Fix the usage of custom macros on the spec file.
-------------------------------------------------------------------
Thu Jan 25 10:49:53 UTC 2018 - bmaryniuk@suse.com
- Fix RES7: different dependency names for python-PyYAML
and python-MarkupSafe
-------------------------------------------------------------------
Wed Jan 24 15:04:42 UTC 2018 - bmaryniuk@suse.com
- Build both python2 and python3 binaries together.
-------------------------------------------------------------------
Wed Jan 17 11:26:54 UTC 2018 - pablo.suarezhernandez@suse.com
- Bugfix: errors in external pillar causes crash instead of report
of them (bsc#1068446)
- Fix 'user.present' when 'gid_from_name' is set but group does
not exist.
- Added:
* bugfix-the-logic-according-to-the-exact-described-pu.patch
* return-error-when-gid_from_name-and-group-does-not-e.patch
-------------------------------------------------------------------
Thu Jan 11 15:57:11 UTC 2018 - jrenner@suse.com
- Fix "No service execution module loaded" issue (bsc#1065792)
- Set SHELL environment variable
Added:
* fix-bsc-1065792.patch
* set-shell-environment-variable-64.patch
-------------------------------------------------------------------
Fri Jan 05 15:24:30 UTC 2018 - jbreuer@suse.de
- Removed unnecessary logging on shutdown (bsc#1050003)
- Renamed patch that adds grain fqdns
Changed:
* catching-error-when-pidfile-cannot-be-deleted
Removed:
* fix-for-pidfile-removal-logging
Renamed:
* add-fqdns-grains -> feat-add-grain-for-all-fqdns
-------------------------------------------------------------------
Thu Dec 28 10:37:10 UTC 2017 - michele.bologna@suse.com
- Add fqdns to grains (bsc#1063419)
Added:
* add-fqdns-grains.patch
-------------------------------------------------------------------
Tue Dec 19 16:15:14 UTC 2017 - mc@suse.com
- Fixing cherrypy websocket with python3
Added:
* python3-compatibility-fix-got-bytes-instead-of-strin.patch
-------------------------------------------------------------------
Mon Dec 18 15:28:26 UTC 2017 - mihai.dinca@suse.com
- Various-bug-fixes
- Python3 bugfix for cherrypy read()
- Fix for logging on salt-master exit in rare cases (pid-file removal)
- Added:
* cherrypy-read-reads-bytes-from-the-wire-and-write-th.patch
* fix-for-pidfile-removal-logging.patch
* split-only-strings-if-they-are-such.patch
-------------------------------------------------------------------
Thu Dec 14 09:18:02 UTC 2017 - mihai.dinca@suse.com
- Fix salt-master for old psutil version
- Added:
* fix-salt-master-for-old-psutil.patch
-------------------------------------------------------------------
Wed Dec 13 16:23:38 UTC 2017 - mihai.dinca@suse.com
- Put back accidentally removed patches
- Added:
* avoid-excessive-syslogging-by-watchdog-cronjob-58.patch
* catching-error-when-pidfile-cannot-be-deleted.patch
-------------------------------------------------------------------
Wed Dec 13 16:22:25 UTC 2017 - mihai.dinca@suse.com
- Fix for delete_deployment in Kubernetes module (bsc#1059291)
- Added:
* fix-for-delete_deployment-in-kubernetes-module.patch
-------------------------------------------------------------------
Wed Dec 13 16:15:53 UTC 2017 - mihai.dinca@suse.com
- Older logrotate need su directive
* Added:
older-logrotate-need-su-directive.patch
-------------------------------------------------------------------
Wed Dec 13 16:10:32 UTC 2017 - mihai.dinca@suse.com
- Fix bsc#1041993 already included in 2017.7.2
- Removed:
* removes-beacon-configuration-deprecation-warning-48.patch
-------------------------------------------------------------------
Wed Dec 13 16:09:41 UTC 2017 - mihai.dinca@suse.com
- Fixed beacons failure when pillar-based suppressing config-based.
(bsc#1060230)
- Added:
* activate-all-beacons-sources-config-pillar-grains.patch
-------------------------------------------------------------------
Thu Dec 7 11:19:12 UTC 2017 - dimstar@opensuse.org

369
salt.spec
View File

@ -15,6 +15,22 @@
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
%if 0%{?suse_version} >= 1320
# SLE15
%global build_py3 1
%global build_py2 1
%global default_py3 1
%else
%if 0%{?suse_version} == 1315
# SLE12
%global build_py3 1
%global build_py2 1
%else
# RES7
%global build_py2 1
%endif
%endif
%define pythonX %{?default_py3: python3}%{!?default_py3: python2}
%if 0%{?suse_version} > 1210 || 0%{?rhel} >= 7 || 0%{?fedora}
%bcond_without systemd
@ -42,26 +58,196 @@ Summary: A parallel remote execution system
License: Apache-2.0
Group: System/Management
Url: http://saltstack.org/
# Git: https://github.com/openSUSE/salt.git
Source0: salt-2017.7.2.tar.gz
Source: https://github.com/saltstack/salt/archive/v%{version}.tar.gz
Source1: README.SUSE
Source2: salt-tmpfiles.d
Source3: html.tar.bz2
Source4: update-documentation.sh
Source5: travis.yml
Source6: zyppnotify
Patch1: list_pkgs-add-parameter-for-returned-attribute-selec.patch
Patch2: use-home-to-get-the-user-home-directory-instead-usin.patch
Patch3: multiprocessing-minion-option-documentation-fixes.patch
Patch4: introduce-process_count_max-minion-configuration-par.patch
Patch5: bugfix-always-return-a-string-list-on-unknown-job-ta.patch
Patch6: enable-with-salt-version-parameter-for-setup.py-scri.patch
Patch7: run-salt-master-as-dedicated-salt-user.patch
Patch8: run-salt-api-as-user-salt-bsc-1064520.patch
Patch1: list_pkgs-add-parameter-for-returned-attribute-selec.patch
Patch2: use-home-to-get-the-user-home-directory-instead-usin.patch
Patch3: multiprocessing-minion-option-documentation-fixes.patch
Patch4: introduce-process_count_max-minion-configuration-par.patch
Patch5: bugfix-always-return-a-string-list-on-unknown-job-ta.patch
Patch6: enable-with-salt-version-parameter-for-setup.py-scri.patch
Patch7: run-salt-master-as-dedicated-salt-user.patch
Patch8: run-salt-api-as-user-salt-bsc-1064520.patch
Patch9: activate-all-beacons-sources-config-pillar-grains.patch
Patch10: fix-for-delete_deployment-in-kubernetes-module.patch
Patch11: catching-error-when-pidfile-cannot-be-deleted.patch
Patch12: avoid-excessive-syslogging-by-watchdog-cronjob-58.patch
Patch13: fix-for-wrong-version-processing.patch
Patch14: older-logrotate-need-su-directive.patch
Patch15: fix-salt-master-for-old-psutil.patch
Patch16: split-only-strings-if-they-are-such.patch
Patch17: cherrypy-read-reads-bytes-from-the-wire-and-write-th.patch
Patch19: python3-compatibility-fix-got-bytes-instead-of-strin.patch
Patch20: feat-add-grain-for-all-fqdns.patch
Patch21: fix-bsc-1065792.patch
Patch22: set-shell-environment-variable-64.patch
Patch23: bugfix-the-logic-according-to-the-exact-described-pu.patch
Patch24: return-error-when-gid_from_name-and-group-does-not-e.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: logrotate
%if 0%{?suse_version} > 1020
BuildRequires: fdupes
%endif
Requires: %{pythonX}-%{name} = %{version}-%{release}
Requires(pre): %{_sbindir}/groupadd
Requires(pre): %{_sbindir}/useradd
%if 0%{?suse_version}
Requires(pre): %fillup_prereq
Requires(pre): pwdutils
%endif
%if 0%{?suse_version}
Requires(pre): dbus-1
%else
Requires(pre): dbus
%endif
Requires: logrotate
Requires: procps
%if %{with systemd}
BuildRequires: systemd
%{?systemd_requires}
%else
%if 0%{?suse_version}
Requires(pre): %insserv_prereq
%endif
%endif
%if %{with fish_completion}
%define fish_dir %{_datadir}/fish/
%define fish_completions_dir %{_datadir}/fish/completions/
%endif
%if %{with bash_completion}
%if 0%{?suse_version} >= 1140
BuildRequires: bash-completion
%else
BuildRequires: bash
%endif
%endif
%if %{with zsh_completion}
BuildRequires: zsh
%endif
%if 0%{?rhel}
BuildRequires: yum
%endif
%description
Salt is a distributed remote execution system used to execute commands and
query data. It was developed in order to bring the best solutions found in
the world of remote execution together and make them better, faster and more
malleable. Salt accomplishes this via its ability to handle larger loads of
information, and not just dozens, but hundreds or even thousands of individual
servers, handle them quickly and through a simple and manageable interface.
%if 0%{?build_py2}
%package -n python2-salt
Summary: python2 library for salt
Group: System/Management
Requires: %{name} = %{version}-%{release}
BuildRequires: python >= 2.7
BuildRequires: python-devel >= 2.7
# requirements/base.txt
%if 0%{?rhel}
BuildRequires: python-jinja2
BuildRequires: python-yaml
BuildRequires: python-markupsafe
%else
BuildRequires: python-Jinja2
BuildRequires: python-PyYAML
BuildRequires: python-MarkupSafe
%endif
BuildRequires: python-futures >= 2.0
BuildRequires: python-msgpack-python > 0.3
BuildRequires: python-psutil
BuildRequires: python-requests >= 1.0.0
BuildRequires: python-tornado >= 4.2.1
# requirements/zeromq.txt
BuildRequires: python-pycrypto >= 2.6.1
BuildRequires: python-pyzmq >= 2.2.0
%if %{with test}
# requirements/dev_python27.txt
BuildRequires: python-boto >= 2.32.1
BuildRequires: python-mock
BuildRequires: python-moto >= 0.3.6
BuildRequires: python-pip
BuildRequires: python-salt-testing >= 2015.2.16
BuildRequires: python-unittest2
BuildRequires: python-xml
%endif
%if %{with builddocs}
BuildRequires: python-sphinx
%endif
Requires: python >= 2.7
#
%if ! 0%{?suse_version} > 1110
Requires: python-certifi
%endif
# requirements/base.txt
%if 0%{?rhel}
Requires: python-jinja2
Requires: python-yaml
Requires: python-markupsafe
Requires: yum
%if 0%{?rhel} == 6
Requires: yum-plugin-security
%endif
%else
Requires: python-Jinja2
Requires: python-PyYAML
Requires: python-MarkupSafe
%endif
Requires: python-futures >= 2.0
Requires: python-msgpack-python > 0.3
Requires: python-psutil
Requires: python-requests >= 1.0.0
Requires: python-tornado >= 4.2.1
%if 0%{?suse_version}
# required for zypper.py
Requires: rpm-python
Requires(pre): libzypp(plugin:system) >= 0
Requires: zypp-plugin-python
# requirements/opt.txt (not all)
# Suggests: python-MySQL-python ## Disabled for now, originally Recommended
Suggests: python-timelib
Suggests: python-gnupg
# requirements/zeromq.txt
%endif
Requires: python-pycrypto >= 2.6.1
Requires: python-pyzmq >= 2.2.0
#
%if 0%{?suse_version}
# python-xml is part of python-base in all rhel versions
Requires: python-xml
Suggests: python-Mako
Recommends: python-netaddr
%endif
%description -n python2-salt
Python2 specific files for salt
%endif
%if 0%{?build_py3}
%package -n python3-salt
Summary: python3 library for salt
Group: System/Management
Requires: %{name} = %{version}-%{release}
BuildRequires: python-rpm-macros
BuildRequires: python3
BuildRequires: python3-devel
@ -94,26 +280,6 @@ BuildRequires: python3-xml
%if %{with builddocs}
BuildRequires: python3-sphinx
%endif
%if 0%{?suse_version} > 1020
BuildRequires: fdupes
%endif
Requires(pre): %{_sbindir}/groupadd
Requires(pre): %{_sbindir}/useradd
%if 0%{?suse_version}
Requires(pre): %fillup_prereq
Requires(pre): pwdutils
%endif
%if 0%{?suse_version}
Requires(pre): dbus-1
%else
Requires(pre): dbus
%endif
Requires: logrotate
Requires: procps
Requires: python3
#
%if ! 0%{?suse_version} > 1110
@ -156,50 +322,21 @@ Suggests: python3-Mako
Recommends: python3-netaddr
%endif
%if %{with systemd}
BuildRequires: systemd
%{?systemd_requires}
%else
%if 0%{?suse_version}
Requires(pre): %insserv_prereq
%endif
%endif
%description -n python3-salt
Python3 specific files for salt
%if %{with fish_completion}
%define fish_dir %{_datadir}/fish/
%define fish_completions_dir %{_datadir}/fish/completions/
%endif
%if %{with bash_completion}
%if 0%{?suse_version} >= 1140
BuildRequires: bash-completion
%else
BuildRequires: bash
%endif
%endif
%if %{with zsh_completion}
BuildRequires: zsh
%endif
%if 0%{?rhel}
BuildRequires: yum
%endif
%description
Salt is a distributed remote execution system used to execute commands and
query data. It was developed in order to bring the best solutions found in
the world of remote execution together and make them better, faster and more
malleable. Salt accomplishes this via its ability to handle larger loads of
information, and not just dozens, but hundreds or even thousands of individual
servers, handle them quickly and through a simple and manageable interface.
%package api
Summary: The api for Salt a parallel remote execution system
Group: System/Management
Requires: %{name} = %{version}-%{release}
Requires: %{name}-master = %{version}-%{release}
%if 0%{?default_py3}
Requires: python3-CherryPy >= 3.2.2
%else
Requires: python-CherryPy >= 3.2.2
%endif
%description api
salt-api is a modular interface on top of Salt that can provide a variety of entry points into a running Salt system.
@ -397,7 +534,6 @@ Zsh command line completion support for %{name}.
%setup -q -n salt-%{version}
cp %{S:1} .
cp %{S:5} ./.travis.yml
cp %{S:6} ./zyppnotify
%patch1 -p1
%patch2 -p1
%patch3 -p1
@ -406,10 +542,33 @@ cp %{S:6} ./zyppnotify
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%build
%if 0%{?build_py2}
%{__python} setup.py --with-salt-version=%{version} --salt-transport=both build
cp ./build/lib/salt/_version.py ./salt
mv build _build.python2
%endif
%if 0%{?build_py3}
%{__python3} setup.py --with-salt-version=%{version} --salt-transport=both build
cp ./build/lib/salt/_version.py ./salt
mv build _build.python3
%endif
%if %{with docs} && %{without builddocs}
# extract docs from the tarball
@ -425,7 +584,28 @@ cd doc && make html && rm _build/html/.buildinfo && rm _build/html/_images/proxy
%endif
%install
%if 0%{?build_py2}
mv _build.python2 build
%{__python} setup.py --salt-transport=both install --prefix=%{_prefix} --root=%{buildroot}
mv build _build.python2
%endif
%if 0%{?build_py3}
mv _build.python3 build
%{__python3} setup.py --salt-transport=both install --prefix=%{_prefix} --root=%{buildroot}
mv build _build.python3
%endif
%if 0%{?default_py3}
DEF_PYPATH=_build.python3/scripts-*/
%else
DEF_PYPATH=_build.python2/scripts-*/
%endif
rm -f %{buildroot}%{_bindir}/*
for script in $DEF_PYPATH/*; do
install -m 0755 $script %{buildroot}%{_bindir}
done
## create missing directories
install -Dd -m 0750 %{buildroot}%{_sysconfdir}/salt/master.d
install -Dd -m 0750 %{buildroot}%{_sysconfdir}/salt/minion.d
@ -468,24 +648,24 @@ install -Dd -m 0750 %{buildroot}%{_sysconfdir}/salt/pki/minion
## Install Zypper plugins only on SUSE machines
%if 0%{?suse_version}
install -Dd -m 0750 %{buildroot}%{_prefix}/lib/zypp/plugins/commit
%{__install} zyppnotify %{buildroot}%{_prefix}/lib/zypp/plugins/commit/zyppnotify
%{__install} scripts/suse/zypper/plugins/commit/zyppnotify %{buildroot}%{_prefix}/lib/zypp/plugins/commit/zyppnotify
%endif
# Install Yum plugins only on RH machines
%if 0%{?fedora} || 0%{?rhel}
install -Dd %{buildroot}%{_prefix}/share/yum-plugins
install -Dd %{buildroot}/etc/yum/pluginconf.d
%{__install} scripts/yum/plugins/yumnotify.py %{buildroot}%{_prefix}/share/yum-plugins
%{__install} scripts/yum/plugins/yumnotify.conf %{buildroot}/etc/yum/pluginconf.d
%{__install} scripts/suse/yum/plugins/yumnotify.py %{buildroot}%{_prefix}/share/yum-plugins
%{__install} scripts/suse/yum/plugins/yumnotify.conf %{buildroot}/etc/yum/pluginconf.d
%endif
## install init and systemd scripts
%if %{with systemd}
install -Dpm 0644 pkg/salt-master.service %{buildroot}%{_unitdir}/salt-master.service
install -Dpm 0644 pkg/suse/salt-master.service %{buildroot}%{_unitdir}/salt-master.service
%if 0%{?suse_version}
install -Dpm 0644 pkg/suse/salt-minion.service %{buildroot}%{_unitdir}/salt-minion.service
%else
install -Dpm 0644 pkg/salt-minion.service.rhel7 %{buildroot}%{_unitdir}/salt-minion.service
install -Dpm 0644 pkg/suse/salt-minion.service.rhel7 %{buildroot}%{_unitdir}/salt-minion.service
%endif
install -Dpm 0644 pkg/salt-syndic.service %{buildroot}%{_unitdir}/salt-syndic.service
install -Dpm 0644 pkg/suse/salt-api.service %{buildroot}%{_unitdir}/salt-api.service
@ -510,7 +690,7 @@ ln -sf %{_initddir}/salt-api %{buildroot}%{_sbindir}/rcsalt-api
## Install sysV salt-minion watchdog for SLES11 and RHEL6
%if 0%{?rhel} == 6 || 0%{?suse_version} == 1110
install -Dpm 0755 scripts/watchdog/salt-daemon-watcher %{buildroot}%{_bindir}/salt-daemon-watcher
install -Dpm 0755 scripts/suse/watchdog/salt-daemon-watcher %{buildroot}%{_bindir}/salt-daemon-watcher
%endif
#
@ -523,8 +703,12 @@ install -Dpm 0640 conf/cloud %{buildroot}%{_sysconfdir}/salt/cloud
install -Dpm 0640 conf/cloud.profiles %{buildroot}%{_sysconfdir}/salt/cloud.profiles
install -Dpm 0640 conf/cloud.providers %{buildroot}%{_sysconfdir}/salt/cloud.providers
#
## install logrotate file
## install logrotate file (for RHEL6 we use without sudo)
%if 0%{?rhel} > 6 || 0%{?suse_version}
install -Dpm 0644 pkg/suse/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
%else
install -Dpm 0644 pkg/salt-common.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/salt
%endif
#
## install SuSEfirewall2 rules
install -Dpm 0644 pkg/suse/salt.SuSEfirewall2 %{buildroot}%{_sysconfdir}/sysconfig/SuSEfirewall2.d/services/salt
@ -544,12 +728,21 @@ install -Dpm 0644 pkg/fish-completions/* %{buildroot}%{fish_completions_dir}
%if 0%{?suse_version} > 1020
%fdupes %{buildroot}%{_docdir}
%if 0%{?build_py2}
%fdupes %{buildroot}%{python_sitelib}
%endif
%if 0%{?build_py3}
%fdupes %{buildroot}%{python3_sitelib}
%endif
%endif
%check
%if %{with test}
python3 setup.py test --runtests-opts=-u
%if 0%{?default_py3}
%{__python3} setup.py test --runtests-opts=-u
%else
%{__python} setup.py test --runtests-opts=-u
%endif
%endif
%pre
@ -711,7 +904,7 @@ if [ $1 -eq 2 ] ; then
true
fi
%if %{with systemd}
if [ `rpm -q systemd --queryformat="%%{VERSION}"` -lt 228 ]; then
if [ `rpm -q systemd --queryformat="%{VERSION}"` -lt 228 ]; then
# On systemd < 228 the 'TasksTask' attribute is not available.
# Removing TasksMax from salt-master.service on SLE12SP1 LTSS (bsc#985112)
sed -i '/TasksMax=infinity/d' %{_unitdir}/salt-master.service
@ -873,8 +1066,13 @@ fi
%config(noreplace) %attr(0640, root, salt) %{_sysconfdir}/salt/cloud.profiles
%config(noreplace) %attr(0640, root, salt) %{_sysconfdir}/salt/cloud.providers
%dir %attr(0750, root, salt) %{_localstatedir}/cache/salt/cloud
%if 0%{?default_py3}
%{python3_sitelib}/salt/cloud/deploy/bootstrap-salt.sh
%attr(755,root,root)%{python3_sitelib}/salt/cloud/deploy/bootstrap-salt.sh
%else
%{python_sitelib}/salt/cloud/deploy/bootstrap-salt.sh
%attr(755,root,root)%{python_sitelib}/salt/cloud/deploy/bootstrap-salt.sh
%endif
%{_mandir}/man1/salt-cloud.1.*
%files ssh
@ -985,9 +1183,6 @@ fi
%{_mandir}/man1/salt-call.1.gz
%{_mandir}/man1/spm.1.gz
%config(noreplace) %{_sysconfdir}/logrotate.d/salt
%{python3_sitelib}/*
%exclude %{python3_sitelib}/salt/cloud/deploy/*.sh
%attr(755,root,root)%{python3_sitelib}/salt/cloud/deploy/*.sh
%doc LICENSE AUTHORS README.rst HACKING.rst README.SUSE
#
%dir %attr(0750, root, salt) %{_sysconfdir}/salt
@ -1001,6 +1196,20 @@ fi
%endif
%{_mandir}/man1/salt.1.*
%if 0%{?build_py2}
%files -n python2-salt
%defattr(-,root,root,-)
%{python_sitelib}/*
%exclude %{python_sitelib}/salt/cloud/deploy/*.sh
%endif
%if 0%{?build_py3}
%files -n python3-salt
%defattr(-,root,root,-)
%{python3_sitelib}/*
%exclude %{python3_sitelib}/salt/cloud/deploy/*.sh
%endif
%if %{with docs}
%files doc
%defattr(-,root,root)
@ -1030,3 +1239,5 @@ fi
%endif
%changelog

View File

@ -0,0 +1,25 @@
From 7f207ed0aa45063e90db2452a311b91f34b1b7e2 Mon Sep 17 00:00:00 2001
From: Johannes Renner <jrenner@suse.com>
Date: Thu, 11 Jan 2018 15:55:25 +0100
Subject: [PATCH] Set SHELL environment variable (#64)
---
pkg/suse/salt-api.service | 1 +
1 file changed, 1 insertion(+)
diff --git a/pkg/suse/salt-api.service b/pkg/suse/salt-api.service
index 6634b74a7d..5c73bb9022 100644
--- a/pkg/suse/salt-api.service
+++ b/pkg/suse/salt-api.service
@@ -6,6 +6,7 @@ After=network.target
[Service]
User=salt
Type=simple
+Environment=SHELL=/bin/bash
LimitNOFILE=8192
ExecStart=/usr/bin/salt-api
TimeoutStopSec=3
--
2.13.6

View File

@ -0,0 +1,50 @@
From 358d18a0cc635b04503d5392ce337227c1f191af Mon Sep 17 00:00:00 2001
From: Bo Maryniuk <bo@suse.de>
Date: Thu, 14 Dec 2017 14:43:52 +0100
Subject: [PATCH] Split only strings, if they are such
* Use unicode literals
* Lintfix: PEP8
See: https://bugzilla.suse.com/show_bug.cgi?id=1072218
https://github.com/saltstack/salt/pull/44991
---
salt/pillar/sql_base.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/salt/pillar/sql_base.py b/salt/pillar/sql_base.py
index e7abceb134..a59c45331f 100644
--- a/salt/pillar/sql_base.py
+++ b/salt/pillar/sql_base.py
@@ -168,7 +168,7 @@ More complete example for MySQL (to also show configuration)
as_list: True
with_lists: [1,3]
'''
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
# Please don't strip redundant parentheses from this file.
# I have added some for clarity.
@@ -275,7 +275,7 @@ class SqlBaseExtPillar(six.with_metaclass(abc.ABCMeta, object)):
# May set 'as_list' from qb[1][2].
else:
defaults.update(qb[1])
- if defaults['with_lists']:
+ if defaults['with_lists'] and isinstance(defaults['with_lists'], six.string_types):
defaults['with_lists'] = [
int(i) for i in defaults['with_lists'].split(',')
]
@@ -437,8 +437,7 @@ class SqlBaseExtPillar(six.with_metaclass(abc.ABCMeta, object)):
cursor.execute(details['query'], (minion_id,))
# Extract the field names the db has returned and process them
- self.process_fields([row[0] for row in cursor.description],
- details['depth'])
+ self.process_fields([row[0] for row in cursor.description], details['depth'])
self.enter_root(root)
self.as_list = details['as_list']
if details['with_lists']:
--
2.15.1

View File

@ -4,10 +4,35 @@
# Author: Bo Maryniuk <bo@suse.de>
#
NO_SPHINX_PARAM="--without-sphinx"
function build_virtenv() {
virtualenv --system-site-packages $1
source $1/bin/activate
pip install --upgrade pip
if [ -z "$2" ]; then
pip install -I Sphinx
fi
}
function check_env() {
for cmd in "sphinx-build" "make" "quilt"; do
if [[ -z "$1" || "$1" != "$NO_SPHINX_PARAM" ]] && [ ! -z "$(which sphinx-build 2>/dev/null)" ]; then
cat <<EOF
You've installed Spinx globally. But it might be outdated or
clash with the version I am going to install into the temporary
virtual environment from PIP.
Please consider to remove Sphinx from your system, perhaps?
Or pass me "$NO_SPHINX_PARAM" param so I will try reusing yours
and see what happens. :)
EOF
exit 1;
fi
for cmd in "make" "quilt" "virtualenv" "pip"; do
if [ -z "$(which $cmd 2>/dev/null)" ]; then
echo "Error: '$cmd' is missing."
echo "Error: '$cmd' is still missing. Install it, please."
exit 1;
fi
done
@ -26,7 +51,7 @@ function build_docs() {
cd _build/html
chmod -R -x+X *
cd ..
tar cvf - html | bzip2 > /tmp/html.tar.bz2
tar cvf - html | bzip2 > $2/html.tar.bz2
}
function write_changelog() {
@ -46,19 +71,30 @@ EOF
}
if [ -z "$1" ]; then
echo "Usage: $0 <your e-mail>"
echo "Usage: $0 <your e-mail> [--without-sphinx]"
exit 1;
fi
check_env;
check_env $2;
START=$(pwd)
V_ENV="sphinx_doc_gen"
V_TMP=$(mktemp -d)
for f in "salt.spec" "salt*tar.gz"; do
cp -v $f $V_TMP
done
cd $V_TMP;
build_virtenv $V_ENV $2;
SRC_DIR="salt-$(cat salt.spec | grep ^Version: | cut -d: -f2 | sed -e 's/[[:blank:]]//g')";
quilt_setup $SRC_DIR
build_docs doc
build_docs doc $V_TMP
cd $START
rm -rf $SRC_DIR
mv /tmp/html.tar.bz2 $START
mv $V_TMP/html.tar.bz2 $START
rm -rf $V_TMP
echo "Done"
echo "---------------"

View File

@ -2,7 +2,7 @@ From 418bcf80ca263c5523e701801e97bae60fdf9b35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
<psuarezhernandez@suse.com>
Date: Mon, 11 Sep 2017 19:57:28 +0200
Subject: [PATCH 2/6] Use $HOME to get the user home directory instead using
Subject: [PATCH] Use $HOME to get the user home directory instead using
'~' char
---
@ -24,5 +24,6 @@ index 480361fe23..00174c072f 100644
if [ ! -d "$(dirname ${_salt_cache_functions})" ]; then
--
2.14.2
2.15.1

3
v2017.7.2.tar.gz Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b9f9dd9ddd129ddadadf963178383b50c32283aeb1c338d9c23cc01b11722db2
size 11483585

View File

@ -1,59 +0,0 @@
#!/usr/bin/python3
#
# Copyright (c) 2016 SUSE Linux LLC
# All Rights Reserved.
#
# Author: Bo Maryniuk <bo@suse.de>
import sys
import os
import hashlib
from zypp_plugin import Plugin
class DriftDetector(Plugin):
"""
Return diff of the installed packages outside the Salt.
"""
def __init__(self):
Plugin.__init__(self)
self.ck_path = "/var/cache/salt/minion/rpmdb.cookie"
self.rpm_path = "/var/lib/rpm/Packages"
def _get_mtime(self):
'''
Get the modified time of the RPM Database.
Returns:
Unix ticks
'''
return os.path.exists(self.rpm_path) and int(os.path.getmtime(self.rpm_path)) or 0
def _get_checksum(self):
'''
Get the checksum of the RPM Database.
Returns:
hexdigest
'''
digest = hashlib.md5()
with open(self.rpm_path, "rb") as rpm_db_fh:
while True:
buff = rpm_db_fh.read(0x1000)
if not buff:
break
digest.update(buff)
return digest.hexdigest()
def PLUGINEND(self, headers, body):
"""
Hook when plugin closes Zypper's transaction.
"""
if 'SALT_RUNNING' not in os.environ:
with open(self.ck_path, 'w') as ck_fh:
ck_fh.write('{chksum} {mtime}\n'.format(chksum=self._get_checksum(), mtime=self._get_mtime()))
self.ack()
DriftDetector().main()