From 5f952007f67610444be87d7105075f273a0e22dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ka=C5=BAmierczak?= Date: Fri, 12 May 2017 10:35:25 +0200 Subject: [PATCH 01/24] Fix: zypper handling of multiple version packages For kernel packages, zypper reports multiple versions as "new" during upgrade. Thus, a salt state requesting pkg.latest of any kernel package would fail, even though zypper runs successfully. This commit provides a simple fix. --- salt/modules/zypper.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index 714afbb62f..a07a371039 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1068,6 +1068,12 @@ def install(name=None, __context__.pop('pkg.list_pkgs', None) new = list_pkgs() + + # Handle packages which report multiple new versions + # (affects only kernel packages at this point) + for pkg in new: + new[pkg] = new[pkg].split(',')[-1] + ret = salt.utils.compare_dicts(old, new) if errors: From 76104f23b45042e164b23f7d6855e575543591c7 Mon Sep 17 00:00:00 2001 From: Evgeny Akhmetkhanov Date: Sun, 14 May 2017 15:32:55 +0300 Subject: [PATCH 02/24] Add basic auth for SPM --- doc/topics/spm/master.rst | 10 +++++++++ salt/spm/__init__.py | 46 +++++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/doc/topics/spm/master.rst b/doc/topics/spm/master.rst index e5d5dc9b6d..c412b7322f 100644 --- a/doc/topics/spm/master.rst +++ b/doc/topics/spm/master.rst @@ -26,6 +26,16 @@ the name of the repository, and the link to the repository: my_repo: url: https://spm.example.com/ +For HTTP/HTTPS Basic authorization you can define credentials: + +.. code-block:: yaml + my_repo: + url: https://spm.example.com/ + username: user + password: pass + +Beware of unauthorized access to this file, please set at least 0640 permissions for this configuration file: + The URL can use ``http``, ``https``, ``ftp``, or ``file``. .. code-block:: yaml diff --git a/salt/spm/__init__.py b/salt/spm/__init__.py index 9692f57477..b2d29854fc 100644 --- a/salt/spm/__init__.py +++ b/salt/spm/__init__.py @@ -228,9 +228,8 @@ class SPMClient(object): dl_path = dl_path.replace('file://', '') shutil.copyfile(dl_path, out_file) else: - response = http.query(dl_path, text=True) with salt.utils.fopen(out_file, 'w') as outf: - outf.write(response.get("text")) + outf.write(self._query_http(dl_path, repo_info['info'])) # Kick off the install self._install_indv_pkg(package, out_file) @@ -463,6 +462,45 @@ class SPMClient(object): continue callback(repo, repo_data[repo]) + def _query_http(self, dl_path, repo_info): + ''' + Download files via http + ''' + query = None + response = None + + try: + if 'username' in repo_info: + try: + if 'password' in repo_info: + query = http.query( + dl_path, text=True, + username=repo_info['username'], + password=repo_info['password'] + ) + else: + raise SPMException('Auth defined, but password is not set for username: \'{0}\'' + .format(repo_info['username'])) + except SPMException as exc: + self.ui.error(str(exc)) + else: + query = http.query(dl_path, text=True) + except SPMException as exc: + self.ui.error(str(exc)) + + try: + if query: + if 'SPM-METADATA' in dl_path: + response = yaml.safe_load(query.get('text', '{}')) + else: + response = query.get('text') + else: + raise SPMException('Response is empty, please check for Errors above.') + except SPMException as exc: + self.ui.error(str(exc)) + + return response + def _download_repo_metadata(self, args): ''' Connect to all repos and download metadata @@ -474,8 +512,8 @@ class SPMClient(object): with salt.utils.fopen(dl_path, 'r') as rpm: metadata = yaml.safe_load(rpm) else: - response = http.query(dl_path, text=True) - metadata = yaml.safe_load(response.get('text', '{}')) + metadata = self._query_http(dl_path, repo_info) + cache_path = '{0}/{1}.p'.format( self.opts['spm_cache_dir'], repo From 33211d032e2588da38877b61673d9d9e45eea9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Knecht?= Date: Mon, 15 May 2017 10:09:25 +0200 Subject: [PATCH 03/24] states: cron: show correct changes when using `special` When using the `cron.present` state with the `special` keyword: /path/to/cron/script: cron.present: - user: root - special: '@hourly' and running Salt in test mode, Salt would always report changes, even when nothing needed to be changed. This commit actually checks if changes are needed when using the `special` keyword. --- salt/states/cron.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/salt/states/cron.py b/salt/states/cron.py index fdebbcf327..ca8f69afb6 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -159,7 +159,8 @@ def _check_cron(user, dayweek=None, comment=None, commented=None, - identifier=None): + identifier=None, + special=None): ''' Return the changes ''' @@ -180,16 +181,21 @@ def _check_cron(user, if cmd is not None: cmd = str(cmd) lst = __salt__['cron.list_tab'](user) - for cron in lst['crons']: - if _cron_matched(cron, cmd, identifier): - if any([_needs_change(x, y) for x, y in - ((cron['minute'], minute), (cron['hour'], hour), - (cron['daymonth'], daymonth), (cron['month'], month), - (cron['dayweek'], dayweek), (cron['identifier'], identifier), - (cron['cmd'], cmd), (cron['comment'], comment), - (cron['commented'], commented))]): - return 'update' - return 'present' + if special is None: + for cron in lst['crons']: + if _cron_matched(cron, cmd, identifier): + if any([_needs_change(x, y) for x, y in + ((cron['minute'], minute), (cron['hour'], hour), + (cron['daymonth'], daymonth), (cron['month'], month), + (cron['dayweek'], dayweek), (cron['identifier'], identifier), + (cron['cmd'], cmd), (cron['comment'], comment), + (cron['commented'], commented))]): + return 'update' + return 'present' + else: + for cron in lst['special']: + if special == cron['spec'] and cmd == cron['cmd']: + return 'present' return 'absent' @@ -310,7 +316,8 @@ def present(name, dayweek=dayweek, comment=comment, commented=commented, - identifier=identifier) + identifier=identifier, + special=special) ret['result'] = None if status == 'absent': ret['comment'] = 'Cron {0} is set to be added'.format(name) From c9bf09a5a13e2a3b26069762ca0624a1eff128d3 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Wed, 10 May 2017 17:30:14 -0600 Subject: [PATCH 04/24] add resolving extra flags to yum upgrade --- salt/modules/yumpkg.py | 38 +++++++++++++++++++++++++++++++------- salt/states/pkg.py | 9 +++++++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 66ffd139fe..007dc0e59c 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -197,10 +197,10 @@ def _get_repo_options(**kwargs): in the yum command, based on the kwargs. ''' # Get repo options from the kwargs - fromrepo = kwargs.get('fromrepo', '') - repo = kwargs.get('repo', '') - disablerepo = kwargs.get('disablerepo', '') - enablerepo = kwargs.get('enablerepo', '') + fromrepo = kwargs.pop('fromrepo', '') + repo = kwargs.pop('repo', '') + disablerepo = kwargs.pop('disablerepo', '') + enablerepo = kwargs.pop('enablerepo', '') # Support old 'repo' argument if repo and not fromrepo: @@ -233,7 +233,7 @@ def _get_excludes_option(**kwargs): Returns a list of '--disableexcludes' option to be used in the yum command, based on the kwargs. ''' - disable_excludes = kwargs.get('disableexcludes', '') + disable_excludes = kwargs.pop('disableexcludes', '') ret = [] if disable_excludes: log.info('Disabling excludes for \'%s\'', disable_excludes) @@ -246,7 +246,7 @@ def _get_branch_option(**kwargs): Returns a list of '--branch' option to be used in the yum command, based on the kwargs. This feature requires 'branch' plugin for YUM. ''' - branch = kwargs.get('branch', '') + branch = kwargs.pop('branch', '') ret = [] if branch: log.info('Adding branch \'%s\'', branch) @@ -254,6 +254,19 @@ def _get_branch_option(**kwargs): return ret +def _get_extra_options(**kwargs): + ''' + Returns list of extra options for yum + ''' + ret = [] + for key, value in kwargs.items(): + if isinstance(key, six.string_types): + ret.append('--{0}=\'{1}\''.format(key, value)) + elif value is True: + ret.append('--{0}'.format(key)) + return ret + + def _get_yum_config(): ''' Returns a dict representing the yum config options and values. @@ -1491,10 +1504,21 @@ def upgrade(name=None, .. versionadded:: 2016.3.0 + + .. note:: + + To add extra arguments to the `yum upgrade` command, pass them as key + word arguments. For arguments without assignments, pass `True` + + .. code-block:: bash + + salt '*' pkg.upgrade security=True exclude='kernel*' + ''' repo_arg = _get_repo_options(**kwargs) exclude_arg = _get_excludes_option(**kwargs) branch_arg = _get_branch_option(**kwargs) + extra_args = _get_extra_options(**kwargs) if salt.utils.is_true(refresh): refresh_db(**kwargs) @@ -1523,7 +1547,7 @@ def upgrade(name=None, and __salt__['config.get']('systemd.scope', True): cmd.extend(['systemd-run', '--scope']) cmd.extend([_yum(), '--quiet', '-y']) - for args in (repo_arg, exclude_arg, branch_arg): + for args in (repo_arg, exclude_arg, branch_arg, extra_args): if args: cmd.extend(args) if skip_verify: diff --git a/salt/states/pkg.py b/salt/states/pkg.py index c03cf509eb..6e776fdc51 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -2335,7 +2335,7 @@ def purged(name, return ret -def uptodate(name, refresh=False, **kwargs): +def uptodate(name, refresh=False, pkgs=None, **kwargs): ''' .. versionadded:: 2014.7.0 @@ -2348,6 +2348,9 @@ def uptodate(name, refresh=False, **kwargs): refresh refresh the package database before checking for new upgrades + pkgs + list of packages to upgrade + :param str cache_valid_time: This parameter sets the value in seconds after which cache marked as invalid, and cache update is necessary. This overwrite ``refresh`` parameter @@ -2383,6 +2386,8 @@ def uptodate(name, refresh=False, **kwargs): if isinstance(refresh, bool): try: packages = __salt__['pkg.list_upgrades'](refresh=refresh, **kwargs) + if isinstance(pkgs, list): + packages = [pkg for pkg in packages if pkg in pkgs] except Exception as exc: ret['comment'] = str(exc) return ret @@ -2400,7 +2405,7 @@ def uptodate(name, refresh=False, **kwargs): return ret try: - ret['changes'] = __salt__['pkg.upgrade'](refresh=refresh, **kwargs) + ret['changes'] = __salt__['pkg.upgrade'](refresh=refresh, pkgs=pkgs, **kwargs) except CommandExecutionError as exc: if exc.info: # Get information for state return from the exception. From 2ca71713b1eb15ec3fac6cdbd0215479fa80e5a5 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Fri, 12 May 2017 08:39:39 -0600 Subject: [PATCH 05/24] use six and clean_kwargs --- salt/modules/yumpkg.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index 007dc0e59c..9be7572227 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -42,6 +42,7 @@ except ImportError: # Import salt libs import salt.utils import salt.utils.pkg +import salt.ext.six as six import salt.utils.itertools import salt.utils.systemd import salt.utils.decorators as decorators @@ -259,7 +260,8 @@ def _get_extra_options(**kwargs): Returns list of extra options for yum ''' ret = [] - for key, value in kwargs.items(): + kwargs = salt.utils.clean_kwargs(**kwargs) + for key, value in six.iteritems(kwargs): if isinstance(key, six.string_types): ret.append('--{0}=\'{1}\''.format(key, value)) elif value is True: From 65b03c667b484a217a3feb45541529548df97b0e Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 16 May 2017 12:06:51 +0200 Subject: [PATCH 06/24] Bugfix: unable to use 127 as hostname --- salt/utils/network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/utils/network.py b/salt/utils/network.py index 8d2e9f5fb2..c07af450e7 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -95,8 +95,8 @@ def _generate_minion_id(): Needs to work on Python 2.6, because of collections.OrderedDict only since 2.7 version. Override 'filter()' for custom filtering. ''' - localhost_matchers = ['localhost.*', 'ip6-.*', '127.*', r'0\.0\.0\.0', - '::1.*', 'ipv6-.*', 'fe00::.*', 'fe02::.*', '1.0.0.*.ip6.arpa'] + localhost_matchers = [r'localhost.*', r'ip6-.*', r'127*[.]\d', r'0\.0\.0\.0', + r'::1.*', r'ipv6-.*', r'fe00::.*', r'fe02::.*', r'1.0.0.*.ip6.arpa'] def append(self, p_object): if p_object and p_object not in self and not self.filter(p_object): From d9c8324a6bb699271788b96afcfac7a7ec63cf95 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 16 May 2017 12:07:32 +0200 Subject: [PATCH 07/24] Unit test for accepting hosts names as 127 --- tests/unit/utils/network_test.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/unit/utils/network_test.py b/tests/unit/utils/network_test.py index a13492f8f8..c197af9eaa 100644 --- a/tests/unit/utils/network_test.py +++ b/tests/unit/utils/network_test.py @@ -266,6 +266,22 @@ class NetworkTestCase(TestCase): self.assertEqual(network._generate_minion_id(), ['hostname.domainname.blank', 'nodename', 'hostname', '1.2.3.4', '5.6.7.8']) + @patch('platform.node', MagicMock(return_value='127')) + @patch('socket.gethostname', MagicMock(return_value='127')) + @patch('socket.getfqdn', MagicMock(return_value='127.domainname.blank')) + @patch('socket.getaddrinfo', MagicMock(return_value=[(2, 3, 0, 'attrname', ('127.0.1.1', 0))])) + @patch('salt.utils.fopen', MagicMock(return_value=False)) + @patch('os.path.exists', MagicMock(return_value=False)) + @patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4', '5.6.7.8'])) + def test_generate_minion_id_127_name(self): + ''' + Test if minion IDs can be named 127.foo + + :return: + ''' + self.assertEqual(network._generate_minion_id(), + ['127.domainname.blank', '127', '1.2.3.4', '5.6.7.8']) + @patch('platform.node', MagicMock(return_value='hostname')) @patch('socket.gethostname', MagicMock(return_value='hostname')) @patch('socket.getfqdn', MagicMock(return_value='hostname')) From 0d0354198b1f532ce53b90d9aa6514163661d377 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 16 May 2017 16:17:26 +0200 Subject: [PATCH 08/24] Harden to 127. IP part --- salt/utils/network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/network.py b/salt/utils/network.py index c07af450e7..036c00d430 100644 --- a/salt/utils/network.py +++ b/salt/utils/network.py @@ -95,7 +95,7 @@ def _generate_minion_id(): Needs to work on Python 2.6, because of collections.OrderedDict only since 2.7 version. Override 'filter()' for custom filtering. ''' - localhost_matchers = [r'localhost.*', r'ip6-.*', r'127*[.]\d', r'0\.0\.0\.0', + localhost_matchers = [r'localhost.*', r'ip6-.*', r'127[.]\d', r'0\.0\.0\.0', r'::1.*', r'ipv6-.*', r'fe00::.*', r'fe02::.*', r'1.0.0.*.ip6.arpa'] def append(self, p_object): From 5168ef8959a5b686b7972ab34c32250b359e7560 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 16 May 2017 16:18:14 +0200 Subject: [PATCH 09/24] Add unit test for hostname can be started from 127 --- tests/unit/utils/network_test.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/unit/utils/network_test.py b/tests/unit/utils/network_test.py index c197af9eaa..b7eea54eb1 100644 --- a/tests/unit/utils/network_test.py +++ b/tests/unit/utils/network_test.py @@ -282,6 +282,22 @@ class NetworkTestCase(TestCase): self.assertEqual(network._generate_minion_id(), ['127.domainname.blank', '127', '1.2.3.4', '5.6.7.8']) + @patch('platform.node', MagicMock(return_value='127890')) + @patch('socket.gethostname', MagicMock(return_value='127890')) + @patch('socket.getfqdn', MagicMock(return_value='127890.domainname.blank')) + @patch('socket.getaddrinfo', MagicMock(return_value=[(2, 3, 0, 'attrname', ('127.0.1.1', 0))])) + @patch('salt.utils.fopen', MagicMock(return_value=False)) + @patch('os.path.exists', MagicMock(return_value=False)) + @patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4', '5.6.7.8'])) + def test_generate_minion_id_127_name_startswith(self): + ''' + Test if minion IDs can be named starting from "127" + + :return: + ''' + self.assertEqual(network._generate_minion_id(), + ['127890.domainname.blank', '127890', '1.2.3.4', '5.6.7.8']) + @patch('platform.node', MagicMock(return_value='hostname')) @patch('socket.gethostname', MagicMock(return_value='hostname')) @patch('socket.getfqdn', MagicMock(return_value='hostname')) From ed03ca534fc446872dc95fec678ef1f369f82b88 Mon Sep 17 00:00:00 2001 From: abednarik Date: Mon, 15 May 2017 14:15:22 -0300 Subject: [PATCH 10/24] Update apt module regarding upgrade against hold packages. Fixes #41231 and related to #30777. --- salt/states/pkg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 6e776fdc51..751c6e0476 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -1152,7 +1152,7 @@ def installed( package, the held package(s) will be skipped and the state will fail. By default, this parameter is set to ``False``. - This option is currently supported only for YUM/DNF. + Currently works with YUM/DNF & APT based systems. .. versionadded:: 2016.11.0 From 6c4c08042ccdb85e531e646a525cf1d398eabbdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ka=C5=BAmierczak?= Date: Tue, 16 May 2017 20:47:04 +0200 Subject: [PATCH 11/24] Added unit tests and copied the behavior to .upgrade method, too. --- salt/modules/zypper.py | 5 +++++ tests/unit/modules/zypper_test.py | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index a07a371039..e3ed3c91a6 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1181,6 +1181,11 @@ def upgrade(refresh=True, __zypper__(systemd_scope=_systemd_scope()).noraise.call(*cmd_update) __context__.pop('pkg.list_pkgs', None) new = list_pkgs() + + # Handle packages which report multiple new versions + # (affects only kernel packages at this point) + for pkg in new: + new[pkg] = new[pkg].split(',')[-1] ret = salt.utils.compare_dicts(old, new) if __zypper__.exit_code not in __zypper__.SUCCESS_EXIT_CODES: diff --git a/tests/unit/modules/zypper_test.py b/tests/unit/modules/zypper_test.py index c29d12c2aa..4871e1d462 100644 --- a/tests/unit/modules/zypper_test.py +++ b/tests/unit/modules/zypper_test.py @@ -359,6 +359,11 @@ class ZypperTestCase(TestCase): self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}}) zypper_mock.assert_any_call('update', '--auto-agree-with-licenses') + with patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.1,1.2"}])): + ret = zypper.upgrade() + self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}}) + zypper_mock.assert_any_call('update', '--auto-agree-with-licenses') + with patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}])): ret = zypper.upgrade(dist_upgrade=True) self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}}) @@ -379,6 +384,22 @@ class ZypperTestCase(TestCase): self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}}) zypper_mock.assert_any_call('dist-upgrade', '--auto-agree-with-licenses', '--from', "Dummy", '--from', 'Dummy2', '--no-allow-vendor-change') + @patch('salt.modules.zypper.refresh_db', MagicMock(return_value=True)) + @patch('salt.modules.zypper._systemd_scope', MagicMock(return_value=False)) + @patch.dict('salt.modules.zypper.__grains__', {'osrelease_info': [12, 1]}) + def test_upgrade_kernel(self): + ''' + Test kernel package upgrade success. + + :return: + ''' + + with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=(['kernel-default'], None))}): + with patch('salt.modules.zypper.__zypper__.noraise.call', MagicMock()): + with patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[{"kernel-default": "3.12.49-11.1"}, {"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"}])): + ret = zypper.install('kernel-default', '--auto-agree-with-licenses') + self.assertDictEqual(ret, {"kernel-default": {"old": "3.12.49-11.1", "new": "3.12.51-60.20.2"}}) + @patch('salt.modules.zypper.refresh_db', MagicMock(return_value=True)) @patch('salt.modules.zypper._systemd_scope', MagicMock(return_value=False)) @patch.dict('salt.modules.zypper.__grains__', {'osrelease_info': [12, 1]}) From 72040136536e21256cac1e2fe973a2b1eac1758f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ka=C5=BAmierczak?= Date: Tue, 16 May 2017 22:48:09 +0200 Subject: [PATCH 12/24] Compacted with statements in the unit test. --- tests/unit/modules/zypper_test.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/unit/modules/zypper_test.py b/tests/unit/modules/zypper_test.py index 4871e1d462..5f1178dc19 100644 --- a/tests/unit/modules/zypper_test.py +++ b/tests/unit/modules/zypper_test.py @@ -394,11 +394,12 @@ class ZypperTestCase(TestCase): :return: ''' - with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=(['kernel-default'], None))}): - with patch('salt.modules.zypper.__zypper__.noraise.call', MagicMock()): - with patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[{"kernel-default": "3.12.49-11.1"}, {"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"}])): - ret = zypper.install('kernel-default', '--auto-agree-with-licenses') - self.assertDictEqual(ret, {"kernel-default": {"old": "3.12.49-11.1", "new": "3.12.51-60.20.2"}}) + with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=(['kernel-default'], None))}), \ + patch('salt.modules.zypper.__zypper__.noraise.call', MagicMock()), \ + patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[ + {"kernel-default": "3.12.49-11.1"}, {"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"}])): + ret = zypper.install('kernel-default', '--auto-agree-with-licenses') + self.assertDictEqual(ret, {"kernel-default": {"old": "3.12.49-11.1", "new": "3.12.51-60.20.2"}}) @patch('salt.modules.zypper.refresh_db', MagicMock(return_value=True)) @patch('salt.modules.zypper._systemd_scope', MagicMock(return_value=False)) From 4550c3ce49ee9633a2b7f9aaf96d1e523566795f Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 16 May 2017 14:41:15 -0700 Subject: [PATCH 13/24] Updating the code that is pulling in the list of cached minions to use self.cache.list instead of relying on checking the local file system, which only works for the localfs cache method. #40748 --- salt/utils/minions.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/salt/utils/minions.py b/salt/utils/minions.py index 34e5d23487..9bf8ce8035 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -253,9 +253,7 @@ class CkMinions(object): cdir = os.path.join(self.opts['cachedir'], 'minions') def list_cached_minions(): - if not os.path.isdir(cdir): - return [] - return os.listdir(cdir) + return self.cache.list('minions') if greedy: minions = [] From 5039fe12fbeed233a202f80d73f10f32a605775c Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 16 May 2017 15:04:07 -0700 Subject: [PATCH 14/24] Removing chdir as it is no needed with this change --- salt/utils/minions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/utils/minions.py b/salt/utils/minions.py index 9bf8ce8035..dfe6e780d5 100644 --- a/salt/utils/minions.py +++ b/salt/utils/minions.py @@ -250,7 +250,6 @@ class CkMinions(object): If not 'greedy' return the only minions have cache data and matched by the condition. ''' cache_enabled = self.opts.get('minion_data_cache', False) - cdir = os.path.join(self.opts['cachedir'], 'minions') def list_cached_minions(): return self.cache.list('minions') From 780a28c9a07ae59e87c575f15567adcb0cec89c8 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 16 May 2017 15:40:41 -0700 Subject: [PATCH 15/24] Swapping the order in the func_alias so the ls function is available. --- salt/cache/consul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/cache/consul.py b/salt/cache/consul.py index d7cbb1f213..b545c96ead 100644 --- a/salt/cache/consul.py +++ b/salt/cache/consul.py @@ -61,7 +61,7 @@ api = None # Define the module's virtual name __virtualname__ = 'consul' -__func_alias__ = {'ls': 'list'} +__func_alias__ = {'list': 'ls'} def __virtual__(): From d411a91676f96c26b9c93e4dcfaf94ebe33d7c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ka=C5=BAmierczak?= Date: Wed, 17 May 2017 11:52:56 +0200 Subject: [PATCH 16/24] Reverted back to cascading with statements for python 2.6 compat --- tests/unit/modules/zypper_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/modules/zypper_test.py b/tests/unit/modules/zypper_test.py index 5f1178dc19..1f7c82361c 100644 --- a/tests/unit/modules/zypper_test.py +++ b/tests/unit/modules/zypper_test.py @@ -394,12 +394,12 @@ class ZypperTestCase(TestCase): :return: ''' - with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=(['kernel-default'], None))}), \ - patch('salt.modules.zypper.__zypper__.noraise.call', MagicMock()), \ - patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[ - {"kernel-default": "3.12.49-11.1"}, {"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"}])): - ret = zypper.install('kernel-default', '--auto-agree-with-licenses') - self.assertDictEqual(ret, {"kernel-default": {"old": "3.12.49-11.1", "new": "3.12.51-60.20.2"}}) + with patch.dict(zypper.__salt__, {'pkg_resource.parse_targets': MagicMock(return_value=(['kernel-default'], None))}): + with patch('salt.modules.zypper.__zypper__.noraise.call', MagicMock()): + with patch('salt.modules.zypper.list_pkgs', MagicMock(side_effect=[ + {"kernel-default": "3.12.49-11.1"}, {"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"}])): + ret = zypper.install('kernel-default', '--auto-agree-with-licenses') + self.assertDictEqual(ret, {"kernel-default": {"old": "3.12.49-11.1", "new": "3.12.51-60.20.2"}}) @patch('salt.modules.zypper.refresh_db', MagicMock(return_value=True)) @patch('salt.modules.zypper._systemd_scope', MagicMock(return_value=False)) From f4b93f9d9a3cc5433b2c181b06bb0ff92e363eaa Mon Sep 17 00:00:00 2001 From: lomeroe Date: Wed, 17 May 2017 08:07:13 -0500 Subject: [PATCH 17/24] properly convert packed string to decimal values --- salt/modules/win_lgpo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index 59d1d8ae66..37005ca1a8 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -2385,9 +2385,14 @@ def _getDataFromRegPolData(search_string, policy_data, return_value_name=False): if len(pol_entry) >= 5: value = pol_entry[4] if vtype == 'REG_DWORD' or vtype == 'REG_QWORD': - value = value.replace(chr(0), '') if value: - value = ord(value) + vlist = list(ord(v) for v in value) + if vtype == 'REG_DWORD': + for v in struct.unpack('I', struct.pack('2H', *vlist)): + value = v + elif vtype == 'REG_QWORD': + for v in struct.unpack('I', struct.pack('4H', *vlist)): + value = v else: value = 0 elif vtype == 'REG_MULTI_SZ': From e1a88e8bf7af7cf9f5e75bf778de54edb889d54e Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Wed, 17 May 2017 14:06:23 -0700 Subject: [PATCH 18/24] Allowing test=True to be passed for salt.runner and salt.wheel when used with orchestration --- salt/states/saltmod.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/salt/states/saltmod.py b/salt/states/saltmod.py index 278ade6290..9e80ac4529 100644 --- a/salt/states/saltmod.py +++ b/salt/states/saltmod.py @@ -647,6 +647,16 @@ def runner(name, **kwargs): 'Unable to fire args event due to missing __orchestration_jid__' ) jid = None + + if __opts__.get('test', False): + ret = { + 'name': name, + 'result': True, + 'changes': {}, + 'comment': "Runner function '{0}' would be executed.".format(name) + } + return ret + out = __salt__['saltutil.runner'](name, __orchestration_jid__=jid, __env__=__env__, @@ -704,6 +714,12 @@ def wheel(name, **kwargs): 'Unable to fire args event due to missing __orchestration_jid__' ) jid = None + + if __opts__.get('test', False): + ret['result'] = True, + ret['comment'] = "Wheel function '{0}' would be executed.".format(name) + return ret + out = __salt__['saltutil.wheel'](name, __orchestration_jid__=jid, __env__=__env__, From cdb072c2070083837a2adcaa8c3567e44c70afc6 Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Thu, 18 May 2017 09:39:04 -0400 Subject: [PATCH 19/24] [2016.11] Bump latest release version to 2016.11.5 --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 0b94b5b258..3127a8675c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -239,7 +239,7 @@ on_saltstack = 'SALT_ON_SALTSTACK' in os.environ project = 'Salt' version = salt.version.__version__ -latest_release = '2016.11.4' # latest release +latest_release = '2016.11.5' # latest release previous_release = '2016.3.6' # latest release from previous branch previous_release_dir = '2016.3' # path on web server for previous branch next_release = '' # next release From 4f0aa577a567269a76547749738e9939429da876 Mon Sep 17 00:00:00 2001 From: lomeroe Date: Thu, 18 May 2017 09:37:53 -0500 Subject: [PATCH 20/24] backport 41307 to 2016.11, properly pack version numbers into single number --- salt/modules/win_lgpo.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/modules/win_lgpo.py b/salt/modules/win_lgpo.py index bfea240455..d941521dda 100644 --- a/salt/modules/win_lgpo.py +++ b/salt/modules/win_lgpo.py @@ -4036,8 +4036,7 @@ def _write_regpol_data(data_to_write, version_nums = (version_nums[0], version_nums[1] + 1) elif gpt_extension.lower() == 'gPCUserExtensionNames'.lower(): version_nums = (version_nums[0] + 1, version_nums[1]) - version_num = int("{0}{1}".format(str(version_nums[0]).zfill(4), - str(version_nums[1]).zfill(4)), 16) + version_num = struct.unpack('>I', struct.pack('>2H', *version_nums))[0] gpt_ini_data = "{0}{1}={2}\r\n{3}".format( gpt_ini_data[0:version_loc.start()], 'Version', version_num, From cde008ff7795229f0acd9d0e394780115d37cf9f Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Thu, 18 May 2017 12:24:53 -0400 Subject: [PATCH 21/24] Add patched packages warning to 2016.11.5 release notes --- doc/topics/releases/2016.11.5.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/topics/releases/2016.11.5.rst b/doc/topics/releases/2016.11.5.rst index 2bebd0de33..d55d039356 100644 --- a/doc/topics/releases/2016.11.5.rst +++ b/doc/topics/releases/2016.11.5.rst @@ -19,6 +19,25 @@ Statistics: Changes: +Patched Packages +---------------- +Due to the critical nature of issue `#41230` we have decided to patch the 2016.11.5 packages with PR `#41244`. This issue affects all calls to a salt-minion if there is an ipv6 nameserver set on the minion's host. The patched packages on repo.saltstack.com will divert from the v2016.11.5 tag and pypi packages due to the additional PR applied to the packages. + +- **PR** `#41244`_: (*cachedout*) Fix ipv6 nameserver grains + @ *2017-05-15T17:55:39Z* + + - **ISSUE** `#41230`_: (*RealKelsar*) 2016.11.5 IPv6 nameserver in resolv.conf leads to minion exception + | refs: `#41244`_ `#41244`_ + - **ISSUE** `#40912`_: (*razed11*) IPV6 Warning when ipv6 set to False + | refs: `#40934`_ + - **PR** `#40934`_: (*gtmanfred*) Only display IPvX warning if role is master + | refs: `#41244`_ `#41244`_ + * 53d5b3e Merge pull request `#41244`_ from cachedout/fix_ipv6_nameserver_grains + * f745db1 Lint + + * 6e1ab69 Partial revert of `#40934`_ + + * 88f49f9 Revert "Only display IPvX warning if role is master" - **PR** `#41173`_: (*twangboy*) Add silent action to MsgBox for Path Actions @ *2017-05-10T17:22:18Z* From 9a1bf4205f952e7b62f94c27c8048c35ad164ac1 Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Thu, 18 May 2017 12:42:35 -0400 Subject: [PATCH 22/24] fix url refs in rst --- doc/topics/releases/2016.11.5.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/topics/releases/2016.11.5.rst b/doc/topics/releases/2016.11.5.rst index d55d039356..5909fd090d 100644 --- a/doc/topics/releases/2016.11.5.rst +++ b/doc/topics/releases/2016.11.5.rst @@ -21,7 +21,7 @@ Changes: Patched Packages ---------------- -Due to the critical nature of issue `#41230` we have decided to patch the 2016.11.5 packages with PR `#41244`. This issue affects all calls to a salt-minion if there is an ipv6 nameserver set on the minion's host. The patched packages on repo.saltstack.com will divert from the v2016.11.5 tag and pypi packages due to the additional PR applied to the packages. +Due to the critical nature of issue `#41230`_ we have decided to patch the 2016.11.5 packages with PR `#41244`_. This issue affects all calls to a salt-minion if there is an ipv6 nameserver set on the minion's host. The patched packages on repo.saltstack.com will divert from the v2016.11.5 tag and pypi packages due to the additional PR applied to the packages. - **PR** `#41244`_: (*cachedout*) Fix ipv6 nameserver grains @ *2017-05-15T17:55:39Z* @@ -799,6 +799,8 @@ Due to the critical nature of issue `#41230` we have decided to patch the 2016.1 .. _`#40930`: https://github.com/saltstack/salt/pull/40930 .. _`#40933`: https://github.com/saltstack/salt/pull/40933 .. _`#40934`: https://github.com/saltstack/salt/pull/40934 +.. _`#41230`: https://github.com/saltstack/salt/issues/41230 +.. _`#41244`: https://github.com/saltstack/salt/pull/41244 .. _`#40935`: https://github.com/saltstack/salt/pull/40935 .. _`#40936`: https://github.com/saltstack/salt/pull/40936 .. _`#40939`: https://github.com/saltstack/salt/pull/40939 From e5fc0aeb9c84450869feb869edcd84bdb9f71554 Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Thu, 18 May 2017 14:17:35 -0400 Subject: [PATCH 23/24] Add 2016.11.6 Release Notes --- doc/topics/releases/2016.11.6.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/topics/releases/2016.11.6.rst diff --git a/doc/topics/releases/2016.11.6.rst b/doc/topics/releases/2016.11.6.rst new file mode 100644 index 0000000000..f8e9bf8958 --- /dev/null +++ b/doc/topics/releases/2016.11.6.rst @@ -0,0 +1,6 @@ +============================ +Salt 2016.11.6 Release Notes +============================ + +Version 2016.11.6 is a bugfix release for :ref:`2016.11.0 `. + From 3c471247f0c787691ddae02b5f03505a7939e252 Mon Sep 17 00:00:00 2001 From: Loren Gordon Date: Thu, 18 May 2017 16:18:34 -0400 Subject: [PATCH 24/24] Corrects versionadded for win_network.get_route --- salt/modules/win_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/win_network.py b/salt/modules/win_network.py index e940271604..e3b4de1f6d 100644 --- a/salt/modules/win_network.py +++ b/salt/modules/win_network.py @@ -203,7 +203,7 @@ def get_route(ip): ''' Return routing information for given destination ip - .. versionadded:: 2016.11.6 + .. versionadded:: 2016.11.5 CLI Example::