From f0961e741ee06313b24cbe116beda90ecb68aebf Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Wed, 3 Aug 2016 12:16:22 -0600 Subject: [PATCH 01/30] Merge with 2016.3 --- salt/cli/daemons.py | 4 +++- salt/config/__init__.py | 37 ++++++++++++++++++++++++++++--------- salt/utils/parsers.py | 11 ++++++++--- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/salt/cli/daemons.py b/salt/cli/daemons.py index 3b3c21d6a3f..735fb4ddec1 100644 --- a/salt/cli/daemons.py +++ b/salt/cli/daemons.py @@ -424,7 +424,9 @@ class ProxyMinion(parsers.ProxyMinionOptionParser, DaemonsMixin): # pylint: dis # Proxies get their ID from the command line. This may need to change in # the future. - self.config['id'] = self.values.proxyid + # We used to set this here. Now it is set in ProxyMinionOptionParser + # by passing it via setup_config to config.minion_config + # self.config['id'] = self.values.proxyid try: if self.config['verify_env']: diff --git a/salt/config/__init__.py b/salt/config/__init__.py index 22c2a812aec..4ee389543ae 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -176,6 +176,11 @@ VALID_OPTS = { # The directory to store all cache files. 'cachedir': str, + # Append minion_id to these directories. Helps with + # multiple proxies and minions running on the same machine. + # Allowed elements in the list: pki_dir, cachedir, extension_modules + 'append_minionid_config_dirs': list, + # Flag to cache jobs locally. 'cache_jobs': bool, @@ -876,6 +881,7 @@ DEFAULT_MINION_OPTS = { 'pki_dir': os.path.join(salt.syspaths.CONFIG_DIR, 'pki', 'minion'), 'id': '', 'cachedir': os.path.join(salt.syspaths.CACHE_DIR, 'minion'), + 'append_minionid_config_dirs': [], 'cache_jobs': False, 'grains_cache': False, 'grains_cache_expiration': 300, @@ -1344,6 +1350,7 @@ DEFAULT_PROXY_MINION_OPTS = { 'log_file': os.path.join(salt.syspaths.LOGS_DIR, 'proxy'), 'add_proxymodule_to_opts': False, 'proxy_merge_grains_in_module': False, + 'append_minionid_config_dirs': ['cachedir'], } # ----- Salt Cloud Configuration Defaults -----------------------------------> @@ -1749,7 +1756,8 @@ def minion_config(path, env_var='SALT_MINION_CONFIG', defaults=None, cache_minion_id=False, - ignore_config_errors=True): + ignore_config_errors=True, + minion_id=None): ''' Reads in the minion configuration file and sets up special options @@ -1789,7 +1797,9 @@ def minion_config(path, overrides.update(include_config(include, path, verbose=True, exit_on_config_errors=not ignore_config_errors)) - opts = apply_minion_config(overrides, defaults, cache_minion_id=cache_minion_id) + opts = apply_minion_config(overrides, defaults, + cache_minion_id=cache_minion_id, + minion_id=minion_id) _validate_opts(opts) return opts @@ -2934,7 +2944,8 @@ def get_id(opts, cache_minion_id=False): def apply_minion_config(overrides=None, defaults=None, - cache_minion_id=False): + cache_minion_id=False, + minion_id=None): ''' Returns minion configurations dict. ''' @@ -2948,20 +2959,28 @@ def apply_minion_config(overrides=None, opts['__cli'] = os.path.basename(sys.argv[0]) - if len(opts['sock_dir']) > len(opts['cachedir']) + 10: - opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix') - # No ID provided. Will getfqdn save us? using_ip_for_id = False if not opts.get('id'): - opts['id'], using_ip_for_id = get_id( - opts, - cache_minion_id=cache_minion_id) + if minion_id: + opts['id'] = minion_id + else: + opts['id'], using_ip_for_id = get_id( + opts, + cache_minion_id=cache_minion_id) # it does not make sense to append a domain to an IP based id if not using_ip_for_id and 'append_domain' in opts: opts['id'] = _append_domain(opts) + for directory in opts.get('append_minionid_config_dirs', []): + if directory in ['pki_dir', 'cachedir', 'extension_modules']: + newdirectory = os.path.join(opts[directory], opts['id']) + opts[directory] = newdirectory + + if len(opts['sock_dir']) > len(opts['cachedir']) + 10: + opts['sock_dir'] = os.path.join(opts['cachedir'], '.salt-unix') + # Enabling open mode requires that the value be set to True, and # nothing else! opts['open_mode'] = opts['open_mode'] is True diff --git a/salt/utils/parsers.py b/salt/utils/parsers.py index a62d150e09e..6320d22a7ff 100644 --- a/salt/utils/parsers.py +++ b/salt/utils/parsers.py @@ -1693,13 +1693,13 @@ class MinionOptionParser(six.with_metaclass(OptionParserMeta, MasterOptionParser class ProxyMinionOptionParser(six.with_metaclass(OptionParserMeta, OptionParser, + ProxyIdMixIn, ConfigDirMixIn, MergeConfigMixIn, LogLevelMixIn, RunUserMixin, DaemonMixIn, - SaltfileMixIn, - ProxyIdMixIn)): # pylint: disable=no-init + SaltfileMixIn)): # pylint: disable=no-init description = ( 'The Salt proxy minion, connects to and controls devices not able to run a minion. ' @@ -1712,8 +1712,13 @@ class ProxyMinionOptionParser(six.with_metaclass(OptionParserMeta, _default_logging_logfile_ = os.path.join(syspaths.LOGS_DIR, 'proxy') def setup_config(self): + try: + minion_id = self.values.proxyid + except AttributeError: + minion_id = None + return config.minion_config(self.get_config_file_path(), - cache_minion_id=False) + cache_minion_id=False, minion_id=minion_id) class SyndicOptionParser(six.with_metaclass(OptionParserMeta, From 84cc7d67c0e5ef33b6336dbd031bde687e83af2c Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Wed, 3 Aug 2016 12:25:14 -0600 Subject: [PATCH 02/30] Add documentation for append_minionid_config_dirs. --- conf/minion | 7 +++++++ conf/proxy | 10 ++++++++++ doc/ref/configuration/minion.rst | 19 ++++++++++++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/conf/minion b/conf/minion index 3ba8ba00953..7270f0c73de 100644 --- a/conf/minion +++ b/conf/minion @@ -127,6 +127,13 @@ # This data may contain sensitive data and should be protected accordingly. #cachedir: /var/cache/salt/minion +# Append minion_id to these directories. Helps with +# multiple proxies and minions running on the same machine. +# Allowed elements in the list: pki_dir, cachedir, extension_modules +# Normally not needed unless running several proxies and/or minions on the same machine +# Defaults to ['cachedir'] for proxies, [] (empty list) for regular minions +#append_minionid_config_dirs: + # Verify and set permissions on configuration directories at startup. #verify_env: True diff --git a/conf/proxy b/conf/proxy index 7b835e25ea5..4e5cc3452cd 100644 --- a/conf/proxy +++ b/conf/proxy @@ -84,6 +84,16 @@ # This data may contain sensitive data and should be protected accordingly. #cachedir: /var/cache/salt/minion +# Append minion_id to these directories. Helps with +# multiple proxies and minions running on the same machine. +# Allowed elements in the list: pki_dir, cachedir, extension_modules +# Normally not needed unless running several proxies and/or minions on the same machine +# Defaults to ['cachedir'] for proxies, [] (empty list) for regular minions +# append_minionid_config_dirs: +# - cachedir + + + # Verify and set permissions on configuration directories at startup. #verify_env: True diff --git a/doc/ref/configuration/minion.rst b/doc/ref/configuration/minion.rst index 0e135ddb2a9..35f1e6a1f46 100644 --- a/doc/ref/configuration/minion.rst +++ b/doc/ref/configuration/minion.rst @@ -395,7 +395,24 @@ This directory may contain sensitive data and should be protected accordingly. cachedir: /var/cache/salt/minion -.. conf_minion:: verify_env +.. conf_minion:: append_minionid_config_dirs + +``append_minionid_config_dirs`` +------------------------------- + +Default: ``[]`` (the empty list) for regular minions, ``['cachedir']`` for proxy minions. + +Append minion_id to these configuration directories. Helps with multiple proxies +and minions running on the same machine. Allowed elements in the list: +``pki_dir``, ``cachedir``, ``extension_modules``. +Normally not needed unless running several proxies and/or minions on the same machine. + +.. code-block:: yaml + + append_minionid_config_dirs: + - pki_dir + - cachedir + ``verify_env`` -------------- From a5f6630e977c9f4bbba450b82136672422aa5e2a Mon Sep 17 00:00:00 2001 From: Denys Havrysh Date: Thu, 4 Aug 2016 12:11:34 +0300 Subject: [PATCH 03/30] Make `pkgbuild.repo` state recognize `createrepo` command return code --- salt/modules/rpmbuild.py | 2 +- salt/states/pkgbuild.py | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/salt/modules/rpmbuild.py b/salt/modules/rpmbuild.py index 7334691bc05..fc223c5fa46 100644 --- a/salt/modules/rpmbuild.py +++ b/salt/modules/rpmbuild.py @@ -466,4 +466,4 @@ def make_repo(repodir, keyid=None, env=None, use_passphrase=False, gnupghome='/e proc.close(terminate=True, kill=True) cmd = 'createrepo --update {0}'.format(repodir) - __salt__['cmd.run'](cmd, runas=runas) + return __salt__['cmd.run_all'](cmd, runas=runas) diff --git a/salt/states/pkgbuild.py b/salt/states/pkgbuild.py index 8bef4771f93..3c1dbf12d8f 100644 --- a/salt/states/pkgbuild.py +++ b/salt/states/pkgbuild.py @@ -346,7 +346,7 @@ def repo(name, if __opts__['test'] is True: ret['result'] = None - ret['comment'] = 'Package repo at {0} will be rebuilt'.format(name) + ret['comment'] = 'Package repo metadata at {0} will be refreshed'.format(name) return ret # Need the check for None here, if env is not provided then it falls back @@ -363,6 +363,18 @@ def repo(name, func = 'rpmbuild.make_repo' break - __salt__[func](name, keyid, env, use_passphrase, gnupghome, runas) - ret['changes'] = {'refresh': True} + res = __salt__[func](name, keyid, env, use_passphrase, gnupghome, runas) + + if res['retcode'] > 0: + ret['result'] = False + else: + ret['changes'] = {'refresh': True} + + if res['stdout'] and res['stderr']: + ret['comment'] = "{0}\n{1}".format(res['stdout'], res['stderr']) + elif res['stdout']: + ret['comment'] = res['stdout'] + elif res['stderr']: + ret['comment'] = res['stderr'] + return ret From 6f3a32dace7ece09006d7d788b7560a23235aa02 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Thu, 4 Aug 2016 11:28:19 +0200 Subject: [PATCH 04/30] Deprecate status.uptime one version later --- salt/modules/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/status.py b/salt/modules/status.py index 029426b81df..cebd57b16d7 100644 --- a/salt/modules/status.py +++ b/salt/modules/status.py @@ -132,7 +132,7 @@ def custom(): return ret -@with_deprecated(globals(), "Boron") +@with_deprecated(globals(), "Carbon") def uptime(): ''' Return the uptime for this system. From 1642dba5d106e7ebd11cd05d53b1a1f28174fe47 Mon Sep 17 00:00:00 2001 From: Jonathan Ballet Date: Thu, 4 Aug 2016 16:56:42 +0200 Subject: [PATCH 05/30] doc: fix broken links in the test documentation page --- doc/topics/tutorials/writing_tests.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/topics/tutorials/writing_tests.rst b/doc/topics/tutorials/writing_tests.rst index cd14bcb9b79..491253b0bfd 100644 --- a/doc/topics/tutorials/writing_tests.rst +++ b/doc/topics/tutorials/writing_tests.rst @@ -418,9 +418,9 @@ against the ``return`` statement in the ``if`` clause. There are more examples of writing unit tests of varying complexities available in the following docs: -* `Simple Unit Test Example` -* `Complete Unit Test Example` -* `Complex Unit Test Example` +* :ref:`Simple Unit Test Example` +* :ref:`Complete Unit Test Example` +* :ref:`Complex Unit Test Example` .. note:: @@ -435,7 +435,7 @@ Automated Test Runs =================== SaltStack maintains a Jenkins server which can be viewed at -http://jenkins.saltstack.com. The tests executed from this Jenkins server +https://jenkins.saltstack.com. The tests executed from this Jenkins server create fresh virtual machines for each test run, then execute the destructive tests on the new, clean virtual machine. This allows for the execution of tests across supported platforms. From ae04e7aaeb190935b92bf362d332b0dbafdc2bd5 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 5 Aug 2016 02:33:01 +0900 Subject: [PATCH 06/30] Initial POC Works fine so long as the GID of the sudo_user matches the GID of the user executing sudo -- i.e., the 'user' setting in the roster. --- salt/client/ssh/__init__.py | 14 ++++++++++++-- salt/client/ssh/shell.py | 3 ++- salt/config.py | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index 3cf53d1c127..d04d3dac406 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -126,6 +126,9 @@ SUDO="" if [ -n "{{SUDO}}" ] then SUDO="sudo " fi +if [ "$SUDO" ] +then SUDO="sudo -u {{SUDO_USER}}" +fi EX_PYTHON_INVALID={EX_THIN_PYTHON_INVALID} PYTHON_CMDS="python27 python2.7 python26 python2.6 python2 python" for py_cmd in $PYTHON_CMDS @@ -229,6 +232,10 @@ class SSH(object): 'ssh_sudo', salt.config.DEFAULT_MASTER_OPTS['ssh_sudo'] ), + 'sudo_user': self.opts.get( + 'ssh_sudo_user', + salt.config.DEFAULT_MASTER_OPTS['ssh_sudo_user'] + ), 'identities_only': self.opts.get( 'ssh_identities_only', salt.config.DEFAULT_MASTER_OPTS['ssh_identities_only'] @@ -609,6 +616,7 @@ class Single(object): mine=False, minion_opts=None, identities_only=False, + sudo_user=None, **kwargs): # Get mine setting and mine_functions if defined in kwargs (from roster) self.mine = mine @@ -656,7 +664,8 @@ class Single(object): 'sudo': sudo, 'tty': tty, 'mods': self.mods, - 'identities_only': identities_only} + 'identities_only': identities_only, + 'sudo_user': sudo_user} self.minion_opts = opts.get('ssh_minion_opts', {}) if minion_opts is not None: self.minion_opts.update(minion_opts) @@ -889,6 +898,7 @@ class Single(object): Prepare the command string ''' sudo = 'sudo' if self.target['sudo'] else '' + sudo_user = self.target['sudo_user'] if '_caller_cachedir' in self.opts: cachedir = self.opts['_caller_cachedir'] else: @@ -927,10 +937,10 @@ ARGS = {10}\n'''.format(self.minion_config, self.argv) py_code = SSH_PY_SHIM.replace('#%%OPTS', arg_str) py_code_enc = py_code.encode('base64') - cmd = SSH_SH_SHIM.format( DEBUG=debug, SUDO=sudo, + SUDO_USER=sudo_user, SSH_PY_CODE=py_code_enc, HOST_PY_MAJOR=sys.version_info[0], ) diff --git a/salt/client/ssh/shell.py b/salt/client/ssh/shell.py index 7713a9d94e4..f08a87789a5 100644 --- a/salt/client/ssh/shell.py +++ b/salt/client/ssh/shell.py @@ -58,7 +58,8 @@ class Shell(object): sudo=False, tty=False, mods=None, - identities_only=False): + identities_only=False, + sudo_user=None): self.opts = opts self.host = host self.user = user diff --git a/salt/config.py b/salt/config.py index eed618014e9..968ceeb71e8 100644 --- a/salt/config.py +++ b/salt/config.py @@ -705,6 +705,7 @@ VALID_OPTS = { 'ssh_passwd': str, 'ssh_port': str, 'ssh_sudo': bool, + 'ssh_sudo_user': str, 'ssh_timeout': float, 'ssh_user': str, 'ssh_scan_ports': str, @@ -1200,6 +1201,7 @@ DEFAULT_MASTER_OPTS = { 'ssh_passwd': '', 'ssh_port': '22', 'ssh_sudo': False, + 'ssh_sudo_user': '', 'ssh_timeout': 60, 'ssh_user': 'root', 'ssh_scan_ports': '22', From 676be7d711f2481b3bde6366bcfdf252cc4aae8d Mon Sep 17 00:00:00 2001 From: Hengyang Hu Date: Thu, 4 Aug 2016 10:42:30 -0700 Subject: [PATCH 07/30] Make the log level back to warning for unclassified exc --- salt/minion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/minion.py b/salt/minion.py index 1ac16570be9..710ea74c3d2 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1389,7 +1389,7 @@ class Minion(MinionBase): ret['out'] = 'nested' except Exception: msg = 'The minion function caused an exception' - log.warning(msg, exc_info_on_loglevel=logging.DEBUG) + log.warning(msg, exc_info_on_loglevel=True) salt.utils.error.fire_exception(salt.exceptions.MinionError(msg), opts, job=data) ret['return'] = '{0}: {1}'.format(msg, traceback.format_exc()) ret['out'] = 'nested' From 2f11df98caa1da3a8e45df0b55f55854b95b16c8 Mon Sep 17 00:00:00 2001 From: Elias Probst Date: Thu, 4 Aug 2016 20:07:21 +0200 Subject: [PATCH 08/30] Handle exceptions in `_get_virtual()` and in `_get_virtual()` consumers --- salt/modules/aptpkg.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/salt/modules/aptpkg.py b/salt/modules/aptpkg.py index 9a7d0717739..246b6fe448b 100644 --- a/salt/modules/aptpkg.py +++ b/salt/modules/aptpkg.py @@ -171,7 +171,12 @@ def _get_virtual(): except KeyError: __context__['pkg._get_virtual'] = {} if HAS_APT: - apt_cache = apt.cache.Cache() + try: + apt_cache = apt.cache.Cache() + except SystemError as se: + msg = 'Failed to get virtual package information ({0})'.format(se) + log.error(msg) + raise CommandExecutionError(msg) pkgs = getattr(apt_cache._cache, 'packages', []) for pkg in pkgs: for item in getattr(pkg, 'provides_list', []): @@ -249,7 +254,10 @@ def latest_version(*names, **kwargs): if refresh: refresh_db() - virtpkgs = _get_virtual() + try: + virtpkgs = _get_virtual() + except CommandExecutionError as cee: + raise CommandExecutionError(cee) all_virt = set() for provides in six.itervalues(virtpkgs): all_virt.update(provides) @@ -1179,7 +1187,10 @@ def list_pkgs(versions_as_list=False, # Check for virtual packages. We need dctrl-tools for this. if not removed: - virtpkgs_all = _get_virtual() + try: + virtpkgs_all = _get_virtual() + except CommandExecutionError as cee: + raise CommandExecutionError(cee) virtpkgs = set() for realpkg, provides in six.iteritems(virtpkgs_all): # grep-available returns info on all virtual packages. Ignore any From 5b56a4acf7c10085af3ee9a6d8a2116c93cc8891 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 5 Aug 2016 03:24:18 +0900 Subject: [PATCH 09/30] Docs --- doc/topics/ssh/roster.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/topics/ssh/roster.rst b/doc/topics/ssh/roster.rst index 6487ff275c4..ce587f30de0 100644 --- a/doc/topics/ssh/roster.rst +++ b/doc/topics/ssh/roster.rst @@ -42,6 +42,9 @@ The information which can be stored in a roster ``target`` is the following: # Optional parameters port: # The target system's ssh port number sudo: # Boolean to run command via sudo + sudo_user: # Str: Set this to execute Salt as a sudo user other than root. + # This user must be in the same system group as the remote user + # that is used to login and is specified above. tty: # Boolean: Set this option to True if sudo is also set to # True and requiretty is also set on the target system priv: # File path to ssh private key, defaults to salt-ssh.rsa From 6f53232e6da233db1334d9f744d97cde29e80b26 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Fri, 5 Aug 2016 03:41:36 +0900 Subject: [PATCH 10/30] Better error handling and a workaround for group mismatch. --- doc/topics/ssh/roster.rst | 3 ++- salt/client/ssh/ssh_py_shim.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/topics/ssh/roster.rst b/doc/topics/ssh/roster.rst index ce587f30de0..7bdaeac9161 100644 --- a/doc/topics/ssh/roster.rst +++ b/doc/topics/ssh/roster.rst @@ -44,7 +44,8 @@ The information which can be stored in a roster ``target`` is the following: sudo: # Boolean to run command via sudo sudo_user: # Str: Set this to execute Salt as a sudo user other than root. # This user must be in the same system group as the remote user - # that is used to login and is specified above. + # that is used to login and is specified above. Alternatively, + # the user must be a super-user. tty: # Boolean: Set this option to True if sudo is also set to # True and requiretty is also set on the target system priv: # File path to ssh private key, defaults to salt-ssh.rsa diff --git a/salt/client/ssh/ssh_py_shim.py b/salt/client/ssh/ssh_py_shim.py index acd8fbfb577..524e1d9c69e 100644 --- a/salt/client/ssh/ssh_py_shim.py +++ b/salt/client/ssh/ssh_py_shim.py @@ -65,9 +65,14 @@ def need_deployment(): # If SUDOing then also give the super user group write permissions sudo_gid = os.environ.get('SUDO_GID') if sudo_gid: - os.chown(OPTIONS.saltdir, -1, int(sudo_gid)) - stt = os.stat(OPTIONS.saltdir) - os.chmod(OPTIONS.saltdir, stt.st_mode | stat.S_IWGRP | stat.S_IRGRP | stat.S_IXGRP) + try: + os.chown(OPTIONS.saltdir, -1, int(sudo_gid)) + stt = os.stat(OPTIONS.saltdir) + os.chmod(OPTIONS.saltdir, stt.st_mode | stat.S_IWGRP | stat.S_IRGRP | stat.S_IXGRP) + except OSError: + sys.stdout.write('\n\nUnable to set permissions on thin directory.\nIf sudo_user is set ' + 'and is not root, be certain the user is in the same group\nas the login user') + sys.exit(1) # Delimiter emitted on stdout *only* to indicate shim message to master. sys.stdout.write("{0}\ndeploy\n".format(OPTIONS.delimiter)) From 4d8119b88bf3a129e4f4d4fc8eac534d9f848870 Mon Sep 17 00:00:00 2001 From: Nathan Delhaye Date: Fri, 5 Aug 2016 16:01:41 +0200 Subject: [PATCH 11/30] fix rabbitmq version detection using a package-agnostic version Fixes #34481 Fixes #35003 Fixes #33588 --- salt/modules/rabbitmq.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index 9b9d16e2f80..1c548140272 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -8,6 +8,7 @@ from __future__ import absolute_import # Import python libs import json +import re import logging import random import string @@ -307,7 +308,9 @@ def check_password(name, password, runas=None): ''' # try to get the rabbitmq-version - adapted from _get_rabbitmq_plugin try: - version = [int(i) for i in __salt__['pkg.version']('rabbitmq-server').split('-')[0].split('.')] + res = __salt__['cmd.run'](['rabbitmqctl', 'status'], runas=runas, python_shell=False) + server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}',res).group(1) + version = [int(i) for i in server_version.split('.')] except ValueError: version = (0, 0, 0) if len(version) < 3: From 730a0770414606a38c78e06b2e48d19f8013910b Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 5 Aug 2016 09:25:47 -0500 Subject: [PATCH 12/30] Do not attempt to get fqdn_ip{4,6} grains when ipv{4,6} grains are empty This prevents DNS resolution issues from causing ``salt-call --local`` to hang. Resolves #32719. --- salt/grains/core.py | 62 +++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/salt/grains/core.py b/salt/grains/core.py index e2d4218fa22..7170d1053d3 100644 --- a/salt/grains/core.py +++ b/salt/grains/core.py @@ -1466,58 +1466,30 @@ def append_domain(): return grain -def ip4(): +def ip_fqdn(): ''' - Return a list of ipv4 addrs + Return ip address and FQDN grains ''' - if salt.utils.is_proxy(): return {} - return {'ipv4': salt.utils.network.ip_addrs(include_loopback=True)} + ret = {} + ret['ipv4'] = salt.utils.network.ip_addrs(include_loopback=True) + ret['ipv6'] = salt.utils.network.ip_addrs6(include_loopback=True) + _fqdn = hostname()['fqdn'] + for socket_type, ipv_num in ((socket.AF_INET, '4'), (socket.AF_INET6, '6')): + key = 'fqdn_ip' + ipv_num + if not ret['ipv' + ipv_num]: + ret[key] = [] + else: + try: + info = socket.getaddrinfo(_fqdn, None, socket_type) + ret[key] = list(set(item[4][0] for item in info)) + except socket.error: + ret[key] = [] -def fqdn_ip4(): - ''' - Return a list of ipv4 addrs of fqdn - ''' - - if salt.utils.is_proxy(): - return {} - - try: - info = socket.getaddrinfo(hostname()['fqdn'], None, socket.AF_INET) - addrs = list(set(item[4][0] for item in info)) - except socket.error: - addrs = [] - return {'fqdn_ip4': addrs} - - -def ip6(): - ''' - Return a list of ipv6 addrs - ''' - - if salt.utils.is_proxy(): - return {} - - return {'ipv6': salt.utils.network.ip_addrs6(include_loopback=True)} - - -def fqdn_ip6(): - ''' - Return a list of ipv6 addrs of fqdn - ''' - - if salt.utils.is_proxy(): - return {} - - try: - info = socket.getaddrinfo(hostname()['fqdn'], None, socket.AF_INET6) - addrs = list(set(item[4][0] for item in info)) - except socket.error: - addrs = [] - return {'fqdn_ip6': addrs} + return ret def ip_interfaces(): From f75eb2ecc755a67df2f1e93c2470f42850299029 Mon Sep 17 00:00:00 2001 From: Nathan Delhaye Date: Fri, 5 Aug 2016 17:13:15 +0200 Subject: [PATCH 13/30] Fix runas in code order and make the check_password work with the new >3.5.7 version --- salt/modules/rabbitmq.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index 1c548140272..f10995326b6 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -307,18 +307,24 @@ def check_password(name, password, runas=None): salt '*' rabbitmq.check_password rabbit_user password ''' # try to get the rabbitmq-version - adapted from _get_rabbitmq_plugin + + if runas is None: + runas = salt.utils.get_user() + try: res = __salt__['cmd.run'](['rabbitmqctl', 'status'], runas=runas, python_shell=False) - server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}',res).group(1) + server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}',res) + + if server_version is None: + raise ValueError("") + + server_version = server_version.group(1) version = [int(i) for i in server_version.split('.')] except ValueError: version = (0, 0, 0) if len(version) < 3: version = (0, 0, 0) - if runas is None: - runas = salt.utils.get_user() - # rabbitmq introduced a native api to check a username and password in version 3.5.7. if tuple(version) >= (3, 5, 7): res = __salt__['cmd.run']( @@ -326,8 +332,8 @@ def check_password(name, password, runas=None): runas=runas, output_loglevel='quiet', python_shell=False) - msg = 'password-check' - return _format_response(res, msg) + + return not 'Error:' in res cmd = ('rabbit_auth_backend_internal:check_user_login' '(<<"{0}">>, [{{password, <<"{1}">>}}]).').format( From 64f93f8938991fe84236cecbee5e4658e8d44c29 Mon Sep 17 00:00:00 2001 From: Derek Maciel Date: Tue, 2 Aug 2016 00:59:15 -0400 Subject: [PATCH 14/30] Assume two EVRs are equal if E and V are equal but one R is missing. --- salt/modules/rpm.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py index e5356a1565d..f5268bf749f 100644 --- a/salt/modules/rpm.py +++ b/salt/modules/rpm.py @@ -651,14 +651,29 @@ def version_cmp(ver1, ver2, ignore_epoch=False): 'more accurate version comparisons' ) else: - cmp_result = cmp_func(salt.utils.str_version_to_evr(ver1), - salt.utils.str_version_to_evr(ver2)) - if cmp_result not in (-1, 0, 1): - raise CommandExecutionError( - 'Comparison result \'{0}\' is invalid'.format(cmp_result) - ) + else: + # If one EVR is missing a release but not the other and they + # otherwise would be equal, assume they are equal. This can + # happen if e.g. you are checking if a package version 3.2 is + # satisfied by a 3.2-1. + (ver1_e, ver1_v, ver1_r) = salt.utils.str_version_to_evr(ver1) + (ver2_e, ver2_v, ver2_r) = salt.utils.str_version_to_evr(ver2) + if not ver1_r or not ver2_r: + tmp_cmp = cmp_func((ver1_e, ver1_v, ''), (ver2_e, ver2_v, '')) + if tmp_cmp not in (-1, 0, 1): + raise CommandExecutionError( + 'Comparison result \'{0}\' is invalid'.format(tmp_cmp) + ) + if tmp_cmp == 0: + return 0 - return cmp_result + cmp_result = cmp_func((ver1_e, ver1_v, ver1_r), + (ver2_e, ver2_v, ver2_r)) + if cmp_result not in (-1, 0, 1): + raise CommandExecutionError( + 'Comparison result \'{0}\' is invalid'.format(cmp_result) + ) + return cmp_result except Exception as exc: log.warning( From 7c15f5b20a8b28d83143c30a342d79002fcd9092 Mon Sep 17 00:00:00 2001 From: Derek Maciel Date: Wed, 3 Aug 2016 14:44:37 -0400 Subject: [PATCH 15/30] Fix formatting --- salt/modules/rpm.py | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py index f5268bf749f..14959258443 100644 --- a/salt/modules/rpm.py +++ b/salt/modules/rpm.py @@ -651,29 +651,28 @@ def version_cmp(ver1, ver2, ignore_epoch=False): 'more accurate version comparisons' ) else: - else: - # If one EVR is missing a release but not the other and they - # otherwise would be equal, assume they are equal. This can - # happen if e.g. you are checking if a package version 3.2 is - # satisfied by a 3.2-1. - (ver1_e, ver1_v, ver1_r) = salt.utils.str_version_to_evr(ver1) - (ver2_e, ver2_v, ver2_r) = salt.utils.str_version_to_evr(ver2) - if not ver1_r or not ver2_r: - tmp_cmp = cmp_func((ver1_e, ver1_v, ''), (ver2_e, ver2_v, '')) - if tmp_cmp not in (-1, 0, 1): - raise CommandExecutionError( - 'Comparison result \'{0}\' is invalid'.format(tmp_cmp) - ) - if tmp_cmp == 0: - return 0 - - cmp_result = cmp_func((ver1_e, ver1_v, ver1_r), - (ver2_e, ver2_v, ver2_r)) - if cmp_result not in (-1, 0, 1): + # If one EVR is missing a release but not the other and they + # otherwise would be equal, assume they are equal. This can + # happen if e.g. you are checking if a package version 3.2 is + # satisfied by a 3.2-1. + (ver1_e, ver1_v, ver1_r) = salt.utils.str_version_to_evr(ver1) + (ver2_e, ver2_v, ver2_r) = salt.utils.str_version_to_evr(ver2) + if not ver1_r or not ver2_r: + tmp_cmp = cmp_func((ver1_e, ver1_v, ''), (ver2_e, ver2_v, '')) + if tmp_cmp not in (-1, 0, 1): raise CommandExecutionError( - 'Comparison result \'{0}\' is invalid'.format(cmp_result) + 'Comparison result \'{0}\' is invalid'.format(tmp_cmp) ) - return cmp_result + if tmp_cmp == 0: + return 0 + + cmp_result = cmp_func((ver1_e, ver1_v, ver1_r), + (ver2_e, ver2_v, ver2_r)) + if cmp_result not in (-1, 0, 1): + raise CommandExecutionError( + 'Comparison result \'{0}\' is invalid'.format(cmp_result) + ) + return cmp_result except Exception as exc: log.warning( From 9ade78de7b4d626fea2ba6de1384b3fd0dd7859a Mon Sep 17 00:00:00 2001 From: Derek Maciel Date: Wed, 3 Aug 2016 14:46:21 -0400 Subject: [PATCH 16/30] Revise unnecessary code duplication --- salt/modules/rpm.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/salt/modules/rpm.py b/salt/modules/rpm.py index 14959258443..22f0d93a6f0 100644 --- a/salt/modules/rpm.py +++ b/salt/modules/rpm.py @@ -652,19 +652,13 @@ def version_cmp(ver1, ver2, ignore_epoch=False): ) else: # If one EVR is missing a release but not the other and they - # otherwise would be equal, assume they are equal. This can - # happen if e.g. you are checking if a package version 3.2 is - # satisfied by a 3.2-1. + # otherwise would be equal, ignore the release. This can happen if + # e.g. you are checking if a package version 3.2 is satisfied by + # 3.2-1. (ver1_e, ver1_v, ver1_r) = salt.utils.str_version_to_evr(ver1) (ver2_e, ver2_v, ver2_r) = salt.utils.str_version_to_evr(ver2) if not ver1_r or not ver2_r: - tmp_cmp = cmp_func((ver1_e, ver1_v, ''), (ver2_e, ver2_v, '')) - if tmp_cmp not in (-1, 0, 1): - raise CommandExecutionError( - 'Comparison result \'{0}\' is invalid'.format(tmp_cmp) - ) - if tmp_cmp == 0: - return 0 + ver1_r = ver2_r = '' cmp_result = cmp_func((ver1_e, ver1_v, ver1_r), (ver2_e, ver2_v, ver2_r)) From 9ed47f713a7757cbec6883ae3cf24b7d85779dc6 Mon Sep 17 00:00:00 2001 From: Derek Maciel Date: Fri, 5 Aug 2016 00:20:07 -0400 Subject: [PATCH 17/30] Add missing documentation for pkg.installed --- salt/states/pkg.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/salt/states/pkg.py b/salt/states/pkg.py index 4d517c93e49..d630fb70836 100644 --- a/salt/states/pkg.py +++ b/salt/states/pkg.py @@ -689,6 +689,9 @@ def installed( - dos2unix - salt-minion: 2015.8.5-1.el6 + If the version given is the string ``latest``, the latest available + package version will be installed à la ``pkg.latest``. + :param bool refresh: This parameter controls whether or not the packge repo database is updated prior to installing the requested package(s). From 6764a886011b1060a98335690e6bd0199fffbd99 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 5 Aug 2016 14:07:50 -0500 Subject: [PATCH 18/30] Ensure that failed recursion results in no blob object being returned --- salt/utils/gitfs.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 43c96cc1b1c..59340145fc7 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -857,6 +857,7 @@ class GitPython(GitProvider): while True: depth += 1 if depth > SYMLINK_RECURSE_DEPTH: + blob = None break try: file_blob = tree / path @@ -878,6 +879,7 @@ class GitPython(GitProvider): break except KeyError: # File not found or repo_path points to a directory + blob = None break return blob, blob.hexsha if blob is not None else blob @@ -1400,6 +1402,7 @@ class Pygit2(GitProvider): while True: depth += 1 if depth > SYMLINK_RECURSE_DEPTH: + blob = None break try: if stat.S_ISLNK(tree[path].filemode): @@ -1415,6 +1418,7 @@ class Pygit2(GitProvider): oid = tree[path].oid blob = self.repo[oid] except KeyError: + blob = None break return blob, blob.hex if blob is not None else blob @@ -1750,6 +1754,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method while True: depth += 1 if depth > SYMLINK_RECURSE_DEPTH: + blob = None break prefix_dirs, _, filename = path.rpartition(os.path.sep) tree = self.walk_tree(tree, prefix_dirs) @@ -1771,6 +1776,7 @@ class Dulwich(GitProvider): # pylint: disable=abstract-method blob = self.repo.get_object(oid) break except KeyError: + blob = None break return blob, blob.sha().hexdigest() if blob is not None else blob From e05648cc2dd8bf66a32966c3aeffa9f58463cc26 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 5 Aug 2016 14:08:24 -0500 Subject: [PATCH 19/30] Break from loop when file is found --- salt/utils/gitfs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 59340145fc7..7d0a7390cc2 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -1417,6 +1417,7 @@ class Pygit2(GitProvider): else: oid = tree[path].oid blob = self.repo[oid] + break except KeyError: blob = None break From 45d563d5acfb28d972adbb5f9c0eb682dabb34aa Mon Sep 17 00:00:00 2001 From: Mikhael A Date: Fri, 4 Mar 2016 14:18:08 +0300 Subject: [PATCH 20/30] Return correct value for services that must be enabled in Systemd, not in SysV This fixes situations, when a server switched from SysV to Systemd. SysV symlinks are still in place and Salt incorrectly determines, that service is already enabled. For example: ~$ salt-call --local service.enabled spamassassin [INFO ] Executing command 'systemctl is-enabled spamassassin.service' [INFO ] Executing command 'runlevel' in directory '/root' local: True However: ~$ systemctl is-enabled spamassassin.service disabled ~$ find /etc/rc*.d/ -name '*spamassassin' /etc/rc0.d/K02spamassassin /etc/rc1.d/K02spamassassin /etc/rc2.d/S02spamassassin /etc/rc3.d/S02spamassassin /etc/rc4.d/S02spamassassin /etc/rc5.d/S02spamassassin /etc/rc6.d/K02spamassassin --- salt/modules/systemd.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index e4e7e7f10b0..c25fa922386 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -779,9 +779,11 @@ def enabled(name, **kwargs): # pylint: disable=unused-argument # string will be non-empty. if bool(__salt__['cmd.run'](cmd, python_shell=False)): return True - else: + elif name in _get_sysv_services(): return _sysv_enabled(name) + return False + def disabled(name): ''' From 51ab9cd6d471a0fb2dcfb4bba487c38946257f93 Mon Sep 17 00:00:00 2001 From: Seth House Date: Thu, 28 Jul 2016 15:52:08 -0600 Subject: [PATCH 21/30] Add saltenv support to module.run This kwarg gets stripped by the state compiler before this function is ever invoked. --- salt/states/module.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/salt/states/module.py b/salt/states/module.py index f5308c841a5..0d2abb90bb2 100644 --- a/salt/states/module.py +++ b/salt/states/module.py @@ -52,6 +52,7 @@ with ``m_``: * name * names * state +* saltenv For example: @@ -183,6 +184,9 @@ def run(name, **kwargs): elif arg == 'state': if 'm_state' in kwargs: defaults[arg] = kwargs.pop('m_state') + elif arg == 'saltenv': + if 'm_saltenv' in kwargs: + defaults[arg] = kwargs.pop('m_saltenv') if arg in kwargs: defaults[arg] = kwargs.pop(arg) missing = set() @@ -195,6 +199,8 @@ def run(name, **kwargs): rarg = 'm_names' elif arg == 'state': rarg = 'm_state' + elif arg == 'saltenv': + rarg = 'm_saltenv' else: rarg = arg if rarg not in kwargs and arg not in defaults: From e2e8bbbfdeda299f173c19c6c8fdd9725125d4e9 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 5 Aug 2016 20:47:24 -0500 Subject: [PATCH 22/30] Add integration test for #35214 --- tests/integration/states/git.py | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/integration/states/git.py b/tests/integration/states/git.py index a78b271e420..809e0a24c4e 100644 --- a/tests/integration/states/git.py +++ b/tests/integration/states/git.py @@ -197,6 +197,62 @@ class GitTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn): finally: shutil.rmtree(name, ignore_errors=True) + def test_latest_fast_forward(self): + ''' + Test running git.latest state a second time after changes have been + made to the remote repo. + ''' + def _head(cwd): + return self.run_function('git.rev_parse', [cwd, 'HEAD']) + + repo_url = 'https://{0}/saltstack/salt-test-repo.git'.format(self.__domain) + mirror_dir = os.path.join(integration.TMP, 'salt_repo_mirror') + mirror_url = 'file://' + mirror_dir + admin_dir = os.path.join(integration.TMP, 'salt_repo_admin') + clone_dir = os.path.join(integration.TMP, 'salt_repo') + + try: + # Mirror the repo + self.run_function('git.clone', + [mirror_dir, repo_url, None, '--mirror']) + + # Make sure the directory for the mirror now exists + self.assertTrue(os.path.exists(mirror_dir)) + + # Clone the mirror twice, once to the admin location and once to + # the clone_dir + ret = self.run_state('git.latest', name=mirror_url, target=admin_dir) + self.assertSaltTrueReturn(ret) + ret = self.run_state('git.latest', name=mirror_url, target=clone_dir) + self.assertSaltTrueReturn(ret) + + # Make a change to the repo by editing the file in the admin copy + # of the repo and committing. + head_pre = _head(admin_dir) + with open(os.path.join(admin_dir, 'LICENSE'), 'a') as fp_: + fp_.write('Hello world!') + self.run_function('git.commit', [admin_dir, 'Added a line', '-a']) + # Make sure HEAD is pointing to a new SHA so we know we properly + # committed our change. + head_post = _head(admin_dir) + self.assertNotEqual(head_pre, head_post) + + # Push the change to the mirror + # NOTE: the test will fail if the salt-test-repo's default branch + # is changed. + self.run_function('git.push', [admin_dir, 'origin', 'develop']) + + # Re-run the git.latest state on the clone_dir + ret = self.run_state('git.latest', name=mirror_url, target=clone_dir) + self.assertSaltTrueReturn(ret) + + # Make sure that the clone_dir now has the correct SHA + self.assertEqual(head_post, _head(clone_dir)) + + finally: + for path in (mirror_dir, admin_dir, clone_dir): + shutil.rmtree(path, ignore_errors=True) + def test_present(self): ''' git.present From bcd5129e9f21035412b6b5b087c09075645a510c Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 5 Aug 2016 20:49:27 -0500 Subject: [PATCH 23/30] Fix regression in git.latest when update is fast-forward --- salt/states/git.py | 48 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/salt/states/git.py b/salt/states/git.py index bf268949bff..ca7f8b749a2 100644 --- a/salt/states/git.py +++ b/salt/states/git.py @@ -809,16 +809,11 @@ def latest(name, elif remote_rev_type == 'sha1': has_remote_rev = True - # If has_remote_rev is False, then either the remote rev could not - # be found with git ls-remote (in which case we won't know more - # until fetching) or we're going to be checking out a new branch - # and don't have to worry about fast-forwarding. So, we will set - # fast_forward to None (to signify uncertainty) unless there are - # local changes, in which case we will set it to False. + # If fast_forward is not boolean, then we don't know if this will + # be a fast forward or not, because a fetch is requirde. fast_forward = None if not local_changes else False if has_remote_rev: - # Remote rev already present if (not revs_match and not update_head) \ and (branch is None or branch == local_branch): ret['comment'] = remote_loc.capitalize() \ @@ -831,25 +826,26 @@ def latest(name, ) return ret - # No need to check if this is a fast_forward if we already know - # that it won't be (due to local changes). - if fast_forward is not False: - if base_rev is None: - # If we're here, the remote_rev exists in the local - # checkout but there is still no HEAD locally. A possible - # reason for this is that an empty repository existed there - # and a remote was added and fetched, but the repository - # was not fast-forwarded. Regardless, going from no HEAD to - # a locally-present rev is considered a fast-forward - # update, unless there are local changes. - fast_forward = not bool(local_changes) - else: - fast_forward = __salt__['git.merge_base']( - target, - refs=[base_rev, remote_rev], - is_ancestor=True, - user=user, - ignore_retcode=True) + # No need to check if this is a fast_forward if we already know + # that it won't be (due to local changes). + if fast_forward is not False: + if base_rev is None: + # If we're here, the remote_rev exists in the local + # checkout but there is still no HEAD locally. A + # possible reason for this is that an empty repository + # existed there and a remote was added and fetched, but + # the repository was not fast-forwarded. Regardless, + # going from no HEAD to a locally-present rev is + # considered a fast-forward update, unless there are + # local changes. + fast_forward = not bool(local_changes) + else: + fast_forward = __salt__['git.merge_base']( + target, + refs=[base_rev, remote_rev], + is_ancestor=True, + user=user, + ignore_retcode=True) if fast_forward is False: if not force_reset: From ff33df4ba1dea0baf895d6c0cbaae8fd0275763c Mon Sep 17 00:00:00 2001 From: abednarik Date: Sat, 6 Aug 2016 08:44:09 -0300 Subject: [PATCH 24/30] Fix disk.wipe missing option. Added -a option to wipefs in disk.,wipe to actually wipe partition. --- salt/modules/disk.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/modules/disk.py b/salt/modules/disk.py index 7fb0348814c..d2ab1665be4 100644 --- a/salt/modules/disk.py +++ b/salt/modules/disk.py @@ -310,13 +310,16 @@ def wipe(device): salt '*' disk.wipe /dev/sda1 ''' - cmd = 'wipefs {0}'.format(device) + cmd = 'wipefs -a {0}'.format(device) try: out = __salt__['cmd.run_all'](cmd, python_shell=False) except subprocess.CalledProcessError as err: return False if out['retcode'] == 0: return True + else: + log.error('Error wiping device {0}: {1}'.format(device, out['stderr'])) + return False def dump(device, args=None): From 6714e8f386485eed61bf92d46c308fa7423843de Mon Sep 17 00:00:00 2001 From: Mike Place Date: Sun, 7 Aug 2016 06:57:20 +0900 Subject: [PATCH 25/30] Fix mock call in disk wipe test --- tests/unit/modules/disk_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/modules/disk_test.py b/tests/unit/modules/disk_test.py index 9c3755c2d39..8cf4d3613d1 100644 --- a/tests/unit/modules/disk_test.py +++ b/tests/unit/modules/disk_test.py @@ -114,7 +114,7 @@ class DiskTestCase(TestCase): with patch.dict(disk.__salt__, {'cmd.run_all': mock}): disk.wipe('/dev/sda') mock.assert_called_once_with( - 'wipefs /dev/sda', + 'wipefs -a /dev/sda', python_shell=False ) From 104116f46462de03843d50ce2c3ffdddf0a56cb5 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Sun, 7 Aug 2016 06:58:55 +0900 Subject: [PATCH 26/30] Add release notes and include entry about disk.wipe fix --- doc/topics/releases/2016.3.4.rst | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/topics/releases/2016.3.4.rst diff --git a/doc/topics/releases/2016.3.4.rst b/doc/topics/releases/2016.3.4.rst new file mode 100644 index 00000000000..e2c08482959 --- /dev/null +++ b/doc/topics/releases/2016.3.4.rst @@ -0,0 +1,9 @@ +=========================== +Salt 2016.3.4 Release Notes +=========================== + +Version 2016.3.4 is a bugfix release for :doc:`2016.3.0 +`. + +- The `disk.wipe` execution module function has been modified + so that it correctly wipes a disk. From c3f29ab205bf95a57759dd49e6d3560679480cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Mon, 8 Aug 2016 11:55:46 +0100 Subject: [PATCH 27/30] checksum validation during zypper pkg.download --- salt/modules/zypper.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index 7dd73dd05f6..73cac286211 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1595,14 +1595,17 @@ def download(*packages, **kwargs): pkg_ret = {} for dld_result in __zypper__.xml.call('download', *packages).getElementsByTagName("download-result"): repo = dld_result.getElementsByTagName("repository")[0] + path = dld_result.getElementsByTagName("localfile")[0].getAttribute("path") pkg_info = { 'repository-name': repo.getAttribute('name'), 'repository-alias': repo.getAttribute('alias'), + 'path': path, } key = _get_first_aggregate_text( dld_result.getElementsByTagName('name') ) - pkg_ret[key] = pkg_info + if __salt__['lowpkg.checksum'](pkg_info['path']): + pkg_ret[key] = pkg_info if pkg_ret: failed = [pkg for pkg in packages if pkg not in pkg_ret] From 18700e821ef56e9d3df858ddaed7a2780642269d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= Date: Wed, 25 May 2016 17:08:16 +0100 Subject: [PATCH 28/30] unit tests for rpm.checksum() and zypper.download() lint issue fixed --- tests/unit/modules/zypper_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/modules/zypper_test.py b/tests/unit/modules/zypper_test.py index 308bf9429a5..2f2b3233f87 100644 --- a/tests/unit/modules/zypper_test.py +++ b/tests/unit/modules/zypper_test.py @@ -387,6 +387,7 @@ class ZypperTestCase(TestCase): test_out = { 'nmap': { + 'path': u'/var/cache/zypp/packages/SLE-12-x86_64-Pool/x86_64/nmap-6.46-1.72.x86_64.rpm', 'repository-alias': u'SLE-12-x86_64-Pool', 'repository-name': u'SLE-12-x86_64-Pool' } From 6cdee210363db16185e32317f85cc49ed58bf29e Mon Sep 17 00:00:00 2001 From: Ivan Babrou Date: Mon, 8 Aug 2016 13:38:39 +0100 Subject: [PATCH 29/30] Default state_output_profile to True everywhere, closes #35166 --- salt/output/highstate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/output/highstate.py b/salt/output/highstate.py index 11c6d1464c1..c40ab6f6fb5 100644 --- a/salt/output/highstate.py +++ b/salt/output/highstate.py @@ -423,7 +423,7 @@ def _format_host(host, data): line_max_len - 7) hstrs.append(colorfmt.format(colors['CYAN'], totals, colors)) - if __opts__.get('state_output_profile', False): + if __opts__.get('state_output_profile', True): sum_duration = sum(rdurations) duration_unit = 'ms' # convert to seconds if duration is 1000ms or more @@ -491,14 +491,14 @@ def _format_terse(tcolor, comps, ret, colors, tabular): result = u'Differs' if tabular is True: fmt_string = u'{0}' - if __opts__.get('state_output_profile', False): + if __opts__.get('state_output_profile', True): fmt_string += u'{6[start_time]!s} [{6[duration]!s} ms] ' fmt_string += u'{2:>10}.{3:<10} {4:7} Name: {1}{5}' elif isinstance(tabular, str): fmt_string = tabular else: fmt_string = u' {0} Name: {1} - Function: {2}.{3} - Result: {4}' - if __opts__.get('state_output_profile', False): + if __opts__.get('state_output_profile', True): fmt_string += u' Started: - {6[start_time]!s} Duration: {6[duration]!s} ms' fmt_string += u'{5}' From 0d3d711e9cb7c3db90698e6d977664c42efa7d8b Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 8 Aug 2016 09:48:21 -0600 Subject: [PATCH 30/30] Lint fixes for 2016.3 branch --- salt/modules/rabbitmq.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index f10995326b6..c9098e686f2 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -312,11 +312,11 @@ def check_password(name, password, runas=None): runas = salt.utils.get_user() try: - res = __salt__['cmd.run'](['rabbitmqctl', 'status'], runas=runas, python_shell=False) - server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}',res) + res = __salt__['cmd.run'](['rabbitmqctl', 'status'], runas=runas, python_shell=False) + server_version = re.search(r'\{rabbit,"RabbitMQ","(.+)"\}', res) if server_version is None: - raise ValueError("") + raise ValueError server_version = server_version.group(1) version = [int(i) for i in server_version.split('.')] @@ -333,7 +333,7 @@ def check_password(name, password, runas=None): output_loglevel='quiet', python_shell=False) - return not 'Error:' in res + return 'Error:' not in res cmd = ('rabbit_auth_backend_internal:check_user_login' '(<<"{0}">>, [{{password, <<"{1}">>}}]).').format(