Accepting request 602524 from systemsmanagement:saltstack
OBS-URL: https://build.opensuse.org/request/show/602524 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/salt?expand=0&rev=75
This commit is contained in:
commit
68d26c0254
@ -1 +1 @@
|
|||||||
f43b8fb2425e3371decf3cde040c70ed15de375d
|
057b96d7f072dc69b61ca9e3b8d04a890003e58f
|
2
_service
2
_service
@ -3,7 +3,7 @@
|
|||||||
<param name="url">https://github.com/openSUSE/salt-packaging.git</param>
|
<param name="url">https://github.com/openSUSE/salt-packaging.git</param>
|
||||||
<param name="subdir">salt</param>
|
<param name="subdir">salt</param>
|
||||||
<param name="filename">package</param>
|
<param name="filename">package</param>
|
||||||
<param name="revision">oxygen-rc1</param>
|
<param name="revision">2018.3.0</param>
|
||||||
<param name="scm">git</param>
|
<param name="scm">git</param>
|
||||||
</service>
|
</service>
|
||||||
<service name="extract_file" mode="disabled">
|
<service name="extract_file" mode="disabled">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
From 7d3c1fee891a34f1e521228458ab113c3f6dabe1 Mon Sep 17 00:00:00 2001
|
From 36bc22560e050b7afe3d872aed99c0cdb9fde282 Mon Sep 17 00:00:00 2001
|
||||||
From: Bo Maryniuk <bo@suse.de>
|
From: Bo Maryniuk <bo@suse.de>
|
||||||
Date: Mon, 12 Mar 2018 12:01:39 +0100
|
Date: Mon, 12 Mar 2018 12:01:39 +0100
|
||||||
Subject: [PATCH] Add SaltSSH multi-version support across Python
|
Subject: [PATCH] Add SaltSSH multi-version support across Python
|
||||||
@ -227,16 +227,45 @@ Disable wiping if state is executed
|
|||||||
Properly mock a tempfile object
|
Properly mock a tempfile object
|
||||||
|
|
||||||
Support Python 2.6 versions
|
Support Python 2.6 versions
|
||||||
|
|
||||||
|
Add digest collector for file trees etc
|
||||||
|
|
||||||
|
Bufix: recurse calls damages the configuration (reference problem)
|
||||||
|
|
||||||
|
Collect digest of the code
|
||||||
|
|
||||||
|
Get code checksum into the shim options
|
||||||
|
|
||||||
|
Get all the code content, not just Python sources
|
||||||
|
|
||||||
|
Bugfix: Python3 compat - string required instead of bytes
|
||||||
|
|
||||||
|
Lintfix: too many empty lines
|
||||||
|
|
||||||
|
Lintfix: blocked function used
|
||||||
|
|
||||||
|
Bugfix: key error master_tops_first
|
||||||
|
|
||||||
|
Fix unit tests for the checksum generator
|
||||||
|
|
||||||
|
Use code checksum to update thin archive on client's cache
|
||||||
|
|
||||||
|
Lintfix
|
||||||
|
|
||||||
|
Set master_top_first to False by default
|
||||||
---
|
---
|
||||||
doc/topics/releases/fluorine.rst | 178 +++++++++++
|
doc/topics/releases/fluorine.rst | 178 +++++++++++
|
||||||
salt/client/ssh/__init__.py | 20 +-
|
salt/client/ssh/__init__.py | 66 ++--
|
||||||
salt/client/ssh/ssh_py_shim.py | 88 ++++--
|
salt/client/ssh/ssh_py_shim.py | 95 ++++--
|
||||||
salt/client/ssh/wrapper/__init__.py | 2 +-
|
salt/client/ssh/wrapper/__init__.py | 2 +-
|
||||||
|
salt/config/__init__.py | 1 +
|
||||||
salt/modules/zfs.py | 4 +-
|
salt/modules/zfs.py | 4 +-
|
||||||
salt/modules/zpool.py | 4 +-
|
salt/modules/zpool.py | 4 +-
|
||||||
salt/utils/thin.py | 434 +++++++++++++++++++-------
|
salt/state.py | 2 +-
|
||||||
tests/unit/utils/test_thin.py | 607 ++++++++++++++++++++++++++++++++++++
|
salt/utils/hashutils.py | 37 +++
|
||||||
8 files changed, 1182 insertions(+), 155 deletions(-)
|
salt/utils/thin.py | 450 +++++++++++++++++++-------
|
||||||
|
tests/unit/utils/test_thin.py | 612 ++++++++++++++++++++++++++++++++++++
|
||||||
|
11 files changed, 1265 insertions(+), 186 deletions(-)
|
||||||
create mode 100644 doc/topics/releases/fluorine.rst
|
create mode 100644 doc/topics/releases/fluorine.rst
|
||||||
create mode 100644 tests/unit/utils/test_thin.py
|
create mode 100644 tests/unit/utils/test_thin.py
|
||||||
|
|
||||||
@ -425,7 +454,7 @@ index 0000000000..40c69e25cc
|
|||||||
+Salt version is also available on the Master machine, although does not need to be directly
|
+Salt version is also available on the Master machine, although does not need to be directly
|
||||||
+installed together with the older Python interpreter.
|
+installed together with the older Python interpreter.
|
||||||
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
|
diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py
|
||||||
index f1c1ad9a22..ea5c700830 100644
|
index f1c1ad9a22..399facf5c8 100644
|
||||||
--- a/salt/client/ssh/__init__.py
|
--- a/salt/client/ssh/__init__.py
|
||||||
+++ b/salt/client/ssh/__init__.py
|
+++ b/salt/client/ssh/__init__.py
|
||||||
@@ -150,14 +150,10 @@ EX_PYTHON_INVALID={EX_THIN_PYTHON_INVALID}
|
@@ -150,14 +150,10 @@ EX_PYTHON_INVALID={EX_THIN_PYTHON_INVALID}
|
||||||
@ -470,16 +499,71 @@ index f1c1ad9a22..ea5c700830 100644
|
|||||||
if kwargs.get('thin_dir'):
|
if kwargs.get('thin_dir'):
|
||||||
self.thin_dir = kwargs['thin_dir']
|
self.thin_dir = kwargs['thin_dir']
|
||||||
elif self.winrm:
|
elif self.winrm:
|
||||||
@@ -1168,7 +1165,6 @@ class Single(object):
|
@@ -1161,38 +1158,39 @@ class Single(object):
|
||||||
|
cachedir = self.opts['_caller_cachedir']
|
||||||
|
else:
|
||||||
|
cachedir = self.opts['cachedir']
|
||||||
|
- thin_sum = salt.utils.thin.thin_sum(cachedir, 'sha1')
|
||||||
|
+ thin_code_digest, thin_sum = salt.utils.thin.thin_sum(cachedir, 'sha1')
|
||||||
|
debug = ''
|
||||||
|
if not self.opts.get('log_level'):
|
||||||
|
self.opts['log_level'] = 'info'
|
||||||
if salt.log.LOG_LEVELS['debug'] >= salt.log.LOG_LEVELS[self.opts.get('log_level', 'info')]:
|
if salt.log.LOG_LEVELS['debug'] >= salt.log.LOG_LEVELS[self.opts.get('log_level', 'info')]:
|
||||||
debug = '1'
|
debug = '1'
|
||||||
arg_str = '''
|
arg_str = '''
|
||||||
-OPTIONS = OBJ()
|
-OPTIONS = OBJ()
|
||||||
OPTIONS.config = \
|
OPTIONS.config = \
|
||||||
"""
|
"""
|
||||||
{0}
|
-{0}
|
||||||
|
+{config}
|
||||||
|
"""
|
||||||
|
-OPTIONS.delimiter = '{1}'
|
||||||
|
-OPTIONS.saltdir = '{2}'
|
||||||
|
-OPTIONS.checksum = '{3}'
|
||||||
|
-OPTIONS.hashfunc = '{4}'
|
||||||
|
-OPTIONS.version = '{5}'
|
||||||
|
-OPTIONS.ext_mods = '{6}'
|
||||||
|
-OPTIONS.wipe = {7}
|
||||||
|
-OPTIONS.tty = {8}
|
||||||
|
-OPTIONS.cmd_umask = {9}
|
||||||
|
-ARGS = {10}\n'''.format(self.minion_config,
|
||||||
|
- RSTR,
|
||||||
|
- self.thin_dir,
|
||||||
|
- thin_sum,
|
||||||
|
- 'sha1',
|
||||||
|
- salt.version.__version__,
|
||||||
|
- self.mods.get('version', ''),
|
||||||
|
- self.wipe,
|
||||||
|
- self.tty,
|
||||||
|
- self.cmd_umask,
|
||||||
|
- self.argv)
|
||||||
|
+OPTIONS.delimiter = '{delimeter}'
|
||||||
|
+OPTIONS.saltdir = '{saltdir}'
|
||||||
|
+OPTIONS.checksum = '{checksum}'
|
||||||
|
+OPTIONS.hashfunc = '{hashfunc}'
|
||||||
|
+OPTIONS.version = '{version}'
|
||||||
|
+OPTIONS.ext_mods = '{ext_mods}'
|
||||||
|
+OPTIONS.wipe = {wipe}
|
||||||
|
+OPTIONS.tty = {tty}
|
||||||
|
+OPTIONS.cmd_umask = {cmd_umask}
|
||||||
|
+OPTIONS.code_checksum = {code_checksum}
|
||||||
|
+ARGS = {arguments}\n'''.format(config=self.minion_config,
|
||||||
|
+ delimeter=RSTR,
|
||||||
|
+ saltdir=self.thin_dir,
|
||||||
|
+ checksum=thin_sum,
|
||||||
|
+ hashfunc='sha1',
|
||||||
|
+ version=salt.version.__version__,
|
||||||
|
+ ext_mods=self.mods.get('version', ''),
|
||||||
|
+ wipe=self.wipe,
|
||||||
|
+ tty=self.tty,
|
||||||
|
+ cmd_umask=self.cmd_umask,
|
||||||
|
+ code_checksum=thin_code_digest,
|
||||||
|
+ arguments=self.argv)
|
||||||
|
py_code = SSH_PY_SHIM.replace('#%%OPTS', arg_str)
|
||||||
|
if six.PY2:
|
||||||
|
py_code_enc = py_code.encode('base64')
|
||||||
diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py
|
diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py
|
||||||
index e46220fc80..661a671b81 100644
|
index e46220fc80..21d03343b9 100644
|
||||||
--- a/salt/client/ssh/ssh_py_shim.py
|
--- a/salt/client/ssh/ssh_py_shim.py
|
||||||
+++ b/salt/client/ssh/ssh_py_shim.py
|
+++ b/salt/client/ssh/ssh_py_shim.py
|
||||||
@@ -16,11 +16,13 @@ import sys
|
@@ -16,11 +16,13 @@ import sys
|
||||||
@ -587,7 +671,7 @@ index e46220fc80..661a671b81 100644
|
|||||||
def main(argv): # pylint: disable=W0613
|
def main(argv): # pylint: disable=W0613
|
||||||
'''
|
'''
|
||||||
Main program body
|
Main program body
|
||||||
@@ -215,30 +261,30 @@ def main(argv): # pylint: disable=W0613
|
@@ -215,32 +261,25 @@ def main(argv): # pylint: disable=W0613
|
||||||
if scpstat != 0:
|
if scpstat != 0:
|
||||||
sys.exit(EX_SCP_NOT_FOUND)
|
sys.exit(EX_SCP_NOT_FOUND)
|
||||||
|
|
||||||
@ -604,33 +688,35 @@ index e46220fc80..661a671b81 100644
|
|||||||
|
|
||||||
- version_path = os.path.normpath(os.path.join(OPTIONS.saltdir, 'version'))
|
- version_path = os.path.normpath(os.path.join(OPTIONS.saltdir, 'version'))
|
||||||
- if not os.path.exists(version_path) or not os.path.isfile(version_path):
|
- if not os.path.exists(version_path) or not os.path.isfile(version_path):
|
||||||
+ if not os.path.exists(OPTIONS.saltdir):
|
- sys.stderr.write(
|
||||||
+ need_deployment()
|
- 'WARNING: Unable to locate current thin '
|
||||||
+
|
|
||||||
+ checksum_path = os.path.normpath(os.path.join(OPTIONS.saltdir, 'thin_checksum'))
|
|
||||||
+ if not os.path.exists(checksum_path) or not os.path.isfile(checksum_path):
|
|
||||||
sys.stderr.write(
|
|
||||||
'WARNING: Unable to locate current thin '
|
|
||||||
- ' version: {0}.\n'.format(version_path)
|
- ' version: {0}.\n'.format(version_path)
|
||||||
+ ' checksum: {0}.\n'.format(checksum_path)
|
- )
|
||||||
)
|
+ if not os.path.exists(OPTIONS.saltdir):
|
||||||
need_deployment()
|
need_deployment()
|
||||||
- with open(version_path, 'r') as vpo:
|
- with open(version_path, 'r') as vpo:
|
||||||
- cur_version = vpo.readline().strip()
|
- cur_version = vpo.readline().strip()
|
||||||
- if cur_version != OPTIONS.version:
|
- if cur_version != OPTIONS.version:
|
||||||
+ with open(checksum_path, 'r') as vpo:
|
- sys.stderr.write(
|
||||||
+ cur_checksum = vpo.readline().strip()
|
|
||||||
+ if cur_checksum != OPTIONS.checksum:
|
|
||||||
sys.stderr.write(
|
|
||||||
- 'WARNING: current thin version {0}'
|
- 'WARNING: current thin version {0}'
|
||||||
+ 'WARNING: current thin checksum {0}'
|
- ' is not up-to-date with {1}.\n'.format(
|
||||||
' is not up-to-date with {1}.\n'.format(
|
|
||||||
- cur_version, OPTIONS.version
|
- cur_version, OPTIONS.version
|
||||||
+ cur_checksum, OPTIONS.checksum
|
- )
|
||||||
)
|
- )
|
||||||
)
|
+
|
||||||
|
+ code_checksum_path = os.path.normpath(os.path.join(OPTIONS.saltdir, 'code-checksum'))
|
||||||
|
+ if not os.path.exists(code_checksum_path) or not os.path.isfile(code_checksum_path):
|
||||||
|
+ sys.stderr.write('WARNING: Unable to locate current code checksum: {0}.\n'.format(code_checksum_path))
|
||||||
|
+ need_deployment()
|
||||||
|
+ with open(code_checksum_path, 'r') as vpo:
|
||||||
|
+ cur_code_cs = vpo.readline().strip()
|
||||||
|
+ if cur_code_cs != OPTIONS.code_checksum:
|
||||||
|
+ sys.stderr.write('WARNING: current code checksum {0} is different to {1}.\n'.format(cur_code_cs,
|
||||||
|
+ OPTIONS.code_checksum))
|
||||||
need_deployment()
|
need_deployment()
|
||||||
@@ -270,7 +316,7 @@ def main(argv): # pylint: disable=W0613
|
# Salt thin exists and is up-to-date - fall through and use it
|
||||||
|
|
||||||
|
@@ -270,7 +309,7 @@ def main(argv): # pylint: disable=W0613
|
||||||
argv_prepared = ARGS
|
argv_prepared = ARGS
|
||||||
|
|
||||||
salt_argv = [
|
salt_argv = [
|
||||||
@ -639,7 +725,7 @@ index e46220fc80..661a671b81 100644
|
|||||||
salt_call_path,
|
salt_call_path,
|
||||||
'--retcode-passthrough',
|
'--retcode-passthrough',
|
||||||
'--local',
|
'--local',
|
||||||
@@ -303,7 +349,10 @@ def main(argv): # pylint: disable=W0613
|
@@ -303,7 +342,10 @@ def main(argv): # pylint: disable=W0613
|
||||||
if OPTIONS.tty:
|
if OPTIONS.tty:
|
||||||
# Returns bytes instead of string on python 3
|
# Returns bytes instead of string on python 3
|
||||||
stdout, _ = subprocess.Popen(salt_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
stdout, _ = subprocess.Popen(salt_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||||
@ -651,7 +737,7 @@ index e46220fc80..661a671b81 100644
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if OPTIONS.wipe:
|
if OPTIONS.wipe:
|
||||||
shutil.rmtree(OPTIONS.saltdir)
|
shutil.rmtree(OPTIONS.saltdir)
|
||||||
@@ -315,5 +364,6 @@ def main(argv): # pylint: disable=W0613
|
@@ -315,5 +357,6 @@ def main(argv): # pylint: disable=W0613
|
||||||
if OPTIONS.cmd_umask is not None:
|
if OPTIONS.cmd_umask is not None:
|
||||||
os.umask(old_umask)
|
os.umask(old_umask)
|
||||||
|
|
||||||
@ -671,6 +757,18 @@ index 04d751b51a..09f9344642 100644
|
|||||||
fsclient=self.fsclient,
|
fsclient=self.fsclient,
|
||||||
minion_opts=self.minion_opts,
|
minion_opts=self.minion_opts,
|
||||||
**self.kwargs
|
**self.kwargs
|
||||||
|
diff --git a/salt/config/__init__.py b/salt/config/__init__.py
|
||||||
|
index df0e1388b7..b3de3820b0 100644
|
||||||
|
--- a/salt/config/__init__.py
|
||||||
|
+++ b/salt/config/__init__.py
|
||||||
|
@@ -1652,6 +1652,7 @@ DEFAULT_MASTER_OPTS = {
|
||||||
|
'state_top': 'top.sls',
|
||||||
|
'state_top_saltenv': None,
|
||||||
|
'master_tops': {},
|
||||||
|
+ 'master_tops_first': False,
|
||||||
|
'order_masters': False,
|
||||||
|
'job_cache': True,
|
||||||
|
'ext_job_cache': '',
|
||||||
diff --git a/salt/modules/zfs.py b/salt/modules/zfs.py
|
diff --git a/salt/modules/zfs.py b/salt/modules/zfs.py
|
||||||
index bc54044b5c..d8fbfc76be 100644
|
index bc54044b5c..d8fbfc76be 100644
|
||||||
--- a/salt/modules/zfs.py
|
--- a/salt/modules/zfs.py
|
||||||
@ -705,8 +803,73 @@ index f955175664..5e03418919 100644
|
|||||||
|
|
||||||
|
|
||||||
@salt.utils.decorators.memoize
|
@salt.utils.decorators.memoize
|
||||||
|
diff --git a/salt/state.py b/salt/state.py
|
||||||
|
index 49d68d2edf..8c0b90545c 100644
|
||||||
|
--- a/salt/state.py
|
||||||
|
+++ b/salt/state.py
|
||||||
|
@@ -3332,7 +3332,7 @@ class BaseHighState(object):
|
||||||
|
ext_matches = self._master_tops()
|
||||||
|
for saltenv in ext_matches:
|
||||||
|
top_file_matches = matches.get(saltenv, [])
|
||||||
|
- if self.opts['master_tops_first']:
|
||||||
|
+ if self.opts.get('master_tops_first'):
|
||||||
|
first = ext_matches[saltenv]
|
||||||
|
second = top_file_matches
|
||||||
|
else:
|
||||||
|
diff --git a/salt/utils/hashutils.py b/salt/utils/hashutils.py
|
||||||
|
index 4c9cb4a50c..18f7459d3c 100644
|
||||||
|
--- a/salt/utils/hashutils.py
|
||||||
|
+++ b/salt/utils/hashutils.py
|
||||||
|
@@ -9,6 +9,7 @@ import base64
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import random
|
||||||
|
+import os
|
||||||
|
|
||||||
|
# Import Salt libs
|
||||||
|
from salt.ext import six
|
||||||
|
@@ -163,3 +164,39 @@ def get_hash(path, form='sha256', chunk_size=65536):
|
||||||
|
for chunk in iter(lambda: ifile.read(chunk_size), b''):
|
||||||
|
hash_obj.update(chunk)
|
||||||
|
return hash_obj.hexdigest()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class DigestCollector(object):
|
||||||
|
+ '''
|
||||||
|
+ Class to collect digest of the file tree.
|
||||||
|
+ '''
|
||||||
|
+
|
||||||
|
+ def __init__(self, form='sha256', buff=0x10000):
|
||||||
|
+ '''
|
||||||
|
+ Constructor of the class.
|
||||||
|
+ :param form:
|
||||||
|
+ '''
|
||||||
|
+ self.__digest = hasattr(hashlib, form) and getattr(hashlib, form)() or None
|
||||||
|
+ if self.__digest is None:
|
||||||
|
+ raise ValueError('Invalid hash type: {0}'.format(form))
|
||||||
|
+ self.__buff = buff
|
||||||
|
+
|
||||||
|
+ def add(self, path):
|
||||||
|
+ '''
|
||||||
|
+ Update digest with the file content by path.
|
||||||
|
+
|
||||||
|
+ :param path:
|
||||||
|
+ :return:
|
||||||
|
+ '''
|
||||||
|
+ with salt.utils.files.fopen(path, 'rb') as ifile:
|
||||||
|
+ for chunk in iter(lambda: ifile.read(self.__buff), b''):
|
||||||
|
+ self.__digest.update(chunk)
|
||||||
|
+
|
||||||
|
+ def digest(self):
|
||||||
|
+ '''
|
||||||
|
+ Get digest.
|
||||||
|
+
|
||||||
|
+ :return:
|
||||||
|
+ '''
|
||||||
|
+
|
||||||
|
+ return salt.utils.stringutils.to_str(self.__digest.hexdigest() + os.linesep)
|
||||||
diff --git a/salt/utils/thin.py b/salt/utils/thin.py
|
diff --git a/salt/utils/thin.py b/salt/utils/thin.py
|
||||||
index 4c0969ea96..a6990d00b1 100644
|
index 4c0969ea96..e4b878eb19 100644
|
||||||
--- a/salt/utils/thin.py
|
--- a/salt/utils/thin.py
|
||||||
+++ b/salt/utils/thin.py
|
+++ b/salt/utils/thin.py
|
||||||
@@ -8,11 +8,14 @@ from __future__ import absolute_import, print_function, unicode_literals
|
@@ -8,11 +8,14 @@ from __future__ import absolute_import, print_function, unicode_literals
|
||||||
@ -849,7 +1012,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
|
|
||||||
|
|
||||||
def thin_path(cachedir):
|
def thin_path(cachedir):
|
||||||
@@ -101,29 +133,136 @@ def thin_path(cachedir):
|
@@ -101,29 +133,137 @@ def thin_path(cachedir):
|
||||||
return os.path.join(cachedir, 'thin', 'thin.tgz')
|
return os.path.join(cachedir, 'thin', 'thin.tgz')
|
||||||
|
|
||||||
|
|
||||||
@ -878,7 +1041,9 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
+def _add_dependency(container, obj):
|
+def _add_dependency(container, obj):
|
||||||
+ '''
|
+ '''
|
||||||
+ Add a dependency to the top list.
|
+ Add a dependency to the top list.
|
||||||
+
|
|
||||||
|
- tops.append(_six.__file__.replace('.pyc', '.py'))
|
||||||
|
- tops.append(backports_abc.__file__.replace('.pyc', '.py'))
|
||||||
+ :param obj:
|
+ :param obj:
|
||||||
+ :param is_file:
|
+ :param is_file:
|
||||||
+ :return:
|
+ :return:
|
||||||
@ -893,23 +1058,32 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
+ '''
|
+ '''
|
||||||
+ This function is called externally from the alternative
|
+ This function is called externally from the alternative
|
||||||
+ Python interpreter from within _get_tops function.
|
+ Python interpreter from within _get_tops function.
|
||||||
+
|
|
||||||
|
- if HAS_CERTIFI:
|
||||||
|
- tops.append(os.path.dirname(certifi.__file__))
|
||||||
+ :param extra_mods:
|
+ :param extra_mods:
|
||||||
+ :param so_mods:
|
+ :param so_mods:
|
||||||
+ :return:
|
+ :return:
|
||||||
+ '''
|
+ '''
|
||||||
+ extra = salt.utils.json.loads(sys.argv[1])
|
+ extra = salt.utils.json.loads(sys.argv[1])
|
||||||
+ tops = get_tops(**extra)
|
+ tops = get_tops(**extra)
|
||||||
+
|
|
||||||
|
- if HAS_SINGLEDISPATCH:
|
||||||
|
- tops.append(singledispatch.__file__.replace('.pyc', '.py'))
|
||||||
+ return salt.utils.json.dumps(tops, ensure_ascii=False)
|
+ return salt.utils.json.dumps(tops, ensure_ascii=False)
|
||||||
+
|
|
||||||
+
|
- if HAS_SINGLEDISPATCH_HELPERS:
|
||||||
|
- tops.append(singledispatch_helpers.__file__.replace('.pyc', '.py'))
|
||||||
|
|
||||||
|
- if HAS_SSL_MATCH_HOSTNAME:
|
||||||
|
- tops.append(os.path.dirname(os.path.dirname(ssl_match_hostname.__file__)))
|
||||||
+def get_ext_tops(config):
|
+def get_ext_tops(config):
|
||||||
+ '''
|
+ '''
|
||||||
+ Get top directories for the dependencies, based on external configuration.
|
+ Get top directories for the dependencies, based on external configuration.
|
||||||
+
|
+
|
||||||
+ :return:
|
+ :return:
|
||||||
+ '''
|
+ '''
|
||||||
|
+ config = copy.deepcopy(config)
|
||||||
+ alternatives = {}
|
+ alternatives = {}
|
||||||
+ required = ['jinja2', 'yaml', 'tornado', 'msgpack']
|
+ required = ['jinja2', 'yaml', 'tornado', 'msgpack']
|
||||||
+ tops = []
|
+ tops = []
|
||||||
@ -958,9 +1132,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
+def _get_ext_namespaces(config):
|
+def _get_ext_namespaces(config):
|
||||||
+ '''
|
+ '''
|
||||||
+ Get namespaces from the existing configuration.
|
+ Get namespaces from the existing configuration.
|
||||||
|
+
|
||||||
- tops.append(_six.__file__.replace('.pyc', '.py'))
|
|
||||||
- tops.append(backports_abc.__file__.replace('.pyc', '.py'))
|
|
||||||
+ :param config:
|
+ :param config:
|
||||||
+ :return:
|
+ :return:
|
||||||
+ '''
|
+ '''
|
||||||
@ -975,22 +1147,14 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
+ "to what Python's major/minor version it should be constrained.")
|
+ "to what Python's major/minor version it should be constrained.")
|
||||||
+ else:
|
+ else:
|
||||||
+ namespaces[ns] = constraint_version
|
+ namespaces[ns] = constraint_version
|
||||||
|
+
|
||||||
- if HAS_CERTIFI:
|
|
||||||
- tops.append(os.path.dirname(certifi.__file__))
|
|
||||||
+ return namespaces
|
+ return namespaces
|
||||||
|
+
|
||||||
- if HAS_SINGLEDISPATCH:
|
+
|
||||||
- tops.append(singledispatch.__file__.replace('.pyc', '.py'))
|
|
||||||
|
|
||||||
- if HAS_SINGLEDISPATCH_HELPERS:
|
|
||||||
- tops.append(singledispatch_helpers.__file__.replace('.pyc', '.py'))
|
|
||||||
+def get_tops(extra_mods='', so_mods=''):
|
+def get_tops(extra_mods='', so_mods=''):
|
||||||
+ '''
|
+ '''
|
||||||
+ Get top directories for the dependencies, based on Python interpreter.
|
+ Get top directories for the dependencies, based on Python interpreter.
|
||||||
|
+
|
||||||
- if HAS_SSL_MATCH_HOSTNAME:
|
|
||||||
- tops.append(os.path.dirname(os.path.dirname(ssl_match_hostname.__file__)))
|
|
||||||
+ :param extra_mods:
|
+ :param extra_mods:
|
||||||
+ :param so_mods:
|
+ :param so_mods:
|
||||||
+ :return:
|
+ :return:
|
||||||
@ -1004,7 +1168,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
|
|
||||||
for mod in [m for m in extra_mods.split(',') if m]:
|
for mod in [m for m in extra_mods.split(',') if m]:
|
||||||
if mod not in locals() and mod not in globals():
|
if mod not in locals() and mod not in globals():
|
||||||
@@ -135,28 +274,49 @@ def get_tops(extra_mods='', so_mods=''):
|
@@ -135,28 +275,49 @@ def get_tops(extra_mods='', so_mods=''):
|
||||||
tops.append(moddir)
|
tops.append(moddir)
|
||||||
else:
|
else:
|
||||||
tops.append(os.path.join(moddir, base + '.py'))
|
tops.append(os.path.join(moddir, base + '.py'))
|
||||||
@ -1066,7 +1230,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
'''
|
'''
|
||||||
Generate the salt-thin tarball and print the location of the tarball
|
Generate the salt-thin tarball and print the location of the tarball
|
||||||
Optional additional mods to include (e.g. mako) can be supplied as a comma
|
Optional additional mods to include (e.g. mako) can be supplied as a comma
|
||||||
@@ -171,19 +331,24 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
@@ -171,19 +332,26 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
||||||
salt-run thin.generate mako,wempy 1
|
salt-run thin.generate mako,wempy 1
|
||||||
salt-run thin.generate overwrite=1
|
salt-run thin.generate overwrite=1
|
||||||
'''
|
'''
|
||||||
@ -1089,6 +1253,8 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
pythinver = os.path.join(thindir, '.thin-gen-py-version')
|
pythinver = os.path.join(thindir, '.thin-gen-py-version')
|
||||||
salt_call = os.path.join(thindir, 'salt-call')
|
salt_call = os.path.join(thindir, 'salt-call')
|
||||||
+ pymap_cfg = os.path.join(thindir, 'supported-versions')
|
+ pymap_cfg = os.path.join(thindir, 'supported-versions')
|
||||||
|
+ code_checksum = os.path.join(thindir, 'code-checksum')
|
||||||
|
+ digest_collector = salt.utils.hashutils.DigestCollector()
|
||||||
+
|
+
|
||||||
with salt.utils.files.fopen(salt_call, 'wb') as fp_:
|
with salt.utils.files.fopen(salt_call, 'wb') as fp_:
|
||||||
- fp_.write(SALTCALL)
|
- fp_.write(SALTCALL)
|
||||||
@ -1097,7 +1263,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
if os.path.isfile(thintar):
|
if os.path.isfile(thintar):
|
||||||
if not overwrite:
|
if not overwrite:
|
||||||
if os.path.isfile(thinver):
|
if os.path.isfile(thinver):
|
||||||
@@ -197,85 +362,88 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
@@ -197,85 +365,88 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
||||||
|
|
||||||
if overwrite:
|
if overwrite:
|
||||||
try:
|
try:
|
||||||
@ -1225,7 +1391,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
for py_ver, tops in _six.iteritems(tops_py_version_mapping):
|
for py_ver, tops in _six.iteritems(tops_py_version_mapping):
|
||||||
for top in tops:
|
for top in tops:
|
||||||
if absonly and not os.path.isabs(top):
|
if absonly and not os.path.isabs(top):
|
||||||
@@ -291,48 +459,76 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
@@ -291,48 +462,80 @@ def gen_thin(cachedir, extra_mods='', overwrite=False, so_mods='',
|
||||||
egg.extractall(tempdir)
|
egg.extractall(tempdir)
|
||||||
top = os.path.join(tempdir, base)
|
top = os.path.join(tempdir, base)
|
||||||
os.chdir(tempdir)
|
os.chdir(tempdir)
|
||||||
@ -1249,6 +1415,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
- tfp.add(os.path.join(root, name),
|
- tfp.add(os.path.join(root, name),
|
||||||
- arcname=os.path.join('py{0}'.format(py_ver), root, name))
|
- arcname=os.path.join('py{0}'.format(py_ver), root, name))
|
||||||
- elif compress == 'zip':
|
- elif compress == 'zip':
|
||||||
|
+ digest_collector.add(os.path.join(root, name))
|
||||||
+ arcname = os.path.join(site_pkg_dir, root, name)
|
+ arcname = os.path.join(site_pkg_dir, root, name)
|
||||||
+ if hasattr(tfp, 'getinfo'):
|
+ if hasattr(tfp, 'getinfo'):
|
||||||
try:
|
try:
|
||||||
@ -1285,6 +1452,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
+ for root, dirs, files in salt.utils.path.os_walk(base, followlinks=True):
|
+ for root, dirs, files in salt.utils.path.os_walk(base, followlinks=True):
|
||||||
+ for name in files:
|
+ for name in files:
|
||||||
+ if not name.endswith(('.pyc', '.pyo')):
|
+ if not name.endswith(('.pyc', '.pyo')):
|
||||||
|
+ digest_collector.add(os.path.join(root, name))
|
||||||
+ arcname = os.path.join(ns, site_pkg_dir, root, name)
|
+ arcname = os.path.join(ns, site_pkg_dir, root, name)
|
||||||
+ if hasattr(tfp, 'getinfo'):
|
+ if hasattr(tfp, 'getinfo'):
|
||||||
+ try:
|
+ try:
|
||||||
@ -1305,6 +1473,8 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
with salt.utils.files.fopen(pythinver, 'w+') as fp_:
|
with salt.utils.files.fopen(pythinver, 'w+') as fp_:
|
||||||
- fp_.write(str(sys.version_info[0])) # future lint: disable=blacklisted-function
|
- fp_.write(str(sys.version_info[0])) # future lint: disable=blacklisted-function
|
||||||
+ fp_.write(str(sys.version_info.major)) # future lint: disable=blacklisted-function
|
+ fp_.write(str(sys.version_info.major)) # future lint: disable=blacklisted-function
|
||||||
|
+ with salt.utils.files.fopen(code_checksum, 'w+') as fp_:
|
||||||
|
+ fp_.write(digest_collector.digest())
|
||||||
os.chdir(os.path.dirname(thinver))
|
os.chdir(os.path.dirname(thinver))
|
||||||
- if compress == 'gzip':
|
- if compress == 'gzip':
|
||||||
- tfp.add('version')
|
- tfp.add('version')
|
||||||
@ -1313,7 +1483,7 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
- tfp.write('version')
|
- tfp.write('version')
|
||||||
- tfp.write('.thin-gen-py-version')
|
- tfp.write('.thin-gen-py-version')
|
||||||
+
|
+
|
||||||
+ for fname in ['version', '.thin-gen-py-version', 'salt-call', 'supported-versions']:
|
+ for fname in ['version', '.thin-gen-py-version', 'salt-call', 'supported-versions', 'code-checksum']:
|
||||||
+ tfp.add(fname)
|
+ tfp.add(fname)
|
||||||
+
|
+
|
||||||
if start_dir:
|
if start_dir:
|
||||||
@ -1323,7 +1493,23 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
return thintar
|
return thintar
|
||||||
|
|
||||||
|
|
||||||
@@ -368,7 +564,7 @@ def gen_min(cachedir, extra_mods='', overwrite=False, so_mods='',
|
@@ -341,7 +544,14 @@ def thin_sum(cachedir, form='sha1'):
|
||||||
|
Return the checksum of the current thin tarball
|
||||||
|
'''
|
||||||
|
thintar = gen_thin(cachedir)
|
||||||
|
- return salt.utils.hashutils.get_hash(thintar, form)
|
||||||
|
+ code_checksum_path = os.path.join(cachedir, 'thin', 'code-checksum')
|
||||||
|
+ if os.path.isfile(code_checksum_path):
|
||||||
|
+ with salt.utils.fopen(code_checksum_path, 'r') as fh:
|
||||||
|
+ code_checksum = "'{0}'".format(fh.read().strip())
|
||||||
|
+ else:
|
||||||
|
+ code_checksum = "'0'"
|
||||||
|
+
|
||||||
|
+ return code_checksum, salt.utils.hashutils.get_hash(thintar, form)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_min(cachedir, extra_mods='', overwrite=False, so_mods='',
|
||||||
|
@@ -368,7 +578,7 @@ def gen_min(cachedir, extra_mods='', overwrite=False, so_mods='',
|
||||||
pyminver = os.path.join(mindir, '.min-gen-py-version')
|
pyminver = os.path.join(mindir, '.min-gen-py-version')
|
||||||
salt_call = os.path.join(mindir, 'salt-call')
|
salt_call = os.path.join(mindir, 'salt-call')
|
||||||
with salt.utils.files.fopen(salt_call, 'wb') as fp_:
|
with salt.utils.files.fopen(salt_call, 'wb') as fp_:
|
||||||
@ -1334,10 +1520,10 @@ index 4c0969ea96..a6990d00b1 100644
|
|||||||
if os.path.isfile(minver):
|
if os.path.isfile(minver):
|
||||||
diff --git a/tests/unit/utils/test_thin.py b/tests/unit/utils/test_thin.py
|
diff --git a/tests/unit/utils/test_thin.py b/tests/unit/utils/test_thin.py
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..8157eefed8
|
index 0000000000..549d48a703
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/tests/unit/utils/test_thin.py
|
+++ b/tests/unit/utils/test_thin.py
|
||||||
@@ -0,0 +1,607 @@
|
@@ -0,0 +1,612 @@
|
||||||
+# -*- coding: utf-8 -*-
|
+# -*- coding: utf-8 -*-
|
||||||
+'''
|
+'''
|
||||||
+ :codeauthor: :email:`Bo Maryniuk <bo@suse.de>`
|
+ :codeauthor: :email:`Bo Maryniuk <bo@suse.de>`
|
||||||
@ -1417,7 +1603,6 @@ index 0000000000..8157eefed8
|
|||||||
+
|
+
|
||||||
+ return tf
|
+ return tf
|
||||||
+
|
+
|
||||||
+
|
|
||||||
+ @patch('salt.exceptions.SaltSystemExit', Exception)
|
+ @patch('salt.exceptions.SaltSystemExit', Exception)
|
||||||
+ @patch('salt.utils.thin.log', MagicMock())
|
+ @patch('salt.utils.thin.log', MagicMock())
|
||||||
+ @patch('salt.utils.thin.os.path.isfile', MagicMock(return_value=False))
|
+ @patch('salt.utils.thin.os.path.isfile', MagicMock(return_value=False))
|
||||||
@ -1532,7 +1717,11 @@ index 0000000000..8157eefed8
|
|||||||
+ 'yaml': '/yaml/',
|
+ 'yaml': '/yaml/',
|
||||||
+ 'tornado': '/tornado/tornado.py',
|
+ 'tornado': '/tornado/tornado.py',
|
||||||
+ 'msgpack': 'msgpack.py'}}}
|
+ 'msgpack': 'msgpack.py'}}}
|
||||||
+ assert cfg == thin.get_ext_tops(cfg)
|
+ out = thin.get_ext_tops(cfg)
|
||||||
|
+ assert out['namespace']['py-version'] == cfg['namespace']['py-version']
|
||||||
|
+ assert out['namespace']['path'] == cfg['namespace']['path']
|
||||||
|
+ assert sorted(out['namespace']['dependencies']) == sorted(['/tornado/tornado.py',
|
||||||
|
+ '/jinja/foo.py', '/yaml/', 'msgpack.py'])
|
||||||
+
|
+
|
||||||
+ @patch('salt.utils.thin.sys.argv', [None, '{"foo": "bar"}'])
|
+ @patch('salt.utils.thin.sys.argv', [None, '{"foo": "bar"}'])
|
||||||
+ @patch('salt.utils.thin.get_tops', lambda **kw: kw)
|
+ @patch('salt.utils.thin.get_tops', lambda **kw: kw)
|
||||||
@ -1698,7 +1887,7 @@ index 0000000000..8157eefed8
|
|||||||
+
|
+
|
||||||
+ :return:
|
+ :return:
|
||||||
+ '''
|
+ '''
|
||||||
+ assert thin.thin_sum('/cachedir', form='sha256') == 12345
|
+ assert thin.thin_sum('/cachedir', form='sha256')[1] == 12345
|
||||||
+ thin.salt.utils.hashutils.get_hash.assert_called()
|
+ thin.salt.utils.hashutils.get_hash.assert_called()
|
||||||
+ assert thin.salt.utils.hashutils.get_hash.call_count == 1
|
+ assert thin.salt.utils.hashutils.get_hash.call_count == 1
|
||||||
+
|
+
|
||||||
@ -1841,6 +2030,7 @@ index 0000000000..8157eefed8
|
|||||||
+ @patch('salt.utils.thin._six.PY3', True)
|
+ @patch('salt.utils.thin._six.PY3', True)
|
||||||
+ @patch('salt.utils.thin._six.PY2', False)
|
+ @patch('salt.utils.thin._six.PY2', False)
|
||||||
+ @patch('salt.utils.thin.sys.version_info', _version_info(None, 3, 6))
|
+ @patch('salt.utils.thin.sys.version_info', _version_info(None, 3, 6))
|
||||||
|
+ @patch('salt.utils.hashutils.DigestCollector', MagicMock())
|
||||||
+ def test_gen_thin_main_content_files_written_py3(self):
|
+ def test_gen_thin_main_content_files_written_py3(self):
|
||||||
+ '''
|
+ '''
|
||||||
+ Test thin.gen_thin function if main content files are written.
|
+ Test thin.gen_thin function if main content files are written.
|
||||||
@ -1855,7 +2045,7 @@ index 0000000000..8157eefed8
|
|||||||
+ 'py3/root/r1', 'py3/root/r2', 'py3/root/r3', 'py3/root2/r4', 'py3/root2/r5', 'py3/root2/r6',
|
+ 'py3/root/r1', 'py3/root/r2', 'py3/root/r3', 'py3/root2/r4', 'py3/root2/r5', 'py3/root2/r6',
|
||||||
+ 'pyall/root/r1', 'pyall/root/r2', 'pyall/root/r3', 'pyall/root2/r4', 'pyall/root2/r5', 'pyall/root2/r6'
|
+ 'pyall/root/r1', 'pyall/root/r2', 'pyall/root/r3', 'pyall/root2/r4', 'pyall/root2/r5', 'pyall/root2/r6'
|
||||||
+ ]
|
+ ]
|
||||||
+ for cl in thin.tarfile.open().method_calls[:-5]:
|
+ for cl in thin.tarfile.open().method_calls[:-6]:
|
||||||
+ arcname = cl[2].get('arcname')
|
+ arcname = cl[2].get('arcname')
|
||||||
+ assert arcname in files
|
+ assert arcname in files
|
||||||
+ files.pop(files.index(arcname))
|
+ files.pop(files.index(arcname))
|
||||||
@ -1890,6 +2080,7 @@ index 0000000000..8157eefed8
|
|||||||
+ @patch('salt.utils.thin._six.PY3', True)
|
+ @patch('salt.utils.thin._six.PY3', True)
|
||||||
+ @patch('salt.utils.thin._six.PY2', False)
|
+ @patch('salt.utils.thin._six.PY2', False)
|
||||||
+ @patch('salt.utils.thin.sys.version_info', _version_info(None, 3, 6))
|
+ @patch('salt.utils.thin.sys.version_info', _version_info(None, 3, 6))
|
||||||
|
+ @patch('salt.utils.hashutils.DigestCollector', MagicMock())
|
||||||
+ def test_gen_thin_ext_alternative_content_files_written_py3(self):
|
+ def test_gen_thin_ext_alternative_content_files_written_py3(self):
|
||||||
+ '''
|
+ '''
|
||||||
+ Test thin.gen_thin function if external alternative content files are written.
|
+ Test thin.gen_thin function if external alternative content files are written.
|
||||||
@ -1905,7 +2096,7 @@ index 0000000000..8157eefed8
|
|||||||
+ 'namespace/py2/root/r1', 'namespace/py2/root/r2', 'namespace/py2/root/r3',
|
+ 'namespace/py2/root/r1', 'namespace/py2/root/r2', 'namespace/py2/root/r3',
|
||||||
+ 'namespace/py2/root2/r4', 'namespace/py2/root2/r5', 'namespace/py2/root2/r6'
|
+ 'namespace/py2/root2/r4', 'namespace/py2/root2/r5', 'namespace/py2/root2/r6'
|
||||||
+ ]
|
+ ]
|
||||||
+ for idx, cl in enumerate(thin.tarfile.open().method_calls[12:-5]):
|
+ for idx, cl in enumerate(thin.tarfile.open().method_calls[12:-6]):
|
||||||
+ arcname = cl[2].get('arcname')
|
+ arcname = cl[2].get('arcname')
|
||||||
+ assert arcname in files
|
+ assert arcname in files
|
||||||
+ files.pop(files.index(arcname))
|
+ files.pop(files.index(arcname))
|
||||||
@ -1946,6 +2137,6 @@ index 0000000000..8157eefed8
|
|||||||
+ for t_line in ['second-system-effect:2:7', 'solar-interference:2:6']:
|
+ for t_line in ['second-system-effect:2:7', 'solar-interference:2:6']:
|
||||||
+ assert t_line in out
|
+ assert t_line in out
|
||||||
--
|
--
|
||||||
2.16.2
|
2.15.1
|
||||||
|
|
||||||
|
|
||||||
|
317
fall-back-to-pymysql.patch
Normal file
317
fall-back-to-pymysql.patch
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
From f7ba683153e11be401a5971ba029d0a3964b1ecb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Maximilian Meister <mmeister@suse.de>
|
||||||
|
Date: Thu, 5 Apr 2018 13:23:23 +0200
|
||||||
|
Subject: [PATCH] fall back to PyMySQL
|
||||||
|
|
||||||
|
same is already done in modules (see #26803)
|
||||||
|
|
||||||
|
Signed-off-by: Maximilian Meister <mmeister@suse.de>
|
||||||
|
---
|
||||||
|
salt/auth/mysql.py | 25 ++++++++++++++++++++++---
|
||||||
|
salt/cache/mysql_cache.py | 28 +++++++++++++++++++---------
|
||||||
|
salt/modules/mysql.py | 22 ++++++++++------------
|
||||||
|
salt/pillar/mysql.py | 21 ++++++++++++++++-----
|
||||||
|
salt/returners/mysql.py | 29 +++++++++++++++++++++--------
|
||||||
|
tests/unit/pillar/test_mysql.py | 2 +-
|
||||||
|
6 files changed, 89 insertions(+), 38 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/auth/mysql.py b/salt/auth/mysql.py
|
||||||
|
index 8bc18a4101..86d00a4373 100644
|
||||||
|
--- a/salt/auth/mysql.py
|
||||||
|
+++ b/salt/auth/mysql.py
|
||||||
|
@@ -55,10 +55,29 @@ import logging
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
try:
|
||||||
|
+ # Trying to import MySQLdb
|
||||||
|
import MySQLdb
|
||||||
|
- HAS_MYSQL = True
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.connections import OperationalError
|
||||||
|
except ImportError:
|
||||||
|
- HAS_MYSQL = False
|
||||||
|
+ try:
|
||||||
|
+ # MySQLdb import failed, try to import PyMySQL
|
||||||
|
+ import pymysql
|
||||||
|
+ pymysql.install_as_MySQLdb()
|
||||||
|
+ import MySQLdb
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.err import OperationalError
|
||||||
|
+ except ImportError:
|
||||||
|
+ MySQLdb = None
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def __virtual__():
|
||||||
|
+ '''
|
||||||
|
+ Confirm that a python mysql client is installed.
|
||||||
|
+ '''
|
||||||
|
+ return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||||
|
|
||||||
|
|
||||||
|
def __get_connection_info():
|
||||||
|
@@ -95,7 +114,7 @@ def auth(username, password):
|
||||||
|
_info['username'],
|
||||||
|
_info['password'],
|
||||||
|
_info['database'])
|
||||||
|
- except MySQLdb.OperationalError as e:
|
||||||
|
+ except OperationalError as e:
|
||||||
|
log.error(e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
diff --git a/salt/cache/mysql_cache.py b/salt/cache/mysql_cache.py
|
||||||
|
index 9d6aa17987..8b0a942310 100644
|
||||||
|
--- a/salt/cache/mysql_cache.py
|
||||||
|
+++ b/salt/cache/mysql_cache.py
|
||||||
|
@@ -46,11 +46,24 @@ value to ``mysql``:
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
from time import sleep
|
||||||
|
import logging
|
||||||
|
+
|
||||||
|
try:
|
||||||
|
+ # Trying to import MySQLdb
|
||||||
|
import MySQLdb
|
||||||
|
- HAS_MYSQL = True
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.connections import OperationalError
|
||||||
|
except ImportError:
|
||||||
|
- HAS_MYSQL = False
|
||||||
|
+ try:
|
||||||
|
+ # MySQLdb import failed, try to import PyMySQL
|
||||||
|
+ import pymysql
|
||||||
|
+ pymysql.install_as_MySQLdb()
|
||||||
|
+ import MySQLdb
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.err import OperationalError
|
||||||
|
+ except ImportError:
|
||||||
|
+ MySQLdb = None
|
||||||
|
|
||||||
|
from salt.exceptions import SaltCacheError
|
||||||
|
|
||||||
|
@@ -71,12 +84,9 @@ __func_alias__ = {'ls': 'list'}
|
||||||
|
|
||||||
|
def __virtual__():
|
||||||
|
'''
|
||||||
|
- Confirm that python-mysql package is installed.
|
||||||
|
+ Confirm that a python mysql client is installed.
|
||||||
|
'''
|
||||||
|
- if not HAS_MYSQL:
|
||||||
|
- return (False, "Please install python-mysql package to use mysql data "
|
||||||
|
- "cache driver")
|
||||||
|
- return __virtualname__
|
||||||
|
+ return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||||
|
|
||||||
|
|
||||||
|
def run_query(conn, query, retries=3):
|
||||||
|
@@ -84,13 +94,13 @@ def run_query(conn, query, retries=3):
|
||||||
|
Get a cursor and run a query. Reconnect up to `retries` times if
|
||||||
|
needed.
|
||||||
|
Returns: cursor, affected rows counter
|
||||||
|
- Raises: SaltCacheError, AttributeError, MySQLdb.OperationalError
|
||||||
|
+ Raises: SaltCacheError, AttributeError, OperationalError
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
out = cur.execute(query)
|
||||||
|
return cur, out
|
||||||
|
- except (AttributeError, MySQLdb.OperationalError) as e:
|
||||||
|
+ except (AttributeError, OperationalError) as e:
|
||||||
|
if retries == 0:
|
||||||
|
raise
|
||||||
|
# reconnect creating new client
|
||||||
|
diff --git a/salt/modules/mysql.py b/salt/modules/mysql.py
|
||||||
|
index 0625b02a96..8b17e461ea 100644
|
||||||
|
--- a/salt/modules/mysql.py
|
||||||
|
+++ b/salt/modules/mysql.py
|
||||||
|
@@ -51,13 +51,14 @@ import salt.utils.stringutils
|
||||||
|
from salt.ext import six
|
||||||
|
# pylint: disable=import-error
|
||||||
|
from salt.ext.six.moves import range, zip # pylint: disable=no-name-in-module,redefined-builtin
|
||||||
|
+
|
||||||
|
try:
|
||||||
|
- # Try to import MySQLdb
|
||||||
|
+ # Trying to import MySQLdb
|
||||||
|
import MySQLdb
|
||||||
|
import MySQLdb.cursors
|
||||||
|
import MySQLdb.converters
|
||||||
|
from MySQLdb.constants import FIELD_TYPE, FLAG
|
||||||
|
- HAS_MYSQLDB = True
|
||||||
|
+ from MySQLdb.connections import OperationalError
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
# MySQLdb import failed, try to import PyMySQL
|
||||||
|
@@ -67,10 +68,9 @@ except ImportError:
|
||||||
|
import MySQLdb.cursors
|
||||||
|
import MySQLdb.converters
|
||||||
|
from MySQLdb.constants import FIELD_TYPE, FLAG
|
||||||
|
- HAS_MYSQLDB = True
|
||||||
|
+ from MySQLdb.err import OperationalError
|
||||||
|
except ImportError:
|
||||||
|
- # No MySQL Connector installed, return False
|
||||||
|
- HAS_MYSQLDB = False
|
||||||
|
+ MySQLdb = None
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@@ -195,11 +195,9 @@ And theses could be mixed, in a like query value with args: 'f\_o\%%o`b\'a"r'
|
||||||
|
|
||||||
|
def __virtual__():
|
||||||
|
'''
|
||||||
|
- Only load this module if the mysql libraries exist
|
||||||
|
+ Confirm that a python mysql client is installed.
|
||||||
|
'''
|
||||||
|
- if HAS_MYSQLDB:
|
||||||
|
- return True
|
||||||
|
- return (False, 'The mysql execution module cannot be loaded: neither MySQLdb nor PyMySQL is available.')
|
||||||
|
+ return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||||
|
|
||||||
|
|
||||||
|
def __check_table(name, table, **connection_args):
|
||||||
|
@@ -331,7 +329,7 @@ def _connect(**kwargs):
|
||||||
|
connargs.pop('passwd')
|
||||||
|
try:
|
||||||
|
dbc = MySQLdb.connect(**connargs)
|
||||||
|
- except MySQLdb.OperationalError as exc:
|
||||||
|
+ except OperationalError as exc:
|
||||||
|
err = 'MySQL Error {0}: {1}'.format(*exc)
|
||||||
|
__context__['mysql.error'] = err
|
||||||
|
log.error(err)
|
||||||
|
@@ -647,7 +645,7 @@ def query(database, query, **connection_args):
|
||||||
|
log.debug('Using db: %s to run query %s', database, query)
|
||||||
|
try:
|
||||||
|
affected = _execute(cur, query)
|
||||||
|
- except MySQLdb.OperationalError as exc:
|
||||||
|
+ except OperationalError as exc:
|
||||||
|
err = 'MySQL Error {0}: {1}'.format(*exc)
|
||||||
|
__context__['mysql.error'] = err
|
||||||
|
log.error(err)
|
||||||
|
@@ -772,7 +770,7 @@ def status(**connection_args):
|
||||||
|
qry = 'SHOW STATUS'
|
||||||
|
try:
|
||||||
|
_execute(cur, qry)
|
||||||
|
- except MySQLdb.OperationalError as exc:
|
||||||
|
+ except OperationalError as exc:
|
||||||
|
err = 'MySQL Error {0}: {1}'.format(*exc)
|
||||||
|
__context__['mysql.error'] = err
|
||||||
|
log.error(err)
|
||||||
|
diff --git a/salt/pillar/mysql.py b/salt/pillar/mysql.py
|
||||||
|
index 8029e5c197..d3f9619ad5 100644
|
||||||
|
--- a/salt/pillar/mysql.py
|
||||||
|
+++ b/salt/pillar/mysql.py
|
||||||
|
@@ -59,16 +59,27 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Import third party libs
|
||||||
|
try:
|
||||||
|
+ # Trying to import MySQLdb
|
||||||
|
import MySQLdb
|
||||||
|
- HAS_MYSQL = True
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
except ImportError:
|
||||||
|
- HAS_MYSQL = False
|
||||||
|
+ try:
|
||||||
|
+ # MySQLdb import failed, try to import PyMySQL
|
||||||
|
+ import pymysql
|
||||||
|
+ pymysql.install_as_MySQLdb()
|
||||||
|
+ import MySQLdb
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ except ImportError:
|
||||||
|
+ MySQLdb = None
|
||||||
|
|
||||||
|
|
||||||
|
def __virtual__():
|
||||||
|
- if not HAS_MYSQL:
|
||||||
|
- return False
|
||||||
|
- return True
|
||||||
|
+ '''
|
||||||
|
+ Confirm that a python mysql client is installed.
|
||||||
|
+ '''
|
||||||
|
+ return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||||
|
|
||||||
|
|
||||||
|
class MySQLExtPillar(SqlBaseExtPillar):
|
||||||
|
diff --git a/salt/returners/mysql.py b/salt/returners/mysql.py
|
||||||
|
index af6698142b..85892cb06c 100644
|
||||||
|
--- a/salt/returners/mysql.py
|
||||||
|
+++ b/salt/returners/mysql.py
|
||||||
|
@@ -155,11 +155,24 @@ import salt.exceptions
|
||||||
|
|
||||||
|
# Import 3rd-party libs
|
||||||
|
from salt.ext import six
|
||||||
|
+
|
||||||
|
try:
|
||||||
|
+ # Trying to import MySQLdb
|
||||||
|
import MySQLdb
|
||||||
|
- HAS_MYSQL = True
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.connections import OperationalError
|
||||||
|
except ImportError:
|
||||||
|
- HAS_MYSQL = False
|
||||||
|
+ try:
|
||||||
|
+ # MySQLdb import failed, try to import PyMySQL
|
||||||
|
+ import pymysql
|
||||||
|
+ pymysql.install_as_MySQLdb()
|
||||||
|
+ import MySQLdb
|
||||||
|
+ import MySQLdb.cursors
|
||||||
|
+ import MySQLdb.converters
|
||||||
|
+ from MySQLdb.err import OperationalError
|
||||||
|
+ except ImportError:
|
||||||
|
+ MySQLdb = None
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@@ -168,10 +181,10 @@ __virtualname__ = 'mysql'
|
||||||
|
|
||||||
|
|
||||||
|
def __virtual__():
|
||||||
|
- if not HAS_MYSQL:
|
||||||
|
- return False, 'Could not import mysql returner; ' \
|
||||||
|
- 'mysql python client is not installed.'
|
||||||
|
- return True
|
||||||
|
+ '''
|
||||||
|
+ Confirm that a python mysql client is installed.
|
||||||
|
+ '''
|
||||||
|
+ return bool(MySQLdb), 'No python mysql client installed.' if MySQLdb is None else ''
|
||||||
|
|
||||||
|
|
||||||
|
def _get_options(ret=None):
|
||||||
|
@@ -228,7 +241,7 @@ def _get_serv(ret=None, commit=False):
|
||||||
|
conn = __context__['mysql_returner_conn']
|
||||||
|
conn.ping()
|
||||||
|
connect = False
|
||||||
|
- except MySQLdb.connections.OperationalError as exc:
|
||||||
|
+ except OperationalError as exc:
|
||||||
|
log.debug('OperationalError on ping: %s', exc)
|
||||||
|
|
||||||
|
if connect:
|
||||||
|
@@ -254,7 +267,7 @@ def _get_serv(ret=None, commit=False):
|
||||||
|
__context__['mysql_returner_conn'] = conn
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
- except MySQLdb.connections.OperationalError as exc:
|
||||||
|
+ except OperationalError as exc:
|
||||||
|
raise salt.exceptions.SaltMasterError('MySQL returner could not connect to database: {exc}'.format(exc=exc))
|
||||||
|
|
||||||
|
cursor = conn.cursor()
|
||||||
|
diff --git a/tests/unit/pillar/test_mysql.py b/tests/unit/pillar/test_mysql.py
|
||||||
|
index 8d49ac24e2..b72988673d 100644
|
||||||
|
--- a/tests/unit/pillar/test_mysql.py
|
||||||
|
+++ b/tests/unit/pillar/test_mysql.py
|
||||||
|
@@ -12,7 +12,7 @@ import salt.pillar.mysql as mysql
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||||
|
-@skipIf(not mysql.HAS_MYSQL, 'MySQL-python module not installed')
|
||||||
|
+@skipIf(mysql.MySQLdb is None, 'MySQL-python module not installed')
|
||||||
|
class MysqlPillarTestCase(TestCase):
|
||||||
|
maxDiff = None
|
||||||
|
|
||||||
|
--
|
||||||
|
2.13.6
|
||||||
|
|
||||||
|
|
91
fix-for-errno-0-resolver-error-0-no-error-bsc-108758.patch
Normal file
91
fix-for-errno-0-resolver-error-0-no-error-bsc-108758.patch
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
From b9cc71639d4e918ef14635124f6991917150de46 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Bo Maryniuk <bo@suse.de>
|
||||||
|
Date: Wed, 21 Mar 2018 11:10:23 +0100
|
||||||
|
Subject: [PATCH] Fix for [Errno 0] Resolver Error 0 (no error)
|
||||||
|
(bsc#1087581)
|
||||||
|
|
||||||
|
* Lintfix: PEP8 ident
|
||||||
|
* Use proper levels of the error handling, use proper log formatting.
|
||||||
|
* Fix unit test for reversed fqdns return data
|
||||||
|
---
|
||||||
|
salt/grains/core.py | 19 ++++++++++++-------
|
||||||
|
tests/unit/grains/test_core.py | 32 ++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 44 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/grains/core.py b/salt/grains/core.py
|
||||||
|
index 17a7d9819a..cd9ba1f29c 100644
|
||||||
|
--- a/salt/grains/core.py
|
||||||
|
+++ b/salt/grains/core.py
|
||||||
|
@@ -1900,16 +1900,21 @@ def fqdns():
|
||||||
|
fqdns = set()
|
||||||
|
|
||||||
|
addresses = salt.utils.network.ip_addrs(include_loopback=False,
|
||||||
|
- interface_data=_INTERFACES)
|
||||||
|
+ interface_data=_INTERFACES)
|
||||||
|
addresses.extend(salt.utils.network.ip_addrs6(include_loopback=False,
|
||||||
|
- interface_data=_INTERFACES))
|
||||||
|
-
|
||||||
|
+ interface_data=_INTERFACES))
|
||||||
|
+ err_message = 'Exception during resolving address: %s'
|
||||||
|
for ip in addresses:
|
||||||
|
try:
|
||||||
|
- fqdns.add(socket.gethostbyaddr(ip)[0])
|
||||||
|
- except (socket.error, socket.herror,
|
||||||
|
- socket.gaierror, socket.timeout) as e:
|
||||||
|
- log.info("Exception during resolving address: " + str(e))
|
||||||
|
+ fqdns.add(socket.getfqdn(socket.gethostbyaddr(ip)[0]))
|
||||||
|
+ except socket.herror as err:
|
||||||
|
+ if err.errno == 0:
|
||||||
|
+ # No FQDN for this IP address, so we don't need to know this all the time.
|
||||||
|
+ log.debug("Unable to resolve address %s: %s", ip, err)
|
||||||
|
+ else:
|
||||||
|
+ log.error(err_message, err)
|
||||||
|
+ except (socket.error, socket.gaierror, socket.timeout) as err:
|
||||||
|
+ log.error(err_message, err)
|
||||||
|
|
||||||
|
grains['fqdns'] = list(fqdns)
|
||||||
|
return grains
|
||||||
|
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
|
||||||
|
index 47c9cdd35b..c604df6c57 100644
|
||||||
|
--- a/tests/unit/grains/test_core.py
|
||||||
|
+++ b/tests/unit/grains/test_core.py
|
||||||
|
@@ -784,3 +784,35 @@ SwapTotal: 4789244 kB'''
|
||||||
|
[]}}
|
||||||
|
with patch.object(salt.utils.dns, 'parse_resolv', MagicMock(return_value=resolv_mock)):
|
||||||
|
assert core.dns() == ret
|
||||||
|
+
|
||||||
|
+ def _run_dns_test(self, resolv_mock, ret):
|
||||||
|
+ with patch.object(salt.utils, 'is_windows',
|
||||||
|
+ MagicMock(return_value=False)):
|
||||||
|
+ with patch.dict(core.__opts__, {'ipv6': False}):
|
||||||
|
+ with patch.object(salt.utils.dns, 'parse_resolv',
|
||||||
|
+ MagicMock(return_value=resolv_mock)):
|
||||||
|
+ get_dns = core.dns()
|
||||||
|
+ self.assertEqual(get_dns, ret)
|
||||||
|
+
|
||||||
|
+ @skipIf(not salt.utils.platform.is_linux(), 'System is not Linux')
|
||||||
|
+ @patch.object(salt.utils, 'is_windows', MagicMock(return_value=False))
|
||||||
|
+ @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']))
|
||||||
|
+ @patch('salt.utils.network.socket.getfqdn', MagicMock(side_effect=lambda v: v)) # Just pass-through
|
||||||
|
+ 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': ['bluesniff.foo.bar', 'foo.bar.baz', 'rinzler.evil-corp.com']}
|
||||||
|
+ with patch.object(socket, 'gethostbyaddr', side_effect=reverse_resolv_mock):
|
||||||
|
+ fqdns = core.fqdns()
|
||||||
|
+ self.assertIn('fqdns', fqdns)
|
||||||
|
+ self.assertEqual(len(fqdns['fqdns']), len(ret['fqdns']))
|
||||||
|
+ self.assertEqual(set(fqdns['fqdns']), set(ret['fqdns']))
|
||||||
|
+
|
||||||
|
--
|
||||||
|
2.13.6
|
||||||
|
|
||||||
|
|
27
initialize-__context__-retcode-for-functions-handled.patch
Normal file
27
initialize-__context__-retcode-for-functions-handled.patch
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
From c374feb62af75dfe18e8c81fb9cb556d678487ce Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
|
||||||
|
<psuarezhernandez@suse.com>
|
||||||
|
Date: Tue, 24 Apr 2018 13:50:49 +0100
|
||||||
|
Subject: [PATCH] Initialize __context__ retcode for functions handled
|
||||||
|
via schedule util module
|
||||||
|
|
||||||
|
---
|
||||||
|
salt/utils/schedule.py | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py
|
||||||
|
index de057477a3..6cb3ce0ef8 100644
|
||||||
|
--- a/salt/utils/schedule.py
|
||||||
|
+++ b/salt/utils/schedule.py
|
||||||
|
@@ -701,6 +701,7 @@ class Schedule(object):
|
||||||
|
for global_key, value in six.iteritems(func_globals):
|
||||||
|
self.functions[mod_name].__globals__[global_key] = value
|
||||||
|
|
||||||
|
+ self.functions.pack['__context__']['retcode'] = 0
|
||||||
|
ret['return'] = self.functions[func](*args, **kwargs)
|
||||||
|
|
||||||
|
if not self.standalone:
|
||||||
|
--
|
||||||
|
2.15.1
|
||||||
|
|
||||||
|
|
37
provide-kwargs-to-pkg_resource.parse_targets-require.patch
Normal file
37
provide-kwargs-to-pkg_resource.parse_targets-require.patch
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
From f7af1739a5795de6f98cfe2856372c755711e6dc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Michael Calmer <mc@suse.de>
|
||||||
|
Date: Wed, 18 Apr 2018 17:19:18 +0200
|
||||||
|
Subject: [PATCH] provide kwargs to pkg_resource.parse_targets required
|
||||||
|
to detect advisory type
|
||||||
|
|
||||||
|
fix invalid string compare
|
||||||
|
---
|
||||||
|
salt/modules/yumpkg.py | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py
|
||||||
|
index 39abb77fbc..9eb27e7701 100644
|
||||||
|
--- a/salt/modules/yumpkg.py
|
||||||
|
+++ b/salt/modules/yumpkg.py
|
||||||
|
@@ -1322,7 +1322,7 @@ def install(name=None,
|
||||||
|
|
||||||
|
try:
|
||||||
|
pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
|
||||||
|
- name, pkgs, sources, saltenv=saltenv, normalize=normalize
|
||||||
|
+ name, pkgs, sources, saltenv=saltenv, normalize=normalize, **kwargs
|
||||||
|
)
|
||||||
|
except MinionError as exc:
|
||||||
|
raise CommandExecutionError(exc)
|
||||||
|
@@ -1620,7 +1620,7 @@ def install(name=None,
|
||||||
|
if _yum() == 'dnf':
|
||||||
|
cmd.extend(['--best', '--allowerasing'])
|
||||||
|
_add_common_args(cmd)
|
||||||
|
- cmd.append('install' if pkg_type is not 'advisory' else 'update')
|
||||||
|
+ cmd.append('install' if pkg_type != 'advisory' else 'update')
|
||||||
|
cmd.extend(targets)
|
||||||
|
out = __salt__['cmd.run_all'](
|
||||||
|
cmd,
|
||||||
|
--
|
||||||
|
2.15.1
|
||||||
|
|
||||||
|
|
41
salt.changes
41
salt.changes
@ -1,3 +1,44 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Apr 25 14:50:36 UTC 2018 - Pablo Suárez Hernández <psuarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Fix minion scheduler to return a 'retcode' attribute (bsc#1089112)
|
||||||
|
- Fix for logging during network interface querying (bsc#1087581)
|
||||||
|
- Fix rhel packages requires both net-tools and iproute (bsc#1087055)
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* initialize-__context__-retcode-for-functions-handled.patch
|
||||||
|
|
||||||
|
- Modified:
|
||||||
|
* fix-for-errno-0-resolver-error-0-no-error-bsc-108758.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Apr 18 17:09:41 UTC 2018 - Pablo Suárez Hernández <psuarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Fix patchinstall on yum module. Bad comparison (bsc#1087278)
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* provide-kwargs-to-pkg_resource.parse_targets-require.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Apr 18 16:55:28 UTC 2018 - Pablo Suárez Hernández <psuarezhernandez@suse.com>
|
||||||
|
|
||||||
|
- Strip trailing commas on Linux user's GECOS fields (bsc#1089362)
|
||||||
|
- Fallback to PyMySQL (bsc#1087891)
|
||||||
|
- Improved test for fqdns
|
||||||
|
- Update SaltSSH patch
|
||||||
|
- Fix for [Errno 0] Resolver Error 0 (no error) (bsc#1087581)
|
||||||
|
* Lintfix: PEP8 ident
|
||||||
|
* Use proper levels of the error handling, use proper log formatting.
|
||||||
|
* Fix unit test for reversed fqdns return data
|
||||||
|
|
||||||
|
- Added:
|
||||||
|
* strip-trailing-commas-on-linux-user-gecos-fields.patch
|
||||||
|
* fall-back-to-pymysql.patch
|
||||||
|
* fix-for-errno-0-resolver-error-0-no-error-bsc-108758.patch
|
||||||
|
|
||||||
|
- Modified:
|
||||||
|
* add-saltssh-multi-version-support-across-python-inte.patch
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Fri Apr 6 16:58:59 UTC 2018 - Mihai Dinca <mdinca@suse.de>
|
Fri Apr 6 16:58:59 UTC 2018 - Mihai Dinca <mdinca@suse.de>
|
||||||
|
|
||||||
|
22
salt.spec
22
salt.spec
@ -86,6 +86,17 @@ Patch12: make-it-possible-to-use-login-pull-and-push-from-mod.patch
|
|||||||
Patch13: explore-module.run-response-to-catch-the-result-in-d.patch
|
Patch13: explore-module.run-response-to-catch-the-result-in-d.patch
|
||||||
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/46684
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/46684
|
||||||
Patch14: add-saltssh-multi-version-support-across-python-inte.patch
|
Patch14: add-saltssh-multi-version-support-across-python-inte.patch
|
||||||
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/46635
|
||||||
|
Patch15: fix-for-errno-0-resolver-error-0-no-error-bsc-108758.patch
|
||||||
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/46890
|
||||||
|
Patch16: fall-back-to-pymysql.patch
|
||||||
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/47149
|
||||||
|
Patch17: strip-trailing-commas-on-linux-user-gecos-fields.patch
|
||||||
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/47155
|
||||||
|
Patch18: provide-kwargs-to-pkg_resource.parse_targets-require.patch
|
||||||
|
# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/47270
|
||||||
|
Patch19: initialize-__context__-retcode-for-functions-handled.patch
|
||||||
|
|
||||||
|
|
||||||
# BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
# BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||||
@ -116,12 +127,12 @@ Requires: procps
|
|||||||
%if 0%{?suse_version} >= 1500
|
%if 0%{?suse_version} >= 1500
|
||||||
Requires: iproute2
|
Requires: iproute2
|
||||||
%else
|
%else
|
||||||
|
%if 0%{?suse_version}
|
||||||
Requires: net-tools
|
Requires: net-tools
|
||||||
%endif
|
%else
|
||||||
|
|
||||||
%if 0%{?rhel}
|
|
||||||
Requires: iproute
|
Requires: iproute
|
||||||
%endif
|
%endif
|
||||||
|
%endif
|
||||||
|
|
||||||
%if %{with systemd}
|
%if %{with systemd}
|
||||||
BuildRequires: systemd
|
BuildRequires: systemd
|
||||||
@ -558,6 +569,11 @@ cp %{S:5} ./.travis.yml
|
|||||||
%patch12 -p1
|
%patch12 -p1
|
||||||
%patch13 -p1
|
%patch13 -p1
|
||||||
%patch14 -p1
|
%patch14 -p1
|
||||||
|
%patch15 -p1
|
||||||
|
%patch16 -p1
|
||||||
|
%patch17 -p1
|
||||||
|
%patch18 -p1
|
||||||
|
%patch19 -p1
|
||||||
|
|
||||||
%build
|
%build
|
||||||
%if 0%{?build_py2}
|
%if 0%{?build_py2}
|
||||||
|
55
strip-trailing-commas-on-linux-user-gecos-fields.patch
Normal file
55
strip-trailing-commas-on-linux-user-gecos-fields.patch
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
From f9fb3639bb3c44babd92d9499bdde83a0a81d6ab Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
|
||||||
|
<psuarezhernandez@suse.com>
|
||||||
|
Date: Wed, 18 Apr 2018 12:05:35 +0100
|
||||||
|
Subject: [PATCH] Strip trailing commas on Linux user GECOS fields
|
||||||
|
|
||||||
|
Add unit tests for GECOS fields
|
||||||
|
---
|
||||||
|
salt/modules/useradd.py | 2 +-
|
||||||
|
tests/unit/modules/test_useradd.py | 18 ++++++++++++++++++
|
||||||
|
2 files changed, 19 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/salt/modules/useradd.py b/salt/modules/useradd.py
|
||||||
|
index 545fe2a6f1..a61ba0e960 100644
|
||||||
|
--- a/salt/modules/useradd.py
|
||||||
|
+++ b/salt/modules/useradd.py
|
||||||
|
@@ -81,7 +81,7 @@ def _build_gecos(gecos_dict):
|
||||||
|
return '{0},{1},{2},{3}'.format(gecos_dict.get('fullname', ''),
|
||||||
|
gecos_dict.get('roomnumber', ''),
|
||||||
|
gecos_dict.get('workphone', ''),
|
||||||
|
- gecos_dict.get('homephone', ''))
|
||||||
|
+ gecos_dict.get('homephone', '')).rstrip(',')
|
||||||
|
|
||||||
|
|
||||||
|
def _update_gecos(name, key, value, root=None):
|
||||||
|
diff --git a/tests/unit/modules/test_useradd.py b/tests/unit/modules/test_useradd.py
|
||||||
|
index eb983685bb..fa30a0df71 100644
|
||||||
|
--- a/tests/unit/modules/test_useradd.py
|
||||||
|
+++ b/tests/unit/modules/test_useradd.py
|
||||||
|
@@ -393,3 +393,21 @@ class UserAddTestCase(TestCase, LoaderModuleMockMixin):
|
||||||
|
mock = MagicMock(side_effect=[{'name': ''}, False, {'name': ''}])
|
||||||
|
with patch.object(useradd, 'info', mock):
|
||||||
|
self.assertFalse(useradd.rename('salt', 'salt'))
|
||||||
|
+
|
||||||
|
+ def test_build_gecos_field(self):
|
||||||
|
+ '''
|
||||||
|
+ Test if gecos fields are built correctly (removing trailing commas)
|
||||||
|
+ '''
|
||||||
|
+ test_gecos = {'fullname': 'Testing',
|
||||||
|
+ 'roomnumber': 1234,
|
||||||
|
+ 'workphone': 22222,
|
||||||
|
+ 'homephone': 99999}
|
||||||
|
+ expected_gecos_fields = 'Testing,1234,22222,99999'
|
||||||
|
+ self.assertEqual(useradd._build_gecos(test_gecos), expected_gecos_fields)
|
||||||
|
+ test_gecos.pop('roomnumber')
|
||||||
|
+ test_gecos.pop('workphone')
|
||||||
|
+ expected_gecos_fields = 'Testing,,,99999'
|
||||||
|
+ self.assertEqual(useradd._build_gecos(test_gecos), expected_gecos_fields)
|
||||||
|
+ test_gecos.pop('homephone')
|
||||||
|
+ expected_gecos_fields = 'Testing'
|
||||||
|
+ self.assertEqual(useradd._build_gecos(test_gecos), expected_gecos_fields)
|
||||||
|
--
|
||||||
|
2.15.1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user