From 3b9326fda7d998bc62f5acb3e99f14e1cc1e1199 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Mon, 5 Jun 2017 12:36:31 -0600 Subject: [PATCH 01/76] Sign_minion_messages support --- salt/master.py | 10 ++++++++++ salt/minion.py | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/salt/master.py b/salt/master.py index 9012c73620..9f88caa306 100644 --- a/salt/master.py +++ b/salt/master.py @@ -19,6 +19,7 @@ import logging import multiprocessing import tempfile import traceback +import salt.serializers.msgpack # Import third party libs from Crypto.PublicKey import RSA @@ -1085,6 +1086,15 @@ class AESFuncs(object): return False if 'tok' in load: load.pop('tok') + + if 'sig' in load: + log.trace('Verifying signed event publish from minion') + sig = load.pop('sig') + this_minion_pubkey = os.path.join(self.opts['pki_dir'], 'minions/{0}'.format(load['id'])) + serialized_load = salt.serializers.msgpack.serialize(load) + if not salt.crypt.verify_signature(this_minion_pubkey, serialized_load, sig): + log.info('Signature for signed event from minion published on bus did not verify') + return load def _ext_nodes(self, load): diff --git a/salt/minion.py b/salt/minion.py index e47a56c18a..7e13917b98 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -19,6 +19,7 @@ import contextlib import multiprocessing from random import randint, shuffle from stat import S_IMODE +import salt.serializers.msgpack # Import Salt Libs # pylint: disable=import-error,no-name-in-module,redefined-builtin @@ -1185,6 +1186,12 @@ class Minion(MinionBase): else: return + if self.opts['sign_minion_messages']: + log.trace('Signing event being published onto the bus.') + minion_privkey_path = os.path.join(self.opts['pki_dir'], 'minion.pem') + sig = salt.crypt.sign_message(minion_privkey_path, salt.serializers.msgpack.serialize(load)) + load['sig'] = sig + def timeout_handler(*_): log.info('fire_master failed: master could not be contacted. Request timed out.') return True @@ -1383,7 +1390,7 @@ class Minion(MinionBase): iret = [] iret.append(single) tag = tagify([data['jid'], 'prog', opts['id'], str(ind)], 'job') - event_data = {'return': single} + minion_instance._fire_master(event_data, tag) ind += 1 ret['return'] = iret From bcc7874439b648d43d89dd39d4422cf5c596fffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Tue, 6 Jun 2017 11:52:00 +0200 Subject: [PATCH 02/76] Allow the user to get multiple statuses at once through globbing --- salt/modules/rh_service.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index c7ce0d51f7..608e372c3f 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -15,6 +15,8 @@ import glob import logging import os import stat +import fnmatch +import re # Import salt libs import salt.utils @@ -470,22 +472,34 @@ def reload_(name): def status(name, sig=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Returns a bool indicating whether the service is running. + + If ``name`` contains globbing characters (such as ``*``, ``?``, or anything between brackets), + returns a dict name/bool instead of a simple bool. CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status sshd + salt '*' service.status '*' ''' - if _service_is_upstart(name): - cmd = 'status {0}'.format(name) - return 'start/running' in __salt__['cmd.run'](cmd, python_shell=False) - if sig: - return bool(__salt__['status.pid'](sig)) - cmd = '/sbin/service {0} status'.format(name) - return __salt__['cmd.retcode'](cmd, python_shell=False, ignore_retcode=True) == 0 + if re.search('\*|\?|\[.+\]', name): + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + if _service_is_upstart(service): + cmd = 'status {0}'.format(service) + results[service] = 'start/running' in __salt__['cmd.run'](cmd, python_shell=False) + if sig: + results[service] = bool(__salt__['status.pid'](sig)) + cmd = '/sbin/service {0} status'.format(service) + results[service] = __salt__['cmd.retcode'](cmd, python_shell=False, ignore_retcode=True) == 0 + if re.search('\*|\?|\[.+\]', name): + return results + return results[name] def delete(name, **kwargs): From f38afb5f4846c4e5c827b3f523b0636fc973d72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Tue, 6 Jun 2017 12:54:24 +0200 Subject: [PATCH 03/76] Add same feature for windows services --- salt/modules/win_service.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 47e1e8441a..b20cad2f80 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -10,6 +10,8 @@ from __future__ import absolute_import import salt.utils import time import logging +import fnmatch +import re from salt.exceptions import CommandExecutionError # Import 3rd party libs @@ -534,11 +536,16 @@ def status(name, sig=None): salt '*' service.status [service signature] ''' - if info(name)['Status'] in ['Running', 'Stop Pending']: - return True - - return False - + if re.search('\*|\?|\[.+\]', name): + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] + if re.search('\*|\?|\[.+\]', name): + return results + return results[name] def getsid(name): ''' From 200522eae5bdfbc23461eb99ff1c2a15b0261cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Tue, 6 Jun 2017 18:57:37 +0200 Subject: [PATCH 04/76] Cleaner params and updated documentation for win_services --- salt/modules/win_service.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index b20cad2f80..8b0b1b9315 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -519,9 +519,11 @@ def execute_salt_restart_task(): return __salt__['task.run'](name='restart-salt-minion') -def status(name, sig=None): +def status(*names, **kwargs): ''' - Return the status for a service + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. Args: name (str): The name of the service to check @@ -529,23 +531,33 @@ def status(name, sig=None): Returns: bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status [service signature] + salt '*' service.status + salt '*' service.status ... ''' - if re.search('\*|\?|\[.+\]', name): - services = fnmatch.filter(get_all(), name) - else: - services = [name] + + if len(names) == 0: + return '' + results = {} - for service in services: - results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] - if re.search('\*|\?|\[.+\]', name): - return results - return results[name] + all_services = get_all() + for name in names: + if re.search('\*|\?|\[.+\]', name): + services = fnmatch.filter(all_services, name) + else: + services = [name] + for service in services: + if service in results: + continue + results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] + if len(names) == 0 and re.search('\*|\?|\[.+\]', names[0]) == false: + return results[name] + return results def getsid(name): ''' From 4540f82aaae3244551386c8c85216b8722ea4125 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Tue, 6 Jun 2017 13:49:16 -0600 Subject: [PATCH 05/76] Port salt-proxy tests to the testsuite changes in Nitrogen. --- tests/integration/__init__.py | 68 ++++++++++++++++++++++++++++------- tests/support/paths.py | 1 + tests/support/processes.py | 7 ++++ tests/support/runtests.py | 1 + 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index 95c76cbb29..12ce122c01 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -453,6 +453,43 @@ class TestDaemon(object): ) sys.stdout.flush() + if self.parser.options.proxy: + try: + sys.stdout.write( + ' * {LIGHT_YELLOW}Starting salt-proxy ... {ENDC}'.format(**self.colors) + ) + sys.stdout.flush() + self.proxy_process = start_daemon( + daemon_name='salt-proxy', + daemon_id=self.master_opts['id'], + daemon_log_prefix='salt-proxy/{}'.format(self.proxy_opts['id']), + daemon_cli_script_name='proxy', + daemon_config=self.proxy_opts, + daemon_config_dir=RUNTIME_VARS.TMP_CONF_DIR, + daemon_class=SaltProxy, + bin_dir_path=SCRIPT_DIR, + fail_hard=True, + start_timeout=30) + sys.stdout.write( + '\r{0}\r'.format( + ' ' * getattr(self.parser.options, 'output_columns', PNUM) + ) + ) + sys.stdout.write( + ' * {LIGHT_GREEN}Starting salt-proxy ... STARTED!\n{ENDC}'.format(**self.colors) + ) + sys.stdout.flush() + except (RuntimeWarning, RuntimeError): + sys.stdout.write( + '\r{0}\r'.format( + ' ' * getattr(self.parser.options, 'output_columns', PNUM) + ) + ) + sys.stdout.write( + ' * {LIGHT_RED}Starting salt-proxy ... FAILED!\n{ENDC}'.format(**self.colors) + ) + sys.stdout.flush() + def start_raet_daemons(self): ''' Fire up the raet daemons! @@ -653,6 +690,7 @@ class TestDaemon(object): * syndic * syndic_master * sub_minion + * proxy ''' return RUNTIME_VARS.RUNTIME_CONFIGS[role] @@ -735,14 +773,14 @@ class TestDaemon(object): syndic_master_opts['pki_dir'] = os.path.join(TMP, 'rootdir-syndic-master', 'pki', 'master') # This proxy connects to master - # proxy_opts = salt.config._read_conf_file(os.path.join(CONF_DIR, 'proxy')) - # proxy_opts['cachedir'] = os.path.join(TMP, 'rootdir', 'cache') + proxy_opts = salt.config._read_conf_file(os.path.join(CONF_DIR, 'proxy')) + proxy_opts['cachedir'] = os.path.join(TMP, 'rootdir-proxy', 'cache') # proxy_opts['user'] = running_tests_user - # proxy_opts['config_dir'] = TMP_CONF_DIR - # proxy_opts['root_dir'] = os.path.join(TMP, 'rootdir') - # proxy_opts['pki_dir'] = os.path.join(TMP, 'rootdir', 'pki') - # proxy_opts['hosts.file'] = os.path.join(TMP, 'rootdir', 'hosts') - # proxy_opts['aliases.file'] = os.path.join(TMP, 'rootdir', 'aliases') + proxy_opts['config_dir'] = RUNTIME_VARS.TMP_CONF_DIR + proxy_opts['root_dir'] = os.path.join(TMP, 'rootdir-proxy') + proxy_opts['pki_dir'] = os.path.join(TMP, 'rootdir-proxy', 'pki') + proxy_opts['hosts.file'] = os.path.join(TMP, 'rootdir-proxy', 'hosts') + proxy_opts['aliases.file'] = os.path.join(TMP, 'rootdir-proxy', 'aliases') if transport == 'raet': master_opts['transport'] = 'raet' @@ -758,6 +796,7 @@ class TestDaemon(object): minion_opts['transport'] = 'tcp' sub_minion_opts['transport'] = 'tcp' syndic_master_opts['transport'] = 'tcp' + proxy_opts['transport'] = 'tcp' # Set up config options that require internal data master_opts['pillar_roots'] = syndic_master_opts['pillar_roots'] = { @@ -815,14 +854,16 @@ class TestDaemon(object): sub_minion_opts[optname] = optname_path syndic_opts[optname] = optname_path syndic_master_opts[optname] = optname_path + proxy_opts[optname] = optname_path master_opts['runtests_conn_check_port'] = get_unused_localhost_port() minion_opts['runtests_conn_check_port'] = get_unused_localhost_port() sub_minion_opts['runtests_conn_check_port'] = get_unused_localhost_port() syndic_opts['runtests_conn_check_port'] = get_unused_localhost_port() syndic_master_opts['runtests_conn_check_port'] = get_unused_localhost_port() + proxy_opts['runtests_conn_check_port'] = get_unused_localhost_port() - for conf in (master_opts, minion_opts, sub_minion_opts, syndic_opts, syndic_master_opts): + for conf in (master_opts, minion_opts, sub_minion_opts, syndic_opts, syndic_master_opts, proxy_opts): if 'engines' not in conf: conf['engines'] = [] conf['engines'].append({'salt_runtests': {}}) @@ -839,7 +880,7 @@ class TestDaemon(object): # ----- Transcribe Configuration ----------------------------------------------------------------------------> for entry in os.listdir(RUNTIME_VARS.CONF_DIR): - if entry in ('master', 'minion', 'sub_minion', 'syndic', 'syndic_master'): + if entry in ('master', 'minion', 'sub_minion', 'syndic', 'syndic_master', 'proxy'): # These have runtime computed values and will be handled # differently continue @@ -855,7 +896,7 @@ class TestDaemon(object): os.path.join(RUNTIME_VARS.TMP_CONF_DIR, entry) ) - for entry in ('master', 'minion', 'sub_minion', 'syndic', 'syndic_master'): + for entry in ('master', 'minion', 'sub_minion', 'syndic', 'syndic_master', 'proxy'): computed_config = copy.deepcopy(locals()['{0}_opts'.format(entry)]) with salt.utils.fopen(os.path.join(RUNTIME_VARS.TMP_CONF_DIR, entry), 'w') as fp_: fp_.write(yaml.dump(computed_config, default_flow_style=False)) @@ -888,12 +929,14 @@ class TestDaemon(object): ) sub_minion_opts = salt.config.minion_config(os.path.join(RUNTIME_VARS.TMP_SUB_MINION_CONF_DIR, 'minion')) syndic_master_opts = salt.config.master_config(os.path.join(RUNTIME_VARS.TMP_SYNDIC_MASTER_CONF_DIR, 'master')) + proxy_opts = salt.config.proxy_config(os.path.join(RUNTIME_VARS.TMP_CONF_DIR, 'proxy')) RUNTIME_VARS.RUNTIME_CONFIGS['master'] = freeze(master_opts) RUNTIME_VARS.RUNTIME_CONFIGS['minion'] = freeze(minion_opts) RUNTIME_VARS.RUNTIME_CONFIGS['syndic'] = freeze(syndic_opts) RUNTIME_VARS.RUNTIME_CONFIGS['sub_minion'] = freeze(sub_minion_opts) RUNTIME_VARS.RUNTIME_CONFIGS['syndic_master'] = freeze(syndic_master_opts) + RUNTIME_VARS.RUNTIME_CONFIGS['proxy'] = freeze(proxy_opts) verify_env([os.path.join(master_opts['pki_dir'], 'minions'), os.path.join(master_opts['pki_dir'], 'minions_pre'), @@ -944,6 +987,7 @@ class TestDaemon(object): cls.sub_minion_opts = sub_minion_opts cls.syndic_opts = syndic_opts cls.syndic_master_opts = syndic_master_opts + cls.proxy_opts = proxy_opts # <---- Verify Environment ----------------------------------------------------------------------------------- def __exit__(self, type, value, traceback): @@ -952,8 +996,8 @@ class TestDaemon(object): ''' self.sub_minion_process.terminate() self.minion_process.terminate() - # if hasattr(self, 'proxy_process'): - # self.proxy_process.terminate() + if hasattr(self, 'proxy_process'): + self.proxy_process.terminate() self.master_process.terminate() try: self.syndic_process.terminate() diff --git a/tests/support/paths.py b/tests/support/paths.py index 09c234c818..0aae3ab1e3 100644 --- a/tests/support/paths.py +++ b/tests/support/paths.py @@ -57,6 +57,7 @@ TMP_CONF_DIR = os.path.join(TMP, 'config') TMP_SUB_MINION_CONF_DIR = os.path.join(TMP_CONF_DIR, 'sub-minion') TMP_SYNDIC_MINION_CONF_DIR = os.path.join(TMP_CONF_DIR, 'syndic-minion') TMP_SYNDIC_MASTER_CONF_DIR = os.path.join(TMP_CONF_DIR, 'syndic-master') +TMP_PROXY_CONF_DIR = os.path.join(TMP_CONF_DIR, 'proxy') CONF_DIR = os.path.join(INTEGRATION_TEST_DIR, 'files', 'conf') PILLAR_DIR = os.path.join(FILES, 'pillar') TMP_SCRIPT_DIR = os.path.join(TMP, 'scripts') diff --git a/tests/support/processes.py b/tests/support/processes.py index 88c41b9c12..d23a82cc0b 100644 --- a/tests/support/processes.py +++ b/tests/support/processes.py @@ -24,6 +24,7 @@ from pytestsalt.fixtures.daemons import SaltCall as PytestSaltCall from pytestsalt.fixtures.daemons import SaltMaster as PytestSaltMaster from pytestsalt.fixtures.daemons import SaltMinion as PytestSaltMinion from pytestsalt.fixtures.daemons import SaltSyndic as PytestSaltSyndic +from pytestsalt.fixtures.daemons import SaltProxy as PytestSaltProxy # Import tests support libs from tests.support.paths import ScriptPathMixin @@ -87,6 +88,12 @@ class SaltRun(ScriptPathMixin, PytestSaltRun): super(SaltRun, self).__init__(None, *args, **kwargs) +class SaltProxy(GetSaltRunFixtureMixin, PytestSaltProxy): + ''' + Class which runs the salt-proxy daemon + ''' + + class SaltMinion(GetSaltRunFixtureMixin, PytestSaltMinion): ''' Class which runs the salt-minion daemon diff --git a/tests/support/runtests.py b/tests/support/runtests.py index ce4e195915..6bee7d4c54 100644 --- a/tests/support/runtests.py +++ b/tests/support/runtests.py @@ -206,6 +206,7 @@ RUNTIME_VARS = RuntimeVars( TMP_CONF_DIR=paths.TMP_CONF_DIR, TMP_CONF_MASTER_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'master.d'), TMP_CONF_MINION_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'minion.d'), + TMP_CONF_PROXY_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'proxy.d'), TMP_CONF_CLOUD_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'cloud.conf.d'), TMP_CONF_CLOUD_PROFILE_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'cloud.profiles.d'), TMP_CONF_CLOUD_PROVIDER_INCLUDES=os.path.join(paths.TMP_CONF_DIR, 'cloud.providers.d'), From c3917d1e9141e79a50443801f13de0573120fd14 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Tue, 6 Jun 2017 14:56:43 -0600 Subject: [PATCH 06/76] Fat finger fix. --- salt/minion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/minion.py b/salt/minion.py index 7e13917b98..6253d63200 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1390,7 +1390,7 @@ class Minion(MinionBase): iret = [] iret.append(single) tag = tagify([data['jid'], 'prog', opts['id'], str(ind)], 'job') - + event_data = {'return': single} minion_instance._fire_master(event_data, tag) ind += 1 ret['return'] = iret From 05aac74fde9a5858dc768fd5d8570fb353853eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Wed, 7 Jun 2017 10:28:32 +0200 Subject: [PATCH 07/76] Rollback to previous parameters declaration for backwards-compatibility (in case sig is used) --- salt/modules/win_service.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 8b0b1b9315..9c7f6d8719 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -519,7 +519,7 @@ def execute_salt_restart_task(): return __salt__['task.run'](name='restart-salt-minion') -def status(*names, **kwargs): +def status(name, sig = None): ''' Return the status for a service. If the name contains globbing, a dict mapping service name to True/False @@ -538,26 +538,19 @@ def status(*names, **kwargs): .. code-block:: bash salt '*' service.status - salt '*' service.status ... ''' - if len(names) == 0: - return '' - results = {} all_services = get_all() - for name in names: - if re.search('\*|\?|\[.+\]', name): - services = fnmatch.filter(all_services, name) - else: - services = [name] - for service in services: - if service in results: - continue - results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] - if len(names) == 0 and re.search('\*|\?|\[.+\]', names[0]) == false: - return results[name] - return results + if re.search('\*|\?|\[.+\]', name): + services = fnmatch.filter(all_services, name) + else: + services = [name] + for service in services: + results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] + if re.search('\*|\?|\[.+\]', names[0]): + return results + return results[name] def getsid(name): ''' From 239e2bcf63a4760732d879f4860fc0490d228dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Wed, 7 Jun 2017 12:29:05 +0200 Subject: [PATCH 08/76] Add same feature to most service modules (except mac_service) --- salt/modules/debian_service.py | 30 +++++++++++++++--- salt/modules/freebsdservice.py | 36 ++++++++++++++++------ salt/modules/gentoo_service.py | 31 ++++++++++++++++--- salt/modules/launchctl.py | 56 +++++++++++++++++++++++----------- salt/modules/netbsdservice.py | 30 +++++++++++++++--- salt/modules/openbsdservice.py | 30 +++++++++++++++--- salt/modules/rest_service.py | 33 +++++++++++++++----- salt/modules/rh_service.py | 31 ++++++++++++------- salt/modules/service.py | 29 +++++++++++++++--- salt/modules/smf.py | 30 +++++++++++++----- salt/modules/ssh_service.py | 35 ++++++++++++++++----- salt/modules/systemd.py | 34 ++++++++++++++++----- salt/modules/upstart.py | 48 +++++++++++++++++++++-------- salt/modules/win_service.py | 5 +-- 14 files changed, 351 insertions(+), 107 deletions(-) diff --git a/salt/modules/debian_service.py b/salt/modules/debian_service.py index 726a4b913e..0559b430ba 100644 --- a/salt/modules/debian_service.py +++ b/salt/modules/debian_service.py @@ -224,19 +224,39 @@ def force_reload(name): def status(name, sig=None): ''' - Return the status for a service, pass a signature to use to find - the service via ps + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = _service_cmd(name, 'status') - return not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = _service_cmd(service, 'status') + results[service] = not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + if contains_globbing: + return results + return results[name] def _osrel(): diff --git a/salt/modules/freebsdservice.py b/salt/modules/freebsdservice.py index 3d7f253a20..08cdb87480 100644 --- a/salt/modules/freebsdservice.py +++ b/salt/modules/freebsdservice.py @@ -473,24 +473,40 @@ def reload_(name, jail=None): def status(name, sig=None, jail=None): ''' - Return the status for a service (True or False). - - name - Name of service + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. .. versionchanged:: 2016.3.4 - jail: optional jid or jail name + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = '{0} {1} onestatus'.format(_cmd(jail), name) - return not __salt__['cmd.retcode'](cmd, - python_shell=False, - ignore_retcode=True) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = '{0} {1} onestatus'.format(_cmd(jail), service) + results[service] = not __salt__['cmd.retcode'](cmd, + python_shell=False, + ignore_retcode=True) + if contains_globbing: + return results + return results[name] diff --git a/salt/modules/gentoo_service.py b/salt/modules/gentoo_service.py index 32dfcde69c..e3ebe0b4a8 100644 --- a/salt/modules/gentoo_service.py +++ b/salt/modules/gentoo_service.py @@ -236,9 +236,17 @@ def zap(name): def status(name, sig=None): ''' - Return the status for a service, returns the PID or an empty string if the - service is running or not, pass a signature to use to find the service via - ps + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: @@ -248,8 +256,21 @@ def status(name, sig=None): ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = _service_cmd(name, 'status') - return not _ret_code(cmd) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = _service_cmd(service, 'status') + results[service] = not _ret_code(cmd) + if contains_globbing: + return results + return results[name] + + def enable(name, **kwargs): diff --git a/salt/modules/launchctl.py b/salt/modules/launchctl.py index 62ed41cfd1..3544e43731 100644 --- a/salt/modules/launchctl.py +++ b/salt/modules/launchctl.py @@ -206,33 +206,53 @@ def missing(job_label): return False if _service_by_name(job_label) else True -def status(job_label, runas=None): +def status(name, runas=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Return the status for a service via systemd. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + runas (str): User to run launchctl commands + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status ''' - service = _service_by_name(job_label) - lookup_name = service['plist']['Label'] if service else job_label - launchctl_data = _get_launchctl_data(lookup_name, runas=runas) - - if launchctl_data: - if BEFORE_YOSEMITE: - if six.PY3: - return 'PID' in plistlib.loads(launchctl_data) - else: - return 'PID' in dict(plistlib.readPlistFromString(launchctl_data)) - else: - pattern = '"PID" = [0-9]+;' - return True if re.search(pattern, launchctl_data) else False + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) else: - return False + services = [name] + results = {} + for service in services: + service_info = _service_by_name(service) + + lookup_name = service_info['plist']['Label'] if service_info else service + launchctl_data = _get_launchctl_data(lookup_name, runas=runas) + + if launchctl_data: + if BEFORE_YOSEMITE: + if six.PY3: + results[service] = 'PID' in plistlib.loads(launchctl_data) + else: + results[service] = 'PID' in dict(plistlib.readPlistFromString(launchctl_data)) + else: + pattern = '"PID" = [0-9]+;' + results[service] = True if re.search(pattern, launchctl_data) else False + else: + results[service] = False + if contains_globbing: + return results + return results[name] def stop(job_label, runas=None): diff --git a/salt/modules/netbsdservice.py b/salt/modules/netbsdservice.py index 974c691869..c153039804 100644 --- a/salt/modules/netbsdservice.py +++ b/salt/modules/netbsdservice.py @@ -103,19 +103,39 @@ def force_reload(name): def status(name, sig=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = '/etc/rc.d/{0} onestatus'.format(name) - return not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = '/etc/rc.d/{0} onestatus'.format(service) + results[service] = not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + if contains_globbing: + return results + return results[name] def _get_svc(rcd, service_status): diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index 32ea278742..cac37bca75 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -93,19 +93,39 @@ def restart(name): def status(name, sig=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = '/etc/rc.d/{0} -f check'.format(name) - return not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = '/etc/rc.d/{0} -f check'.format(service) + results[service] = not __salt__['cmd.retcode'](cmd, ignore_retcode=True) + if contains_globbing: + return results + return results[name] def reload_(name): diff --git a/salt/modules/rest_service.py b/salt/modules/rest_service.py index 4ac72aedd7..a041c6d41f 100644 --- a/salt/modules/rest_service.py +++ b/salt/modules/rest_service.py @@ -115,11 +115,20 @@ def restart(name, sig=None): def status(name, sig=None): ''' - Return the status for a service via rest_sample, returns a bool - whether the service is running. + Return the status for a service via rest_sample. + If the name contains globbing, a dict mapping service name to True/False + values is returned. .. versionadded:: 2015.8.0 + Args: + name (str): The name of the service to check + sig (str): Not implemented + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise + CLI Example: .. code-block:: bash @@ -128,11 +137,21 @@ def status(name, sig=None): ''' proxy_fn = 'rest_sample.service_status' - resp = __proxy__[proxy_fn](name) - if resp['comment'] == 'stopped': - return False - if resp['comment'] == 'running': - return True + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + resp = __proxy__[proxy_fn](service) + if resp['comment'] == 'running': + results[service] = True + else: + results[service] = False + if contains_globbing: + return results + return results[name] def running(name, sig=None): diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index 608e372c3f..9ec962bfbc 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -472,19 +472,29 @@ def reload_(name): def status(name, sig=None): ''' - Returns a bool indicating whether the service is running. + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. - If ``name`` contains globbing characters (such as ``*``, ``?``, or anything between brackets), - returns a dict name/bool instead of a simple bool. + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status sshd - salt '*' service.status '*' + salt '*' service.status [service signature] ''' - if re.search('\*|\?|\[.+\]', name): + if sig: + return bool(__salt__['status.pid'](sig)) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: services = fnmatch.filter(get_all(), name) else: services = [name] @@ -493,11 +503,10 @@ def status(name, sig=None): if _service_is_upstart(service): cmd = 'status {0}'.format(service) results[service] = 'start/running' in __salt__['cmd.run'](cmd, python_shell=False) - if sig: - results[service] = bool(__salt__['status.pid'](sig)) - cmd = '/sbin/service {0} status'.format(service) - results[service] = __salt__['cmd.retcode'](cmd, python_shell=False, ignore_retcode=True) == 0 - if re.search('\*|\?|\[.+\]', name): + else: + cmd = '/sbin/service {0} status'.format(service) + results[service] = __salt__['cmd.retcode'](cmd, python_shell=False, ignore_retcode=True) == 0 + if contains_globbing: return results return results[name] diff --git a/salt/modules/service.py b/salt/modules/service.py index bb7133ee99..c437d06712 100644 --- a/salt/modules/service.py +++ b/salt/modules/service.py @@ -134,9 +134,17 @@ def restart(name): def status(name, sig=None): ''' - Return the status for a service, returns the PID or an empty string if the - service is running or not, pass a signature to use to find the service via - ps + Return the status for a service. + If the name contains globbing, a dict mapping service name to PID or empty + string is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + string: PID if running, empty otherwise + dict: Maps service name to PID if running, empty string otherwise CLI Example: @@ -144,7 +152,20 @@ def status(name, sig=None): salt '*' service.status [service signature] ''' - return __salt__['status.pid'](sig if sig else name) + if sig: + return __salt__['status.pid'](sig) + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + results[service] = __salt__['status.pid'](service) + if contains_globbing: + return results + return results[name] def reload_(name): diff --git a/salt/modules/smf.py b/salt/modules/smf.py index 0fb8e55f68..3043c66356 100644 --- a/salt/modules/smf.py +++ b/salt/modules/smf.py @@ -226,8 +226,17 @@ def reload_(name): def status(name, sig=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Not implemented + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: @@ -235,12 +244,19 @@ def status(name, sig=None): salt '*' service.status ''' - cmd = '/usr/bin/svcs -H -o STATE {0}'.format(name) - line = __salt__['cmd.run'](cmd, python_shell=False) - if line == 'online': - return True + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) else: - return False + services = [name] + results = {} + for service in services: + cmd = '/usr/bin/svcs -H -o STATE {0}'.format(service) + line = __salt__['cmd.run'](cmd, python_shell=False) + results[service] = line == 'online': + if contains_globbing: + return results + return results[name] def enable(name, **kwargs): diff --git a/salt/modules/ssh_service.py b/salt/modules/ssh_service.py index deec797e75..617cfa1691 100644 --- a/salt/modules/ssh_service.py +++ b/salt/modules/ssh_service.py @@ -60,7 +60,7 @@ def list_(): def start(name, sig=None): ''' - Start the specified service on the rest_sample + Start the specified service on the ssh_sample CLI Example: @@ -103,8 +103,17 @@ def restart(name, sig=None): def status(name, sig=None): ''' - Return the status for a service via rest_sample, returns a bool - whether the service is running. + Return the status for a service via ssh_sample. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Not implemented + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: @@ -114,11 +123,21 @@ def status(name, sig=None): ''' proxy_fn = 'ssh_sample.service_status' - resp = __proxy__[proxy_fn](name) - if resp['comment'] == 'stopped': - return False - if resp['comment'] == 'running': - return True + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + resp = __proxy__[proxy_fn](service) + if resp['comment'] == 'running': + results[service] = True + else: + results[service] = False + if contains_globbing: + return results + return results[name] def running(name, sig=None): diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index a0bc289867..b4f194495f 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -876,19 +876,39 @@ def force_reload(name): # established by Salt's service management states. def status(name, sig=None): # pylint: disable=unused-argument ''' - Return the status for a service via systemd, returns ``True`` if the - service is running and ``False`` if it is not. + Return the status for a service via systemd. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Not implemented + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' - _check_for_unit_changes(name) - return __salt__['cmd.retcode'](_systemctl_cmd('is-active', name), - python_shell=False, - ignore_retcode=True) == 0 + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + _check_for_unit_changes(service) + results[service] = __salt__['cmd.retcode'](_systemctl_cmd('is-active', service), + python_shell=False, + ignore_retcode=True) == 0 + if contains_globbing: + return results + return results[name] + # The unused kwargs argument is required to maintain consistency with the API diff --git a/salt/modules/upstart.py b/salt/modules/upstart.py index 5ad08062ee..f1fd825199 100644 --- a/salt/modules/upstart.py +++ b/salt/modules/upstart.py @@ -426,27 +426,49 @@ def force_reload(name): def status(name, sig=None): ''' - Return the status for a service, returns a bool whether the service is - running. + Return the status for a service. + If the name contains globbing, a dict mapping service name to True/False + values is returned. + + Args: + name (str): The name of the service to check + sig (str): Signature to use to find the service via ps + + Returns: + bool: True if running, False otherwise + dict: Maps service name to True if running, False otherwise CLI Example: .. code-block:: bash - salt '*' service.status + salt '*' service.status [service signature] ''' if sig: return bool(__salt__['status.pid'](sig)) - cmd = ['service', name, 'status'] - if _service_is_upstart(name): - # decide result base on cmd output, thus ignore retcode, - # which makes cmd output not at error lvl even when cmd fail. - return 'start/running' in __salt__['cmd.run'](cmd, python_shell=False, - ignore_retcode=True) - # decide result base on retcode, thus ignore output (set quite) - # because there is no way to avoid logging at error lvl when - # service is not running - retcode != 0 (which is totally relevant). - return not bool(__salt__['cmd.retcode'](cmd, python_shell=False, + + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: + services = fnmatch.filter(get_all(), name) + else: + services = [name] + results = {} + for service in services: + cmd = ['service', service, 'status'] + if _service_is_upstart(service): + # decide result base on cmd output, thus ignore retcode, + # which makes cmd output not at error lvl even when cmd fail. + results[service] = 'start/running' in __salt__['cmd.run'](cmd, python_shell=False, + ignore_retcode=True) + else: + # decide result base on retcode, thus ignore output (set quite) + # because there is no way to avoid logging at error lvl when + # service is not running - retcode != 0 (which is totally relevant). + results[service] = not bool(__salt__['cmd.retcode'](cmd, python_shell=False, + if contains_globbing: + return results + return results[name] + quite=True)) diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 9c7f6d8719..0055debdab 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -542,13 +542,14 @@ def status(name, sig = None): results = {} all_services = get_all() - if re.search('\*|\?|\[.+\]', name): + contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + if contains_globbing: services = fnmatch.filter(all_services, name) else: services = [name] for service in services: results[service] = info(service)['Status'] in ['Running', 'Stop Pending'] - if re.search('\*|\?|\[.+\]', names[0]): + if contains_globbing: return results return results[name] From e44673cdae485cb4ba062170dc63bc7937d841b8 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Wed, 7 Jun 2017 15:23:34 -0600 Subject: [PATCH 09/76] Add caching of key. --- salt/crypt.py | 35 ++++++++++++++++++++++++++++++++--- salt/master.py | 5 +++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/salt/crypt.py b/salt/crypt.py index e9e4f15dad..d1ad8efa3b 100644 --- a/salt/crypt.py +++ b/salt/crypt.py @@ -37,6 +37,7 @@ except ImportError: # Import salt libs import salt.defaults.exitcodes import salt.utils +import salt.utils.decorators import salt.payload import salt.transport.client import salt.utils.rsax931 @@ -127,13 +128,41 @@ def gen_keys(keydir, keyname, keysize, user=None): return priv +@salt.utils.decorators.memoize +def _get_key_with_evict(path, timestamp): + ''' + Load a key from disk. `timestamp` above is intended to be the timestamp + of the file's last modification. This fn is memoized so if it is called with the + same path and timestamp (the file's last modified time) the second time + the result is returned from the memoiziation. If the file gets modified + then the params are different and the key is loaded from disk. + ''' + log.debug('salt.crypt._get_key_with_evict: Loading private key') + with salt.utils.fopen(path) as f: + key = RSA.importKey(f.read()) + return key + + +def _get_rsa_key(path): + ''' + Read a key off the disk. Poor man's simple cache in effect here, + we memoize the result of calling _get_rsa_with_evict. This means + the first time _get_key_with_evict is called with a path and a timestamp + the result is cached. If the file (the private key) does not change + then its timestamp will not change and the next time the result is returned + from the cache. If the key DOES change the next time _get_rsa_with_evict + is called it is called with different parameters and the fn is run fully to + retrieve the key from disk. + ''' + log.debug('salt.crypt._get_rsa_key: Loading private key') + return _get_key_with_evict(path, os.path.getmtime(path)) + + def sign_message(privkey_path, message): ''' Use Crypto.Signature.PKCS1_v1_5 to sign a message. Returns the signature. ''' - log.debug('salt.crypt.sign_message: Loading private key') - with salt.utils.fopen(privkey_path) as f: - key = RSA.importKey(f.read()) + key = _get_rsa_key(privkey_path) log.debug('salt.crypt.sign_message: Signing message.') signer = PKCS1_v1_5.new(key) return signer.sign(SHA.new(message)) diff --git a/salt/master.py b/salt/master.py index 9f88caa306..fc8023ef48 100644 --- a/salt/master.py +++ b/salt/master.py @@ -1084,8 +1084,6 @@ class AESFuncs(object): ) ) return False - if 'tok' in load: - load.pop('tok') if 'sig' in load: log.trace('Verifying signed event publish from minion') @@ -1095,6 +1093,9 @@ class AESFuncs(object): if not salt.crypt.verify_signature(this_minion_pubkey, serialized_load, sig): log.info('Signature for signed event from minion published on bus did not verify') + if 'tok' in load: + load.pop('tok') + return load def _ext_nodes(self, load): From fdf66e25f1e5c99f01a34e4c2bc54a9e3d60106f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Thu, 8 Jun 2017 11:07:03 +0200 Subject: [PATCH 10/76] Add versionchanged --- salt/modules/debian_service.py | 3 +++ salt/modules/freebsdservice.py | 3 +++ salt/modules/gentoo_service.py | 3 +++ salt/modules/launchctl.py | 3 +++ salt/modules/netbsdservice.py | 3 +++ salt/modules/openbsdservice.py | 3 +++ salt/modules/rest_service.py | 3 +++ salt/modules/rh_service.py | 3 +++ salt/modules/service.py | 3 +++ salt/modules/smf.py | 3 +++ salt/modules/ssh_service.py | 3 +++ salt/modules/systemd.py | 3 +++ salt/modules/upstart.py | 3 +++ salt/modules/win_service.py | 3 +++ 14 files changed, 42 insertions(+) diff --git a/salt/modules/debian_service.py b/salt/modules/debian_service.py index 0559b430ba..1bfdb89905 100644 --- a/salt/modules/debian_service.py +++ b/salt/modules/debian_service.py @@ -228,6 +228,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/freebsdservice.py b/salt/modules/freebsdservice.py index 08cdb87480..31a710b575 100644 --- a/salt/modules/freebsdservice.py +++ b/salt/modules/freebsdservice.py @@ -479,6 +479,9 @@ def status(name, sig=None, jail=None): .. versionchanged:: 2016.3.4 + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/gentoo_service.py b/salt/modules/gentoo_service.py index e3ebe0b4a8..aaa2ba836c 100644 --- a/salt/modules/gentoo_service.py +++ b/salt/modules/gentoo_service.py @@ -240,6 +240,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/launchctl.py b/salt/modules/launchctl.py index 3544e43731..76747725f1 100644 --- a/salt/modules/launchctl.py +++ b/salt/modules/launchctl.py @@ -212,6 +212,9 @@ def status(name, runas=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check runas (str): User to run launchctl commands diff --git a/salt/modules/netbsdservice.py b/salt/modules/netbsdservice.py index c153039804..c4dcaee82b 100644 --- a/salt/modules/netbsdservice.py +++ b/salt/modules/netbsdservice.py @@ -107,6 +107,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index cac37bca75..97725e2518 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -97,6 +97,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/rest_service.py b/salt/modules/rest_service.py index a041c6d41f..261db384d2 100644 --- a/salt/modules/rest_service.py +++ b/salt/modules/rest_service.py @@ -121,6 +121,9 @@ def status(name, sig=None): .. versionadded:: 2015.8.0 + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Not implemented diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index 9ec962bfbc..f2b0ff216c 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -476,6 +476,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/service.py b/salt/modules/service.py index c437d06712..42d483140f 100644 --- a/salt/modules/service.py +++ b/salt/modules/service.py @@ -138,6 +138,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to PID or empty string is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/smf.py b/salt/modules/smf.py index 3043c66356..dbc1ee3af0 100644 --- a/salt/modules/smf.py +++ b/salt/modules/smf.py @@ -230,6 +230,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Not implemented diff --git a/salt/modules/ssh_service.py b/salt/modules/ssh_service.py index 617cfa1691..27b5ba3012 100644 --- a/salt/modules/ssh_service.py +++ b/salt/modules/ssh_service.py @@ -107,6 +107,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Not implemented diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index b4f194495f..ec175497d9 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -880,6 +880,9 @@ def status(name, sig=None): # pylint: disable=unused-argument If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Not implemented diff --git a/salt/modules/upstart.py b/salt/modules/upstart.py index f1fd825199..4091331327 100644 --- a/salt/modules/upstart.py +++ b/salt/modules/upstart.py @@ -430,6 +430,9 @@ def status(name, sig=None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Signature to use to find the service via ps diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index 0055debdab..bca86ea931 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -525,6 +525,9 @@ def status(name, sig = None): If the name contains globbing, a dict mapping service name to True/False values is returned. + .. versionchanged:: Oxygen + The service name can now be a glob (e.g. ``salt*``) + Args: name (str): The name of the service to check sig (str): Not supported on Windows From b51e8ee6cc8e390c81e0e4403aca94965848acf8 Mon Sep 17 00:00:00 2001 From: Vasili Syrakis Date: Thu, 8 Jun 2017 21:22:54 +1000 Subject: [PATCH 11/76] cloud vmware get_instance [size] #38814 changed from str to dict --- salt/cloud/clouds/vmware.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 7b646525f1..b394da17ba 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -988,7 +988,10 @@ def _format_instance_info_select(vm, selection): if 'size' in selection: cpu = vm["config.hardware.numCPU"] if "config.hardware.numCPU" in vm else "N/A" ram = "{0} MB".format(vm["config.hardware.memoryMB"]) if "config.hardware.memoryMB" in vm else "N/A" - vm_select_info['size'] = u"cpu: {0}\nram: {1}".format(cpu, ram) + vm_select_info['size'] = { + 'cpu': cpu, + 'ram': ram + } if 'state' in selection: vm_select_info['state'] = str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A" @@ -1175,7 +1178,10 @@ def _format_instance_info(vm): vm_full_info = { 'id': str(vm['name']), 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", - 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), + 'size': { + 'cpu': cpu, + 'ram': ram + }, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': ip_addresses, 'public_ips': [], @@ -1579,7 +1585,10 @@ def list_nodes(kwargs=None, call=None): vm_info = { 'id': vm["name"], 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", - 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), + 'size': { + 'cpu': cpu, + 'ram': ram + }, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [], 'public_ips': [] From fab282e5148100e6079d4a278a41445045fa3e64 Mon Sep 17 00:00:00 2001 From: Vasili Syrakis Date: Fri, 9 Jun 2017 01:18:35 +1000 Subject: [PATCH 12/76] Revert previous change; add cpu and ram as extra keys --- salt/cloud/clouds/vmware.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index b394da17ba..4597f2b266 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -988,10 +988,9 @@ def _format_instance_info_select(vm, selection): if 'size' in selection: cpu = vm["config.hardware.numCPU"] if "config.hardware.numCPU" in vm else "N/A" ram = "{0} MB".format(vm["config.hardware.memoryMB"]) if "config.hardware.memoryMB" in vm else "N/A" - vm_select_info['size'] = { - 'cpu': cpu, - 'ram': ram - } + vm_select_info['size'] = u"cpu: {0}\nram: {1}".format(cpu, ram) + vm_select_info['cpu'] = cpu + vm_select_info['ram'] = ram if 'state' in selection: vm_select_info['state'] = str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A" @@ -1178,10 +1177,9 @@ def _format_instance_info(vm): vm_full_info = { 'id': str(vm['name']), 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", - 'size': { - 'cpu': cpu, - 'ram': ram - }, + 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), + 'cpu': cpu, + 'ram': ram, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': ip_addresses, 'public_ips': [], @@ -1585,10 +1583,9 @@ def list_nodes(kwargs=None, call=None): vm_info = { 'id': vm["name"], 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", - 'size': { - 'cpu': cpu, - 'ram': ram - }, + 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), + 'cpu': cpu, + 'ram': ram, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [], 'public_ips': [] From dadf4b851c40a2ad960212a7b0c7a5a9436209d6 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Thu, 8 Jun 2017 13:18:53 -0600 Subject: [PATCH 13/76] Add documentation to the example master and minion configuration files. Move minion event signing to a saner place. Enable dropping messages when signature does not verify or when minion is not adding the signature to its payloads. --- conf/master | 14 ++++++++++++++ doc/topics/releases/2016.3.7.rst | 15 +++++++++++++++ salt/config/__init__.py | 16 ++++++++++++++++ salt/daemons/masterapi.py | 1 + salt/master.py | 29 +++++++++++++++++++++-------- salt/minion.py | 21 +++++++++++++++------ salt/utils/job.py | 1 + 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/conf/master b/conf/master index a675a8a2d5..4ed0dc62d3 100644 --- a/conf/master +++ b/conf/master @@ -366,6 +366,20 @@ # will cause minion to throw an exception and drop the message. # sign_pub_messages: False +# Signature verification on messages published from minions +# This requires that minions cryptographically sign the messages they +# publish to the master. If minions are not signing, then log this information +# at loglevel 'INFO' and drop the message without acting on it. +# require_minion_sign_messages: False + +# The below will drop messages when their signatures do not validate. +# Note that when this option is False but `require_minion_sign_messages` is True +# minions MUST sign their messages but the validity of their signatures +# is ignored. +# These two config options exist so a Salt infrastructure can be moved +# to signing minion messages gradually. +# drop_messages_signature_fail: False + ##### Salt-SSH Configuration ##### ########################################## diff --git a/doc/topics/releases/2016.3.7.rst b/doc/topics/releases/2016.3.7.rst index 2f10a21dfe..3c47df7eda 100644 --- a/doc/topics/releases/2016.3.7.rst +++ b/doc/topics/releases/2016.3.7.rst @@ -9,3 +9,18 @@ controls whether a minion can request that the master revoke its key. When True can request a key revocation and the master will comply. If it is False, the key will not be revoked by the msater. +New master configuration option `require_minion_sign_messages` +This requires that minions cryptographically sign the messages they +publish to the master. If minions are not signing, then log this information +at loglevel 'INFO' and drop the message without acting on it. + +New master configuration option `drop_messages_signature_fail` +Drop messages from minions when their signatures do not validate. +Note that when this option is False but `require_minion_sign_messages` is True +minions MUST sign their messages but the validity of their signatures +is ignored. + +New minion configuration option `minion_sign_messages` +Causes the minion to cryptographically sign the payload of messages it places +on the event bus for the master. The payloads are signed with the minion's +private key so the master can verify the signature with its public key. diff --git a/salt/config/__init__.py b/salt/config/__init__.py index 4ac6278204..fd30172f5d 100644 --- a/salt/config/__init__.py +++ b/salt/config/__init__.py @@ -874,6 +874,19 @@ VALID_OPTS = { # File chunk size for salt-cp 'salt_cp_chunk_size': int, + + # Require that the minion sign messages it posts to the master on the event + # bus + 'minion_sign_messages': bool, + + # Have master drop messages from minions for which their signatures do + # not verify + 'drop_messages_signature_fail': bool, + + # Require that payloads from minions have a 'sig' entry + # (in other words, require that minions have 'minion_sign_messages' + # turned on) + 'require_minion_sign_messages': bool, } # default configurations @@ -1105,6 +1118,7 @@ DEFAULT_MINION_OPTS = { 'ssl': None, 'cache': 'localfs', 'salt_cp_chunk_size': 65536, + 'minion_sign_messages': False, } DEFAULT_MASTER_OPTS = { @@ -1364,6 +1378,8 @@ DEFAULT_MASTER_OPTS = { 'thin_extra_mods': '', 'allow_minion_key_revoke': True, 'salt_cp_chunk_size': 98304, + 'require_minion_sign_messages': False, + 'drop_messages_signature_fail': False, } diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index 11ac705adc..4ffcebf648 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -780,6 +780,7 @@ class RemoteFuncs(object): # If the return data is invalid, just ignore it if any(key not in load for key in ('return', 'jid', 'id')): return False + if load['jid'] == 'req': # The minion is returning a standalone job, request a jobid prep_fstr = '{0}.prep_jid'.format(self.opts['master_job_cache']) diff --git a/salt/master.py b/salt/master.py index fc8023ef48..d40f638ec3 100644 --- a/salt/master.py +++ b/salt/master.py @@ -1085,14 +1085,6 @@ class AESFuncs(object): ) return False - if 'sig' in load: - log.trace('Verifying signed event publish from minion') - sig = load.pop('sig') - this_minion_pubkey = os.path.join(self.opts['pki_dir'], 'minions/{0}'.format(load['id'])) - serialized_load = salt.serializers.msgpack.serialize(load) - if not salt.crypt.verify_signature(this_minion_pubkey, serialized_load, sig): - log.info('Signature for signed event from minion published on bus did not verify') - if 'tok' in load: load.pop('tok') @@ -1385,6 +1377,24 @@ class AESFuncs(object): :param dict load: The minion payload ''' + if self.opts['require_minion_sign_messages'] and 'sig' not in load: + log.critical('_return: Master is requiring minions to sign their messages, but there is no signature in this payload from {0}.'.format(load['id'])) + return False + + if 'sig' in load: + log.trace('Verifying signed event publish from minion') + sig = load.pop('sig') + this_minion_pubkey = os.path.join(self.opts['pki_dir'], 'minions/{0}'.format(load['id'])) + serialized_load = salt.serializers.msgpack.serialize(load) + if not salt.crypt.verify_signature(this_minion_pubkey, serialized_load, sig): + log.info('Failed to verify event signature from minion {0}.'.format(load['id'])) + if self.opts['drop_messages_signature_fail']: + log.critical('Drop_messages_signature_fail is enabled, dropping message from {0}'.format(load['id'])) + return False + else: + log.info('But \'drop_message_signature_fail\' is disabled, so message is still accepted.') + load['sig'] = sig + try: salt.utils.job.store_job( self.opts, load, event=self.event, mminion=self.mminion) @@ -1428,6 +1438,9 @@ class AESFuncs(object): ret['fun_args'] = load['arg'] if 'out' in load: ret['out'] = load['out'] + if 'sig' in load: + ret['sig'] = load['sig'] + self._return(ret) def minion_runner(self, clear_load): diff --git a/salt/minion.py b/salt/minion.py index 6253d63200..6d362669f2 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1158,11 +1158,25 @@ class Minion(MinionBase): return functions, returners, errors, executors def _send_req_sync(self, load, timeout): + + if self.opts['minion_sign_messages']: + log.trace('Signing event to be published onto the bus.') + minion_privkey_path = os.path.join(self.opts['pki_dir'], 'minion.pem') + sig = salt.crypt.sign_message(minion_privkey_path, salt.serializers.msgpack.serialize(load)) + load['sig'] = sig + channel = salt.transport.Channel.factory(self.opts) return channel.send(load, timeout=timeout) @tornado.gen.coroutine def _send_req_async(self, load, timeout): + + if self.opts['minion_sign_messages']: + log.trace('Signing event to be published onto the bus.') + minion_privkey_path = os.path.join(self.opts['pki_dir'], 'minion.pem') + sig = salt.crypt.sign_message(minion_privkey_path, salt.serializers.msgpack.serialize(load)) + load['sig'] = sig + channel = salt.transport.client.AsyncReqChannel.factory(self.opts) ret = yield channel.send(load, timeout=timeout) raise tornado.gen.Return(ret) @@ -1186,12 +1200,6 @@ class Minion(MinionBase): else: return - if self.opts['sign_minion_messages']: - log.trace('Signing event being published onto the bus.') - minion_privkey_path = os.path.join(self.opts['pki_dir'], 'minion.pem') - sig = salt.crypt.sign_message(minion_privkey_path, salt.serializers.msgpack.serialize(load)) - load['sig'] = sig - def timeout_handler(*_): log.info('fire_master failed: master could not be contacted. Request timed out.') return True @@ -1636,6 +1644,7 @@ class Minion(MinionBase): log.warning(msg) return True + if sync: try: ret_val = self._send_req_sync(load, timeout=timeout) diff --git a/salt/utils/job.py b/salt/utils/job.py index 31e99a69d8..de53f1e8ec 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -3,6 +3,7 @@ # Import Python libs from __future__ import absolute_import import logging +import os # Import Salt libs import salt.minion From 687872a48884acf971752c74bd999eeac29dbf22 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Thu, 8 Jun 2017 13:54:15 -0600 Subject: [PATCH 14/76] Lint --- salt/minion.py | 1 - salt/utils/job.py | 1 - 2 files changed, 2 deletions(-) diff --git a/salt/minion.py b/salt/minion.py index 6d362669f2..ba148af3a7 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1644,7 +1644,6 @@ class Minion(MinionBase): log.warning(msg) return True - if sync: try: ret_val = self._send_req_sync(load, timeout=timeout) diff --git a/salt/utils/job.py b/salt/utils/job.py index de53f1e8ec..31e99a69d8 100644 --- a/salt/utils/job.py +++ b/salt/utils/job.py @@ -3,7 +3,6 @@ # Import Python libs from __future__ import absolute_import import logging -import os # Import Salt libs import salt.minion From 88716a29d2cd31f723df2eff7f8cf54d62fe076a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Fri, 9 Jun 2017 19:09:20 +0200 Subject: [PATCH 15/76] Fix pylint errors and warnings --- salt/modules/debian_service.py | 3 ++- salt/modules/freebsdservice.py | 4 +++- salt/modules/gentoo_service.py | 6 +++--- salt/modules/launchctl.py | 3 ++- salt/modules/netbsdservice.py | 4 +++- salt/modules/openbsdservice.py | 4 +++- salt/modules/rest_service.py | 4 +++- salt/modules/rh_service.py | 4 ++-- salt/modules/service.py | 4 +++- salt/modules/smf.py | 6 ++++-- salt/modules/ssh_service.py | 4 +++- salt/modules/systemd.py | 3 ++- salt/modules/upstart.py | 5 +++-- salt/modules/win_service.py | 5 +++-- 14 files changed, 39 insertions(+), 20 deletions(-) diff --git a/salt/modules/debian_service.py b/salt/modules/debian_service.py index 1bfdb89905..821e71486e 100644 --- a/salt/modules/debian_service.py +++ b/salt/modules/debian_service.py @@ -13,6 +13,7 @@ from __future__ import absolute_import # Import python libs import logging import glob +import fnmatch import re # Import 3rd-party libs @@ -248,7 +249,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/freebsdservice.py b/salt/modules/freebsdservice.py index 31a710b575..6d2dd8e627 100644 --- a/salt/modules/freebsdservice.py +++ b/salt/modules/freebsdservice.py @@ -13,6 +13,8 @@ from __future__ import absolute_import # Import python libs import logging import os +import fnmatch +import re # Import salt libs import salt.utils @@ -499,7 +501,7 @@ def status(name, sig=None, jail=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/gentoo_service.py b/salt/modules/gentoo_service.py index aaa2ba836c..e75c6c816f 100644 --- a/salt/modules/gentoo_service.py +++ b/salt/modules/gentoo_service.py @@ -13,6 +13,8 @@ to the correct service manager # Import Python libs from __future__ import absolute_import import logging +import fnmatch +import re # Import salt libs import salt.utils.systemd @@ -260,7 +262,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: @@ -274,8 +276,6 @@ def status(name, sig=None): return results[name] - - def enable(name, **kwargs): ''' Enable the named service to start at boot diff --git a/salt/modules/launchctl.py b/salt/modules/launchctl.py index 76747725f1..401c1f0882 100644 --- a/salt/modules/launchctl.py +++ b/salt/modules/launchctl.py @@ -17,6 +17,7 @@ from distutils.version import LooseVersion # pylint: disable=no-name-in-module import logging import os import plistlib +import fnmatch import re # Import salt libs @@ -230,7 +231,7 @@ def status(name, runas=None): salt '*' service.status ''' - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/netbsdservice.py b/salt/modules/netbsdservice.py index c4dcaee82b..dc59f095f6 100644 --- a/salt/modules/netbsdservice.py +++ b/salt/modules/netbsdservice.py @@ -13,6 +13,8 @@ from __future__ import absolute_import # Import python libs import os import glob +import fnmatch +import re __func_alias__ = { 'reload_': 'reload' @@ -127,7 +129,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/openbsdservice.py b/salt/modules/openbsdservice.py index 97725e2518..4e09785de4 100644 --- a/salt/modules/openbsdservice.py +++ b/salt/modules/openbsdservice.py @@ -12,6 +12,8 @@ The service module for OpenBSD # Import python libs from __future__ import absolute_import import os +import re +import fnmatch import logging # Import 3rd-party libs @@ -117,7 +119,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/rest_service.py b/salt/modules/rest_service.py index 261db384d2..fd06a7ef51 100644 --- a/salt/modules/rest_service.py +++ b/salt/modules/rest_service.py @@ -7,6 +7,8 @@ from __future__ import absolute_import import salt.utils import logging +import fnmatch +import re log = logging.getLogger(__name__) @@ -140,7 +142,7 @@ def status(name, sig=None): ''' proxy_fn = 'rest_sample.service_status' - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index f2b0ff216c..576e0a5089 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -36,7 +36,7 @@ if salt.utils.which('initctl'): try: # Don't re-invent the wheel, import the helper functions from the # upstart module. - from salt.modules.upstart \ + from salt.modules.upstart import _upstart_enable, _upstart_disable, _upstart_is_enabled except Exception as exc: log.error('Unable to import helper functions from ' @@ -496,7 +496,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/service.py b/salt/modules/service.py index 42d483140f..d537ab6929 100644 --- a/salt/modules/service.py +++ b/salt/modules/service.py @@ -6,6 +6,8 @@ from __future__ import absolute_import # Import python libs import os +import fnmatch +import re __func_alias__ = { 'reload_': 'reload' @@ -158,7 +160,7 @@ def status(name, sig=None): if sig: return __salt__['status.pid'](sig) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/smf.py b/salt/modules/smf.py index dbc1ee3af0..d7342af237 100644 --- a/salt/modules/smf.py +++ b/salt/modules/smf.py @@ -12,6 +12,8 @@ that use SMF also. (e.g. SmartOS) # Import Python libs from __future__ import absolute_import +import fnmatch +import re __func_alias__ = { 'reload_': 'reload' @@ -247,7 +249,7 @@ def status(name, sig=None): salt '*' service.status ''' - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: @@ -256,7 +258,7 @@ def status(name, sig=None): for service in services: cmd = '/usr/bin/svcs -H -o STATE {0}'.format(service) line = __salt__['cmd.run'](cmd, python_shell=False) - results[service] = line == 'online': + results[service] = line == 'online' if contains_globbing: return results return results[name] diff --git a/salt/modules/ssh_service.py b/salt/modules/ssh_service.py index 27b5ba3012..04a1c92b96 100644 --- a/salt/modules/ssh_service.py +++ b/salt/modules/ssh_service.py @@ -7,6 +7,8 @@ Provide the service module for the proxy-minion SSH sample from __future__ import absolute_import import logging import salt.utils +import fnmatch +import re log = logging.getLogger(__name__) @@ -126,7 +128,7 @@ def status(name, sig=None): ''' proxy_fn = 'ssh_sample.service_status' - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index ec175497d9..b64cf945c8 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -17,6 +17,7 @@ import errno import glob import logging import os +import fnmatch import re import shlex @@ -897,7 +898,7 @@ def status(name, sig=None): # pylint: disable=unused-argument salt '*' service.status [service signature] ''' - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: diff --git a/salt/modules/upstart.py b/salt/modules/upstart.py index 4091331327..cca903b6e7 100644 --- a/salt/modules/upstart.py +++ b/salt/modules/upstart.py @@ -450,7 +450,7 @@ def status(name, sig=None): if sig: return bool(__salt__['status.pid'](sig)) - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(get_all(), name) else: @@ -462,12 +462,13 @@ def status(name, sig=None): # decide result base on cmd output, thus ignore retcode, # which makes cmd output not at error lvl even when cmd fail. results[service] = 'start/running' in __salt__['cmd.run'](cmd, python_shell=False, - ignore_retcode=True) + ignore_retcode=True) else: # decide result base on retcode, thus ignore output (set quite) # because there is no way to avoid logging at error lvl when # service is not running - retcode != 0 (which is totally relevant). results[service] = not bool(__salt__['cmd.retcode'](cmd, python_shell=False, + ignore_retcode=True) if contains_globbing: return results return results[name] diff --git a/salt/modules/win_service.py b/salt/modules/win_service.py index bca86ea931..0dc8243821 100644 --- a/salt/modules/win_service.py +++ b/salt/modules/win_service.py @@ -519,7 +519,7 @@ def execute_salt_restart_task(): return __salt__['task.run'](name='restart-salt-minion') -def status(name, sig = None): +def status(name, sig=None): ''' Return the status for a service. If the name contains globbing, a dict mapping service name to True/False @@ -545,7 +545,7 @@ def status(name, sig = None): results = {} all_services = get_all() - contains_globbing = bool(re.search('\*|\?|\[.+\]', name)) + contains_globbing = bool(re.search(r'\*|\?|\[.+\]', name)) if contains_globbing: services = fnmatch.filter(all_services, name) else: @@ -556,6 +556,7 @@ def status(name, sig = None): return results return results[name] + def getsid(name): ''' Return the SID for this windows service From 8ae9cf251ddcadf9071bbc8dc5b626011f83d142 Mon Sep 17 00:00:00 2001 From: plassa-b Date: Fri, 9 Jun 2017 22:01:57 +0200 Subject: [PATCH 16/76] Fix some more pylint errors --- salt/modules/rh_service.py | 3 +-- salt/modules/systemd.py | 1 - salt/modules/upstart.py | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index 576e0a5089..fe324e9170 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -36,8 +36,7 @@ if salt.utils.which('initctl'): try: # Don't re-invent the wheel, import the helper functions from the # upstart module. - from salt.modules.upstart - import _upstart_enable, _upstart_disable, _upstart_is_enabled + import salt.modules.upstart except Exception as exc: log.error('Unable to import helper functions from ' 'salt.modules.upstart: {0}'.format(exc)) diff --git a/salt/modules/systemd.py b/salt/modules/systemd.py index 32beb80658..e3e68cb6b4 100644 --- a/salt/modules/systemd.py +++ b/salt/modules/systemd.py @@ -1055,7 +1055,6 @@ def status(name, sig=None): # pylint: disable=unused-argument return results[name] - # **kwargs is required to maintain consistency with the API established by # Salt's service management states. def enable(name, no_block=False, unmask=False, unmask_runtime=False, **kwargs): # pylint: disable=unused-argument diff --git a/salt/modules/upstart.py b/salt/modules/upstart.py index cca903b6e7..aa9aae7c96 100644 --- a/salt/modules/upstart.py +++ b/salt/modules/upstart.py @@ -468,12 +468,12 @@ def status(name, sig=None): # because there is no way to avoid logging at error lvl when # service is not running - retcode != 0 (which is totally relevant). results[service] = not bool(__salt__['cmd.retcode'](cmd, python_shell=False, - ignore_retcode=True) + ignore_retcode=True, + quite=True)) if contains_globbing: return results return results[name] - quite=True)) def _get_service_exec(): From 7d9c07de2c40bb18bc7c421210515512fe583a05 Mon Sep 17 00:00:00 2001 From: plassa-b Date: Sat, 10 Jun 2017 00:04:36 +0200 Subject: [PATCH 17/76] Fix yet another pylint error --- salt/modules/rh_service.py | 2 +- salt/modules/upstart.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/modules/rh_service.py b/salt/modules/rh_service.py index fe324e9170..cd66952900 100644 --- a/salt/modules/rh_service.py +++ b/salt/modules/rh_service.py @@ -36,7 +36,7 @@ if salt.utils.which('initctl'): try: # Don't re-invent the wheel, import the helper functions from the # upstart module. - import salt.modules.upstart + from salt.modules.upstart import _upstart_enable, _upstart_disable, _upstart_is_enabled except Exception as exc: log.error('Unable to import helper functions from ' 'salt.modules.upstart: {0}'.format(exc)) diff --git a/salt/modules/upstart.py b/salt/modules/upstart.py index aa9aae7c96..19bb822a50 100644 --- a/salt/modules/upstart.py +++ b/salt/modules/upstart.py @@ -475,7 +475,6 @@ def status(name, sig=None): return results[name] - def _get_service_exec(): ''' Debian uses update-rc.d to manage System-V style services. From aacf9f0a44303abad6dad684472a43fa59bb64c7 Mon Sep 17 00:00:00 2001 From: "xiaofei.sun" Date: Sun, 11 Jun 2017 08:59:41 +0800 Subject: [PATCH 18/76] fix maximum recursion depth exceeded --- salt/utils/schedule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 2c1efef805..9e4ed857a8 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -280,6 +280,7 @@ from __future__ import absolute_import, with_statement import os import sys import time +import copy import signal import datetime import itertools @@ -715,7 +716,7 @@ class Schedule(object): kwargs = {} if 'kwargs' in data: kwargs = data['kwargs'] - ret['fun_args'].append(data['kwargs']) + ret['fun_args'].append(copy.deepcopy(data['kwargs'])) if func not in self.functions: ret['return'] = self.functions.missing_fun_string(func) From c0b1f57fc00e7153a6090363e6d29a78a7cf5fe6 Mon Sep 17 00:00:00 2001 From: "xiaofei.sun" Date: Sun, 11 Jun 2017 09:38:59 +0800 Subject: [PATCH 19/76] add exception --- salt/utils/schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 9e4ed857a8..ec4d37fd06 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -791,7 +791,7 @@ class Schedule(object): log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) os.unlink(proc_fn) - except OSError as exc: + except Exception as exc: if exc.errno == errno.EEXIST or exc.errno == errno.ENOENT: # EEXIST and ENOENT are OK because the file is gone and that's what # we wanted From bc855b4711e3e96dbcafac870f3d491f8b7ef3fc Mon Sep 17 00:00:00 2001 From: "xiaofei.sun" Date: Mon, 12 Jun 2017 17:34:49 +0800 Subject: [PATCH 20/76] fix swallow exception --- salt/utils/schedule.py | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index ec4d37fd06..68215adc9c 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -716,7 +716,7 @@ class Schedule(object): kwargs = {} if 'kwargs' in data: kwargs = data['kwargs'] - ret['fun_args'].append(copy.deepcopy(data['kwargs'])) + ret['fun_args'].append(copy.deepcopy(kwargs)) if func not in self.functions: ret['return'] = self.functions.missing_fun_string(func) @@ -773,25 +773,29 @@ class Schedule(object): ret['success'] = False ret['retcode'] = 254 finally: - try: - # Only attempt to return data to the master - # if the scheduled job is running on a minion. - if '__role' in self.opts and self.opts['__role'] == 'minion': - if 'return_job' in data and not data['return_job']: - pass - else: - # Send back to master so the job is included in the job list - mret = ret.copy() - mret['jid'] = 'req' - event = salt.utils.event.get_event('minion', opts=self.opts, listen=False) - load = {'cmd': '_return', 'id': self.opts['id']} - for key, value in six.iteritems(mret): - load[key] = value - event.fire_event(load, '__schedule_return') + # Only attempt to return data to the master + # if the scheduled job is running on a minion. + if '__role' in self.opts and self.opts['__role'] == 'minion': + if 'return_job' in data and not data['return_job']: + pass + else: + # Send back to master so the job is included in the job list + mret = ret.copy() + mret['jid'] = 'req' + event = salt.utils.event.get_event('minion', opts=self.opts, listen=False) + load = {'cmd': '_return', 'id': self.opts['id']} + for key, value in six.iteritems(mret): + load[key] = value - log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) + try: + event.fire_event(load, '__schedule_return') + except Exception as exc: + log.exception("Unhandled exception firing evnet: {0}".format(exc)) + + log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) + try: os.unlink(proc_fn) - except Exception as exc: + except OSError as exc: if exc.errno == errno.EEXIST or exc.errno == errno.ENOENT: # EEXIST and ENOENT are OK because the file is gone and that's what # we wanted From c54fde69a00dd1935d1e23e2dadf5f0bfd824995 Mon Sep 17 00:00:00 2001 From: "xiaofei.sun" Date: Mon, 12 Jun 2017 17:58:36 +0800 Subject: [PATCH 21/76] fix spell error --- salt/utils/schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/schedule.py b/salt/utils/schedule.py index 68215adc9c..32890e6405 100644 --- a/salt/utils/schedule.py +++ b/salt/utils/schedule.py @@ -790,7 +790,7 @@ class Schedule(object): try: event.fire_event(load, '__schedule_return') except Exception as exc: - log.exception("Unhandled exception firing evnet: {0}".format(exc)) + log.exception("Unhandled exception firing event: {0}".format(exc)) log.debug('schedule.handle_func: Removing {0}'.format(proc_fn)) try: From e8a24db9279f805584856c5642568232417096f5 Mon Sep 17 00:00:00 2001 From: twangboy Date: Mon, 12 Jun 2017 11:56:18 -0600 Subject: [PATCH 22/76] Remove win_unicode_console dependency --- pkg/windows/build_env_2.ps1 | 11 ----------- pkg/windows/req_2.txt | 1 - 2 files changed, 12 deletions(-) diff --git a/pkg/windows/build_env_2.ps1 b/pkg/windows/build_env_2.ps1 index 5267301648..98a922ca3d 100644 --- a/pkg/windows/build_env_2.ps1 +++ b/pkg/windows/build_env_2.ps1 @@ -261,17 +261,6 @@ DownloadFileWithProgress $url $file # Install Start_Process_and_test_exitcode "$($ini['Settings']['Scripts2Dir'])\pip.exe" "install --no-index --find-links=$($ini['Settings']['DownloadDir']) $file " "pip install PyCrypto" -#============================================================================== -# Download sitecustomize.py -#============================================================================== -Write-Output " ----------------------------------------------------------------" -Write-Output " - $script_name :: Download sitecustomize . . ." -Write-Output " ----------------------------------------------------------------" -$file = "sitecustomize.py" -$url = "$($ini['Settings']['SaltRepo'])/$file" -$file = "$($ini['Settings']['SitePkgs2Dir'])\$file" -DownloadFileWithProgress $url $file - #============================================================================== # Copy DLLs to Python Directory #============================================================================== diff --git a/pkg/windows/req_2.txt b/pkg/windows/req_2.txt index b244f070cb..83e35fc6a7 100644 --- a/pkg/windows/req_2.txt +++ b/pkg/windows/req_2.txt @@ -2,4 +2,3 @@ lxml==3.6.0 pypiwin32==219 -win-unicode-console==0.5 \ No newline at end of file From 628f709c3cc3cfbf805f5cceb76a96991cf3415d Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Mon, 12 Jun 2017 12:55:14 -0600 Subject: [PATCH 23/76] Correct test--caching requires files on disk but the test just supplies what would have been read from disk. --- tests/unit/crypt_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/crypt_test.py b/tests/unit/crypt_test.py index f548820397..b29bac3ffc 100644 --- a/tests/unit/crypt_test.py +++ b/tests/unit/crypt_test.py @@ -101,8 +101,9 @@ class CryptTestCase(TestCase): salt.utils.fopen.assert_has_calls([open_priv_wb, open_pub_wb], any_order=True) def test_sign_message(self): - with patch('salt.utils.fopen', mock_open(read_data=PRIVKEY_DATA)): - self.assertEqual(SIG, crypt.sign_message('/keydir/keyname.pem', MSG)) + key = Crypto.PublicKey.RSA.importKey(PRIVKEY_DATA) + with patch('salt.crypt._get_rsa_key', return_value=key): + self.assertEqual(SIG, salt.crypt.sign_message('/keydir/keyname.pem', MSG)) def test_verify_signature(self): with patch('salt.utils.fopen', mock_open(read_data=PUBKEY_DATA)): From d67c1dfbf7c3bcd5edf5afdd40f7c857d3f6758a Mon Sep 17 00:00:00 2001 From: twangboy Date: Tue, 13 Jun 2017 15:02:44 -0600 Subject: [PATCH 24/76] Remove references to salt master installation --- doc/topics/installation/windows.rst | 136 ++++++++++++---------------- 1 file changed, 57 insertions(+), 79 deletions(-) diff --git a/doc/topics/installation/windows.rst b/doc/topics/installation/windows.rst index 2e23246241..e4adc4ed66 100644 --- a/doc/topics/installation/windows.rst +++ b/doc/topics/installation/windows.rst @@ -36,21 +36,14 @@ The 64bit installer has been tested on Windows 7 64bit and Windows Server Please file a bug report on our GitHub repo if issues for other platforms are found. -There are two installers available. +There are installers available for Python 2 and Python 3. -============================================= ================================= -Filename Details -============================================= ================================= -``Salt-Minion---Setup.exe`` Just the salt Minion -``Salt---Setup.exe`` Salt Minion and Master -============================================= ================================= +The installer will detect previous installations of Salt and ask if you would +like to remove them. Clicking OK will remove the Salt binaries and related files +but leave any existing config, cache, and PKI information. -When run, both installers will detect previous installations of Salt and ask if -you would like to remove them. Clicking OK will remove the Salt binaries and -related files but leave any existing config, cache, and PKI information. - -Salt Minion Only Installation -============================= +Salt Minion Installation +======================== After the Welcome and the License Agreement, the installer asks for two bits of information to configure the minion; the master hostname and the minion name. @@ -83,18 +76,6 @@ be managed there or from the command line like any other Windows service. 2008 x64 SP1 redistributable. Allow all Windows updates to run salt-minion smoothly. -Salt Minion/Master Installation -=============================== - -This installer behaves the same as the Minion installer but adds an additional -installer page. You will be prompted to choose to install the minion and master. -The minion check box is checked by default. To also install the master, check -the master checkbox. To install only the master, uncheck the minion checkbox. At -least one item must be selected. - -You will also be prompted on the final page to start the ``salt-master`` -service. - Installation Prerequisites -------------------------- @@ -109,7 +90,7 @@ Silent Installer Options ======================== The installer can be run silently by providing the ``/S`` option at the command -line. Both installers also accept the following options for configuring the Salt +line. The installer also accepts the following options for configuring the Salt Minion silently: ========================= ===================================================== @@ -126,19 +107,6 @@ Option Description ``Automatic (Delayed Start)`` ========================= ===================================================== -The Master/Minion installer also supports the following options: - -========================= ===================================================== -Option Description -========================= ===================================================== -``/start-master=`` Either a 1 or 0. '1' will start the salt-master - service, '0' will not. Default is to start the - service after installation. -``/install-master`` Will install the master along with the minion. - Default is to install minion only -``/master-only`` Will only install the master. -========================= ===================================================== - .. note:: ``/start-service`` has been deprecated but will continue to function as expected for the time being. @@ -147,24 +115,17 @@ Here are some examples of using the silent installer: .. code-block:: bat - # install both minion and master - # configure the minion and start both services + # Install the Salt Minion + # Configure the minion and start the service - Salt-2016.9.1-Setup-amd64.exe /S /master=yoursaltmaster /minion-name=yourminionname /install-master + Salt-Minion-2017.5.1-Py2-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname .. code-block:: bat - # install only the master but don't start the salt-master service + # Install the Salt Minion + # Configure the minion but don't start the minion service - *-Setup-*.exe /S /master=yoursaltmaster /minion-name=yourminionname - -.. code-block:: bat - - # install the minion and master - # configure the minion to talk to the local master - # start both services - - *-Setup-*.exe /S /master=yoursaltmaster /minion-name=yourminionname /start-minion=0 + Salt-Minion-2017.5.1-Py3-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname /start-minion=0 Running the Salt Minion on Windows as an Unprivileged User @@ -268,21 +229,26 @@ code. They are located in the ``pkg\windows`` directory in the Salt repo Scripts: -------- -================= =========== -Script Description -================= =========== -``build_env.ps1`` A PowerShell script that sets up the build environment -``build_pkg.bat`` A batch file that builds a Windows installer based on the - contents of the ``C:\Python27`` directory -``build.bat`` A batch file that fully automates the building of the Windows - installer using the above two scripts -================= =========== +=================== =========== +Script Description +=================== =========== +``build_env_2.ps1`` A PowerShell script that sets up a Python 2 build + environment +``build_env_3.ps1`` A PowerShell script that sets up a Python 3 build + environment +``build_pkg.bat`` A batch file that builds a Windows installer based on the + contents of the ``C:\Python27`` directory +``build.bat`` A batch file that fully automates the building of the + Windows installer using the above two scripts +=================== =========== .. note:: - The ``build.bat`` and ``build_pkg.bat`` scripts both accept a single - parameter to specify the version of Salt that will be displayed in the - Windows installer. If no version is passed, the version will be determined - using git. + The ``build.bat`` and ``build_pkg.bat`` scripts both accept a parameter to + specify the version of Salt that will be displayed in the Windows installer. + If no version is passed, the version will be determined using git. + + Both scripts also accept an additional parameter to specify the version of + Python to use. The default is 2. Prerequisite Software --------------------- @@ -316,7 +282,7 @@ Go into the ``salt`` directory and checkout the version of salt to work with .. code-block:: bat cd salt - git checkout 2016.3 + git checkout 2017.5.2 2. Setup the Python Environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,14 +293,14 @@ PowerShell script. .. code-block:: bat cd pkg\windows - powershell -file build_env.ps1 + powershell -file build_env_2.ps1 .. note:: You can also do this from Explorer by navigating to the ``pkg\windows`` - directory, right clicking the **build_env.ps1** powershell script and + directory, right clicking the **build_env_2.ps1** powershell script and selecting **Run with PowerShell** -This will download and install Python with all the dependencies needed to +This will download and install Python 2 with all the dependencies needed to develop and build Salt. .. note:: @@ -367,6 +333,10 @@ with ``pip`` If ``pip`` is not recognized, you may need to restart your shell to get the updated path +.. note:: + if ``pip`` is still not recognized make sure that the Python Scripts folder + is in the System ``%PATH%``. (``C:\Python2\Scripts``) + 4. Setup Salt Configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -381,9 +351,9 @@ easiest way to set this up is to copy the contents of the md salt xcopy /s /e \Salt-Dev\salt\pkg\windows\buildenv\* \salt\ -Now go into the ``C:\salt\conf`` directory and edit the file name ``minion`` (no -extension). You need to configure the master and id parameters in this file. -Edit the following lines: +Now go into the ``C:\salt\conf`` directory and edit the minion config file named +``minion`` (no extension). You need to configure the master and id parameters in +this file. Edit the following lines: .. code-block:: bat @@ -414,16 +384,20 @@ Navigate to the root ``salt`` directory and install Salt. ------------------------------- Navigate to the ``pkg\windows`` directory and run the ``build_pkg.bat`` -with the build version (2016.3) script. +with the build version (2017.5.2) and the Python version as parameters. .. code-block:: bat cd pkg\windows - build_pkg.bat 2016.3 + build_pkg.bat 2017.5.2 2 + ^^^^^^^^ ^ + | | + # build version -- | + # python version ------ .. note:: If no version is passed, the ``build_pkg.bat`` will guess the version number - using git. + using git. If the python version is not passed, the default is 2. .. _create-windows-installer-easy: @@ -446,7 +420,7 @@ build. .. code-block:: bat cd salt - git checkout 2016.3 + git checkout 2017.5.2 Then navigate to ``pkg\windows`` and run the ``build.bat`` script with the version you're building. @@ -454,10 +428,14 @@ version you're building. .. code-block:: bat cd pkg\windows - build.bat 2016.3 + build.bat 2017.5.2 3 + ^^^^^^^^ ^ + | | + # build version | + # python version -- -This will install everything needed to build a Windows installer for Salt. The -binary will be in the ``salt\pkg\windows\installer`` directory. +This will install everything needed to build a Windows installer for Salt using +Python 3. The binary will be in the ``salt\pkg\windows\installer`` directory. .. _test-salt-minion: From 22601201c4b93ee4f1f1c21e41e0f95e483e2c1d Mon Sep 17 00:00:00 2001 From: twangboy Date: Tue, 13 Jun 2017 15:09:38 -0600 Subject: [PATCH 25/76] Add note about salt-master on Windows --- doc/topics/installation/windows.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/topics/installation/windows.rst b/doc/topics/installation/windows.rst index e4adc4ed66..cc251c6918 100644 --- a/doc/topics/installation/windows.rst +++ b/doc/topics/installation/windows.rst @@ -38,6 +38,11 @@ found. There are installers available for Python 2 and Python 3. +.. note:: + + An installer and documentation for Salt Master on Windows is available + through Salt Enterprise. + The installer will detect previous installations of Salt and ask if you would like to remove them. Clicking OK will remove the Salt binaries and related files but leave any existing config, cache, and PKI information. From 380f1daa51a41f738dc4d376b9c2c3cfa0656127 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Tue, 13 Jun 2017 15:59:15 -0600 Subject: [PATCH 26/76] open and write in byte mode using fileserver This switches to byte mode explicitely in the last few places I could find that are using the fileserver payload to store files. We should only ever be reading in the file, and then passing it to the minion, the unicode locale on the master should not matter. Then we want to make sure to write the information in bytes to the filesystem. --- salt/fileserver/hgfs.py | 4 ++-- salt/fileserver/svnfs.py | 2 +- salt/utils/gitfs.py | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index 3e068e3afb..5dec96909f 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -314,7 +314,7 @@ def init(): if new_remote: remote_map = os.path.join(__opts__['cachedir'], 'hgfs/remote_map.txt') try: - with salt.utils.fopen(remote_map, 'w+') as fp_: + with salt.utils.fopen(remote_map, 'wb+') as fp_: timestamp = datetime.now().strftime('%d %b %Y %H:%M:%S.%f') fp_.write('# hgfs_remote map as of {0}\n'.format(timestamp)) for repo in repos: @@ -538,7 +538,7 @@ def update(): os.makedirs(env_cachedir) new_envs = envs(ignore_cache=True) serial = salt.payload.Serial(__opts__) - with salt.utils.fopen(env_cache, 'w+') as fp_: + with salt.utils.fopen(env_cache, 'wb+') as fp_: fp_.write(serial.dumps(new_envs)) log.trace('Wrote env cache data to {0}'.format(env_cache)) diff --git a/salt/fileserver/svnfs.py b/salt/fileserver/svnfs.py index d77bfd5a59..6cdbab98fe 100644 --- a/salt/fileserver/svnfs.py +++ b/salt/fileserver/svnfs.py @@ -453,7 +453,7 @@ def update(): os.makedirs(env_cachedir) new_envs = envs(ignore_cache=True) serial = salt.payload.Serial(__opts__) - with salt.utils.fopen(env_cache, 'w+') as fp_: + with salt.utils.fopen(env_cache, 'wb+') as fp_: fp_.write(serial.dumps(new_envs)) log.trace('Wrote env cache data to {0}'.format(env_cache)) diff --git a/salt/utils/gitfs.py b/salt/utils/gitfs.py index 3094b94845..f9bc9b9b01 100644 --- a/salt/utils/gitfs.py +++ b/salt/utils/gitfs.py @@ -2177,8 +2177,7 @@ class GitBase(object): if refresh_env_cache: new_envs = self.envs(ignore_cache=True) serial = salt.payload.Serial(self.opts) - mode = 'wb+' if six.PY3 else 'w+' - with salt.utils.fopen(self.env_cache, mode) as fp_: + with salt.utils.fopen(self.env_cache, 'wb+') as fp_: fp_.write(serial.dumps(new_envs)) log.trace('Wrote env cache data to {0}'.format(self.env_cache)) From fa9023c9e09e836bd6c48e99f46f3f4ac93c44ab Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Wed, 14 Jun 2017 08:52:11 -0600 Subject: [PATCH 27/76] remove byte This does not need to be bytes because we are only storing the hashes, and not user files --- salt/fileserver/hgfs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/fileserver/hgfs.py b/salt/fileserver/hgfs.py index 5dec96909f..f3a372530f 100644 --- a/salt/fileserver/hgfs.py +++ b/salt/fileserver/hgfs.py @@ -314,7 +314,7 @@ def init(): if new_remote: remote_map = os.path.join(__opts__['cachedir'], 'hgfs/remote_map.txt') try: - with salt.utils.fopen(remote_map, 'wb+') as fp_: + with salt.utils.fopen(remote_map, 'w+') as fp_: timestamp = datetime.now().strftime('%d %b %Y %H:%M:%S.%f') fp_.write('# hgfs_remote map as of {0}\n'.format(timestamp)) for repo in repos: From 45975e299efe608bbab88a945a3a50430f85575e Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 14 Jun 2017 09:39:29 -0600 Subject: [PATCH 28/76] Remove reference to Salt Enterprise --- doc/topics/installation/windows.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/topics/installation/windows.rst b/doc/topics/installation/windows.rst index cc251c6918..e4adc4ed66 100644 --- a/doc/topics/installation/windows.rst +++ b/doc/topics/installation/windows.rst @@ -38,11 +38,6 @@ found. There are installers available for Python 2 and Python 3. -.. note:: - - An installer and documentation for Salt Master on Windows is available - through Salt Enterprise. - The installer will detect previous installations of Salt and ask if you would like to remove them. Clicking OK will remove the Salt binaries and related files but leave any existing config, cache, and PKI information. From e5f3d08751adb07d385c6e25b152dd5533142797 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 14 Jun 2017 11:01:24 -0500 Subject: [PATCH 29/76] Fix spurious error when glob/regex used in publisher_acl An error is logged if any of the publisher_acl targets is not present in the available usernames (as derived using pwd.getpwall()). However, at some point publisher_acl was expanded to support globs and regexes to specify user names. When this was done, the code which checks the publisher_acl entries against the available users was not updated. This results in spurious errors in the log when this code tries to look for a regex or glob expression in the list of available usernames. However, there is no real reason for this check, as all it does is run pwd.getpwnam() on the publisher_acl entry, and it does this only when the entry is not in the list of available users. So there is no way for this to do anything but raise a KeyError. The if block which checks the entry against the list of available users has therefore been removed. --- salt/daemons/masterapi.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index 62c63f5687..add78b10ea 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -253,27 +253,12 @@ def access_keys(opts): acl_users.add(opts['user']) acl_users.add(salt.utils.get_user()) if opts['client_acl_verify'] and HAS_PWD: - log.profile('Beginning pwd.getpwall() call in masterarpi acess_keys function') + log.profile('Beginning pwd.getpwall() call in masterarpi access_keys function') for user in pwd.getpwall(): users.append(user.pw_name) - log.profile('End pwd.getpwall() call in masterarpi acess_keys function') + log.profile('End pwd.getpwall() call in masterarpi access_keys function') for user in acl_users: - log.info( - 'Preparing the {0} key for local communication'.format( - user - ) - ) - - if opts['client_acl_verify'] and HAS_PWD: - if user not in users: - try: - log.profile('Beginning pwd.getpnam() call in masterarpi acess_keys function') - user = pwd.getpwnam(user).pw_name - log.profile('Beginning pwd.getpwnam() call in masterarpi acess_keys function') - except KeyError: - log.error('ACL user {0} is not available'.format(user)) - continue - + log.info('Preparing the %s key for local communication', user) keys[user] = mk_key(opts, user) # Check other users matching ACL patterns From 7484bcc6c66949db6170b054dd78df90e6b82afb Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 14 Jun 2017 11:53:17 -0500 Subject: [PATCH 30/76] parse_targets: include version in packed return data --- salt/modules/pkg_resource.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/salt/modules/pkg_resource.py b/salt/modules/pkg_resource.py index 1df9307d0b..9657853c38 100644 --- a/salt/modules/pkg_resource.py +++ b/salt/modules/pkg_resource.py @@ -115,11 +115,16 @@ def parse_targets(name=None, if __grains__['os'] == 'MacOS' and sources: log.warning('Parameter "sources" ignored on MacOS hosts.') + version = kwargs.get('version') + if pkgs and sources: log.error('Only one of "pkgs" and "sources" can be used.') return None, None elif pkgs: + if version is not None: + log.warning('\'version\' argument will be ignored for multiple ' + 'package targets') pkgs = _repack_pkgs(pkgs, normalize=normalize) if not pkgs: return None, None @@ -127,6 +132,9 @@ def parse_targets(name=None, return pkgs, 'repository' elif sources and __grains__['os'] != 'MacOS': + if version is not None: + log.warning('\'version\' argument will be ignored for multiple ' + 'package targets') sources = pack_sources(sources, normalize=normalize) if not sources: return None, None @@ -153,9 +161,9 @@ def parse_targets(name=None, if normalize: _normalize_name = \ __salt__.get('pkg.normalize_name', lambda pkgname: pkgname) - packed = dict([(_normalize_name(x), None) for x in name.split(',')]) + packed = dict([(_normalize_name(x), version) for x in name.split(',')]) else: - packed = dict([(x, None) for x in name.split(',')]) + packed = dict([(x, version) for x in name.split(',')]) return packed, 'repository' else: From 89bdc50f4e8e74d21a56f8d3e485da405fd27265 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 12:15:42 -0700 Subject: [PATCH 31/76] Adding the ability to configure some options when generating libvirt keys, particularly the number of days that the certificates will be valid for. --- salt/pillar/libvirt.py | 28 ++++++++++++++------- salt/states/virt.py | 56 +++++++++++++++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/salt/pillar/libvirt.py b/salt/pillar/libvirt.py index d826e7ec66..96ccc7d9b4 100644 --- a/salt/pillar/libvirt.py +++ b/salt/pillar/libvirt.py @@ -33,11 +33,18 @@ def ext_pillar(minion_id, 'libvirt', minion_id) cacert = os.path.join(__opts__['pki_dir'], - 'libvirt', - 'cacert.pem') + 'libvirt', + 'cacert.pem') if not os.path.isdir(key_dir): # No keys have been generated - gen_hyper_keys(minion_id) + gen_hyper_keys(minion_id, + pillar.get('ext_pillar_virt.country', 'US'), + pillar.get('ext_pillar_virt.st', 'Utah'), + pillar.get('ext_pillar_virt.locality', + 'Salt Lake City'), + pillar.get('ext_pillar_virt.organization', 'Salted'), + pillar.get('ext_pillar_virt.expiration_days', '365') + ) ret = {} for key in os.listdir(key_dir): if not key.endswith('.pem'): @@ -51,10 +58,11 @@ def ext_pillar(minion_id, def gen_hyper_keys(minion_id, - country='US', - state='Utah', - locality='Salt Lake City', - organization='Salted'): + country='US', + state='Utah', + locality='Salt Lake City', + organization='Salted', + expiration_days='365'): ''' Generate the keys to be used by libvirt hypervisors, this routine gens the keys and applies them to the pillar for the hypervisor minions @@ -91,8 +99,10 @@ def gen_hyper_keys(minion_id, with salt.utils.fopen(srvinfo, 'w+') as fp_: infodat = ('organization = salted\ncn = {0}\ntls_www_server' '\nencryption_key\nsigning_key' - '\ndigitalSignature').format( - __grains__['fqdn']) + '\ndigitalSignature\n' + 'expiration_days = {1}' + ).format( + __grains__['fqdn'], expiration_days) fp_.write(infodat) if not os.path.isfile(priv): subprocess.call( diff --git a/salt/states/virt.py b/salt/states/virt.py index f7cb41f916..e576f46453 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -27,6 +27,7 @@ except ImportError: import salt.utils from salt.exceptions import CommandExecutionError + __virtualname__ = 'virt' @@ -42,7 +43,7 @@ def __virtual__(): return False -def keys(name, basepath='/etc/pki'): +def keys(name, basepath='/etc/pki', **kwargs): ''' Manage libvirt keys. @@ -52,20 +53,53 @@ def keys(name, basepath='/etc/pki'): basepath Defaults to ``/etc/pki``, this is the root location used for libvirt keys on the hypervisor + + The following parameters are optional: + + country + The country that the certificate should use. Defaults to US. + + state + The state that the certificate should use. Defaults to Utah. + + locality + The locality that the certificate should use. + Defaults to Salt Lake City. + + organization + The organization that the certificate should use. + Defaults to Salted. + + expiration_days + The number of days that the certificate should be valid for. + Defaults to 365 days (1 year) + ''' - #libvirt.serverkey.pem - #libvirt.servercert.pem - #libvirt.clientkey.pem - #libvirt.clientcert.pem - #libvirt.cacert.pem + # libvirt.serverkey.pem + # libvirt.servercert.pem + # libvirt.clientkey.pem + # libvirt.clientcert.pem + # libvirt.cacert.pem ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''} - pillar = __salt__['pillar.ext']({'libvirt': '_'}) + + # Grab all kwargs to make them available as pillar values + # rename them to something hopefully unique to avoid + # overriding anything existing + pillar_kwargs = {} + for (key, value) in kwargs.iteritems(): + pillar_kwargs['ext_pillar_virt.{0}'.format(key)] = value + + pillar = __salt__['pillar.ext']({'libvirt': '_'}, pillar_kwargs) paths = { - 'serverkey': os.path.join(basepath, 'libvirt', 'private', 'serverkey.pem'), - 'servercert': os.path.join(basepath, 'libvirt', 'servercert.pem'), - 'clientkey': os.path.join(basepath, 'libvirt', 'private', 'clientkey.pem'), - 'clientcert': os.path.join(basepath, 'libvirt', 'clientcert.pem'), + 'serverkey': os.path.join(basepath, 'libvirt', + 'private', 'serverkey.pem'), + 'servercert': os.path.join(basepath, 'libvirt', + 'servercert.pem'), + 'clientkey': os.path.join(basepath, 'libvirt', + 'private', 'clientkey.pem'), + 'clientcert': os.path.join(basepath, 'libvirt', + 'clientcert.pem'), 'cacert': os.path.join(basepath, 'CA', 'cacert.pem') } From 02ae3c63b1a5659f06d555bc256e3652d06c3f48 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 13:12:01 -0700 Subject: [PATCH 32/76] Adding versionadded tags --- salt/states/virt.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/salt/states/virt.py b/salt/states/virt.py index e576f46453..562deed1a6 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -59,21 +59,31 @@ def keys(name, basepath='/etc/pki', **kwargs): country The country that the certificate should use. Defaults to US. + .. versionadded:: Oxygen + state The state that the certificate should use. Defaults to Utah. + .. versionadded:: Oxygen + locality The locality that the certificate should use. Defaults to Salt Lake City. + .. versionadded:: Oxygen + organization The organization that the certificate should use. Defaults to Salted. + .. versionadded:: Oxygen + expiration_days The number of days that the certificate should be valid for. Defaults to 365 days (1 year) + .. versionadded:: Oxygen + ''' # libvirt.serverkey.pem # libvirt.servercert.pem From 2ceb40b8a92768b5ea22d3d60694bc6f723d483b Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 15:50:53 -0700 Subject: [PATCH 33/76] Removing rogue parens. --- salt/states/virt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/states/virt.py b/salt/states/virt.py index 562deed1a6..ebb89c554b 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -97,7 +97,7 @@ def keys(name, basepath='/etc/pki', **kwargs): # rename them to something hopefully unique to avoid # overriding anything existing pillar_kwargs = {} - for (key, value) in kwargs.iteritems(): + for key, value in kwargs.iteritems(): pillar_kwargs['ext_pillar_virt.{0}'.format(key)] = value pillar = __salt__['pillar.ext']({'libvirt': '_'}, pillar_kwargs) From 0bcdb6b246626f0bfcbff29a0bc1f801c8953842 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 15:52:23 -0700 Subject: [PATCH 34/76] Moving expiration_days to previous line --- salt/pillar/libvirt.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/pillar/libvirt.py b/salt/pillar/libvirt.py index 96ccc7d9b4..182c4aae6a 100644 --- a/salt/pillar/libvirt.py +++ b/salt/pillar/libvirt.py @@ -99,8 +99,7 @@ def gen_hyper_keys(minion_id, with salt.utils.fopen(srvinfo, 'w+') as fp_: infodat = ('organization = salted\ncn = {0}\ntls_www_server' '\nencryption_key\nsigning_key' - '\ndigitalSignature\n' - 'expiration_days = {1}' + '\ndigitalSignature\nexpiration_days = {1}' ).format( __grains__['fqdn'], expiration_days) fp_.write(infodat) From 61b644de7d09920a12b40960c6b0d1560d125057 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 16:35:50 -0700 Subject: [PATCH 35/76] Fixing lint errors --- salt/states/virt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/states/virt.py b/salt/states/virt.py index ebb89c554b..b08efe149f 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -14,8 +14,9 @@ for the generation and signing of certificates for systems running libvirt: from __future__ import absolute_import # Import python libs -import os import fnmatch +import os +from salt.ext import six try: import libvirt # pylint: disable=import-error @@ -97,7 +98,7 @@ def keys(name, basepath='/etc/pki', **kwargs): # rename them to something hopefully unique to avoid # overriding anything existing pillar_kwargs = {} - for key, value in kwargs.iteritems(): + for key, value in six.iteritems(kwargs): pillar_kwargs['ext_pillar_virt.{0}'.format(key)] = value pillar = __salt__['pillar.ext']({'libvirt': '_'}, pillar_kwargs) From 95b9973a5d0d339f674fda6ee8540e70a9a3344b Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 16:36:40 -0700 Subject: [PATCH 36/76] removing rogue space --- salt/states/virt.py | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/states/virt.py b/salt/states/virt.py index b08efe149f..23d5ef7cb0 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -28,7 +28,6 @@ except ImportError: import salt.utils from salt.exceptions import CommandExecutionError - __virtualname__ = 'virt' From 78052ff00e91f0a37be3aa39963b517488b50ed0 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 13 Jun 2017 18:30:27 -0700 Subject: [PATCH 37/76] Updating the unit test for libvirt to include coverage for new options --- tests/unit/states/test_libvirt.py | 123 ++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tests/unit/states/test_libvirt.py b/tests/unit/states/test_libvirt.py index f6ab3f318a..9301ac5332 100644 --- a/tests/unit/states/test_libvirt.py +++ b/tests/unit/states/test_libvirt.py @@ -72,3 +72,126 @@ class LibvirtTestCase(TestCase, LoaderModuleMockMixin): ret.update({'comment': comt, 'result': True, 'changes': {'servercert': 'new'}}) self.assertDictEqual(virt.keys(name, basepath=self.pki_dir), ret) + + def test_keys_with_expiration_days(self): + ''' + Test to manage libvirt keys. + ''' + with patch('os.path.isfile', MagicMock(return_value=False)): + name = 'sunrise' + + ret = {'name': name, + 'result': True, + 'comment': '', + 'changes': {}} + + mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'], + {'libvirt.servercert.pem': 'A'}]) + with patch.dict(virt.__salt__, {'pillar.ext': mock}): + comt = ('All keys are correct') + ret.update({'comment': comt}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + expiration_days=700), ret) + + with patch.dict(virt.__opts__, {'test': True}): + comt = ('Libvirt keys are set to be updated') + ret.update({'comment': comt, 'result': None}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + expiration_days=700), ret) + + with patch.dict(virt.__opts__, {'test': False}): + with patch.object(salt.utils, 'fopen', MagicMock(mock_open())): + comt = ('Updated libvirt certs and keys') + ret.update({'comment': comt, 'result': True, + 'changes': {'servercert': 'new'}}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + expiration_days=700), ret) + + def test_keys_with_state(self): + ''' + Test to manage libvirt keys. + ''' + with patch('os.path.isfile', MagicMock(return_value=False)): + name = 'sunrise' + + ret = {'name': name, + 'result': True, + 'comment': '', + 'changes': {}} + + mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'], + {'libvirt.servercert.pem': 'A'}]) + with patch.dict(virt.__salt__, {'pillar.ext': mock}): + comt = ('All keys are correct') + ret.update({'comment': comt}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + st='California'), ret) + + with patch.dict(virt.__opts__, {'test': True}): + comt = ('Libvirt keys are set to be updated') + ret.update({'comment': comt, 'result': None}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + st='California'), ret) + + with patch.dict(virt.__opts__, {'test': False}): + with patch.object(salt.utils, 'fopen', MagicMock(mock_open())): + comt = ('Updated libvirt certs and keys') + ret.update({'comment': comt, 'result': True, + 'changes': {'servercert': 'new'}}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + st='California'), ret) + + def test_keys_with_all_options(self): + ''' + Test to manage libvirt keys. + ''' + with patch('os.path.isfile', MagicMock(return_value=False)): + name = 'sunrise' + + ret = {'name': name, + 'result': True, + 'comment': '', + 'changes': {}} + + mock = MagicMock(side_effect=[[], ['libvirt.servercert.pem'], + {'libvirt.servercert.pem': 'A'}]) + with patch.dict(virt.__salt__, {'pillar.ext': mock}): + comt = ('All keys are correct') + ret.update({'comment': comt}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + country='USA', + st='California', + locality='Los_Angeles', + organization='SaltStack', + expiration_days=700), ret) + + with patch.dict(virt.__opts__, {'test': True}): + comt = ('Libvirt keys are set to be updated') + ret.update({'comment': comt, 'result': None}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + country='USA', + st='California', + locality='Los_Angeles', + organization='SaltStack', + expiration_days=700), ret) + + with patch.dict(virt.__opts__, {'test': False}): + with patch.object(salt.utils, 'fopen', MagicMock(mock_open())): + comt = ('Updated libvirt certs and keys') + ret.update({'comment': comt, 'result': True, + 'changes': {'servercert': 'new'}}) + self.assertDictEqual(virt.keys(name, + basepath=self.pki_dir, + country='USA', + st='California', + locality='Los_Angeles', + organization='SaltStack', + expiration_days=700), ret) From efa3c8e65379e8922139ec6baf8140417d587418 Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Wed, 14 Jun 2017 10:38:16 -0700 Subject: [PATCH 38/76] removing unneeded comments --- salt/states/virt.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/salt/states/virt.py b/salt/states/virt.py index 23d5ef7cb0..89fa6f61aa 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -85,12 +85,6 @@ def keys(name, basepath='/etc/pki', **kwargs): .. versionadded:: Oxygen ''' - # libvirt.serverkey.pem - # libvirt.servercert.pem - # libvirt.clientkey.pem - # libvirt.clientcert.pem - # libvirt.cacert.pem - ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''} # Grab all kwargs to make them available as pillar values From 698806fb09cceba310f3cdd41de1e3c23697df8b Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Wed, 14 Jun 2017 13:57:04 -0500 Subject: [PATCH 39/76] No need to manually create pkg_params dict when name and version passed This was an incorrect fix, the fix should have been made in pkg_resource.parse_targets. Now that it is fixed there, this is not needed. --- salt/modules/ebuild.py | 4 +--- salt/modules/pacman.py | 9 --------- salt/modules/yumpkg.py | 9 --------- salt/modules/zypper.py | 8 -------- 4 files changed, 1 insertion(+), 29 deletions(-) diff --git a/salt/modules/ebuild.py b/salt/modules/ebuild.py index 0810090b65..621c0b1579 100644 --- a/salt/modules/ebuild.py +++ b/salt/modules/ebuild.py @@ -592,9 +592,7 @@ def install(name=None, # Handle version kwarg for a single package target if pkgs is None and sources is None: version_num = kwargs.get('version') - if version_num: - pkg_params = {name: version_num} - else: + if not version_num: version_num = '' if slot is not None: version_num += ':{0}'.format(slot) diff --git a/salt/modules/pacman.py b/salt/modules/pacman.py index 5c2dfaeeef..4e72975ce2 100644 --- a/salt/modules/pacman.py +++ b/salt/modules/pacman.py @@ -524,15 +524,6 @@ def install(name=None, if pkg_params is None or len(pkg_params) == 0: return {} - version_num = kwargs.get('version') - if version_num: - if pkgs is None and sources is None: - # Allow 'version' to work for single package target - pkg_params = {name: version_num} - else: - log.warning('\'version\' parameter will be ignored for multiple ' - 'package targets') - if 'root' in kwargs: pkg_params['-r'] = kwargs['root'] diff --git a/salt/modules/yumpkg.py b/salt/modules/yumpkg.py index ba01f496fd..08ff94c9da 100644 --- a/salt/modules/yumpkg.py +++ b/salt/modules/yumpkg.py @@ -1092,15 +1092,6 @@ def install(name=None, if pkg_params is None or len(pkg_params) == 0: return {} - version_num = kwargs.get('version') - if version_num: - if pkgs is None and sources is None: - # Allow "version" to work for single package target - pkg_params = {name: version_num} - else: - log.warning('"version" parameter will be ignored for multiple ' - 'package targets') - old = list_pkgs(versions_as_list=False) # Use of __context__ means no duplicate work here, just accessing # information already in __context__ from the previous call to list_pkgs() diff --git a/salt/modules/zypper.py b/salt/modules/zypper.py index 528f477c04..6b59fdfaf3 100644 --- a/salt/modules/zypper.py +++ b/salt/modules/zypper.py @@ -1004,14 +1004,6 @@ def install(name=None, if pkg_params is None or len(pkg_params) == 0: return {} - version_num = version - if version_num: - if pkgs is None and sources is None: - # Allow "version" to work for single package target - pkg_params = {name: version_num} - else: - log.warning("'version' parameter will be ignored for multiple package targets") - if pkg_type == 'repository': targets = [] problems = [] From eac6b151eb46ee9716fbc130828cd72f65f76d48 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Fri, 26 May 2017 12:23:22 +0200 Subject: [PATCH 40/76] Improved SVN output in test mode --- salt/states/svn.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/salt/states/svn.py b/salt/states/svn.py index 54329be760..e53ae18864 100644 --- a/salt/states/svn.py +++ b/salt/states/svn.py @@ -95,13 +95,29 @@ def latest(name, 'The path "{0}" exists and is not ' 'a directory.'.format(target) ) + if __opts__['test']: + if rev: + new_rev = str(rev) + else: + new_rev = 'HEAD' + if not os.path.exists(target): return _neutral_test( ret, - ('{0} doesn\'t exist and is set to be checked out.').format(target)) - svn_cmd = 'svn.diff' - opts += ('-r', 'HEAD') + ('{0} doesn\'t exist and is set to be checked out at revision ' + new_rev + '.').format(target)) + + try: + current_info = __salt__['svn.info'](cwd, target, user=user, username=username, password=password, fmt='dict') + svn_cmd = 'svn.diff' + except exceptions.CommandExecutionError: + return _fail( + ret, + ('{0} exists but is not a svn working copy.').format(target)) + + current_rev = current_info[0]['Revision'] + + opts += ('-r', current_rev + ':' + new_rev) if trust: opts += ('--trust-server-cert',) From fae41c287544f1a4f4c01baedac06131cb5c0123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Wains?= Date: Thu, 8 Jun 2017 22:10:52 +0200 Subject: [PATCH 41/76] Adjusting SVN unit test --- tests/unit/states/svn_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/states/svn_test.py b/tests/unit/states/svn_test.py index 87f5660cca..307ca7480b 100644 --- a/tests/unit/states/svn_test.py +++ b/tests/unit/states/svn_test.py @@ -55,7 +55,8 @@ class SvnTestCase(TestCase): mock = MagicMock(side_effect=[False, True]) with patch.object(os.path, 'exists', mock): mock = MagicMock(return_value=True) - with patch.dict(svn.__salt__, {'svn.diff': mock}): + info_mock = MagicMock(return_value=[{'Revision': 'mocked'}]) + with patch.dict(svn.__salt__, {'svn.diff': mock, 'svn.info': info_mock}): mock = MagicMock(return_value=["Dude"]) with patch.object(svn, '_neutral_test', mock): self.assertListEqual(svn.latest("salt", From fa368f21ace80bc519f2120ec2773f62a2b486dd Mon Sep 17 00:00:00 2001 From: Ch3LL Date: Wed, 14 Jun 2017 16:00:50 -0400 Subject: [PATCH 42/76] Add Change Log to 2016.11.6 Release Notes --- doc/topics/releases/2016.11.6.rst | 1335 +++++++++++++++++++++++++++++ 1 file changed, 1335 insertions(+) diff --git a/doc/topics/releases/2016.11.6.rst b/doc/topics/releases/2016.11.6.rst index f8e9bf8958..b1e80b3c7e 100644 --- a/doc/topics/releases/2016.11.6.rst +++ b/doc/topics/releases/2016.11.6.rst @@ -4,3 +4,1338 @@ Salt 2016.11.6 Release Notes Version 2016.11.6 is a bugfix release for :ref:`2016.11.0 `. +Changes for v2016.11.5..v2016.11.6 +---------------------------------------------------------------- + +Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs): + +*Generated at: 2017-06-14T19:58:30Z* + +Statistics: + +- Total Merges: **117** +- Total Issue references: **57** +- Total PR references: **141** + +Changes: + + +- **PR** `#41692`_: (*rallytime*) Add boto and boto3 version dependencies to boto_vpc state docs + @ *2017-06-14T19:05:07Z* + + - **ISSUE** `#40155`_: (*grichmond-salt*) State module boto_vpc not working with boto 2 + | refs: `#41692`_ + * edcafc6 Merge pull request `#41692`_ from rallytime/`fix-40155`_ + * 539c1b0 Add boto and boto3 version dependencies to boto_vpc state docs + +- **PR** `#40902`_: (*lorengordon*) Removes duplicates when merging pillar lists and adds pillar.get override for pillar_merge_lists + @ *2017-06-14T18:39:09Z* + + - **ISSUE** `#39918`_: (*kivoli*) Enabling list merging leads to multiplying of unique list items + | refs: `#40902`_ + * bdaeb55 Merge pull request `#40902`_ from lorengordon/pillar-get-merge-lists + * 6e35673 Preserves order when removing duplicates + + * 18eda70 Updates list merge tests to check for sorted, unique lists + + * 74bf91f Sorts the list when removing duplicates + + * 26a4b1b Adds pillar.get param to control list merge/overwrite behavior + + * ed04bae Removes duplicate values when merging lists + +- **PR** `#41723`_: (*rallytime*) Support apache-libcloud work-around for issue `#32743`_ for versions older than 2.0.0 + @ *2017-06-14T17:13:38Z* + + - **ISSUE** `#32743`_: (*tonybaloney*) Issue with salt-cloud on OpenSUSE + | refs: `#41723`_ `#41723`_ + - **PR** `#40837`_: (*tonybaloney*) Upgrade apache-libcloud package dependency for 2.0 + | refs: `#41723`_ `#41723`_ + * 203ec67 Merge pull request `#41723`_ from rallytime/libcloud-support + * 1e9a060 Bump version check down to 1.4.0 and use distutils.version lib + + * a30f654 Support apache-libcloud work-around for issue `#32743`_ for versions older than 2.0.0 + +- **PR** `#41655`_: (*Enquier*) Allow Nova cloud module to set a specific floating ip address + @ *2017-06-14T16:44:05Z* + + - **ISSUE** `#41654`_: (*Enquier*) Nova Cloud module doesn't work for python-novaclient 8.0.0+ + | refs: `#41655`_ + * 62dbf50 Merge pull request `#41655`_ from Enquier/nova-cloud-set_ip_address + * 293bc64 Removed empty debug log + + * 3d9871f Cleaning up, removing debugging tests + + * c78e5fe Fixing error message + + * 404dffb Debugging variable format + + * 6fa3b97 removing string call + + * 005995e modifying variable calls + + * 9e5e7a3 Testing variable changes + + * 05e240f Debugging Format of floating_ip variable + + * 366aca0 Adding Max version check for Nova since Cloud no longer operates at higher versions + + * 6f66c9d Fixing response of floating_ip_show to align with other floating ip's. Spelling fix + + * 58459ad Adding ability to set a Floating IP by a specific IP address + +- **PR** `#41731`_: (*terminalmage*) Clarify that archive_format is required pre-2016.11.0 + @ *2017-06-14T15:05:21Z* + + * 82eab84 Merge pull request `#41731`_ from terminalmage/docs + * d3f4ea1 Clarify that archive_format is required pre-2016.11.0 + +- **PR** `#41663`_: (*skizunov*) Don't invoke lspci if enable_lspci is False + @ *2017-06-13T21:19:42Z* + + * b6d27be Merge pull request `#41663`_ from skizunov/develop3 + * 154d6ce Don't invoke lspci if enable_lspci is False + +- **PR** `#41693`_: (*rallytime*) Document available kwargs for ec2.create_volume function + @ *2017-06-13T19:51:10Z* + + - **ISSUE** `#40446`_: (*sumeetisp*) [Documentation] include list of kwargs for ec2.create_volume in cloud driver + | refs: `#41693`_ + * 46b8d5d Merge pull request `#41693`_ from rallytime/`fix-40446`_ + * 569eb2b Document available kwargs for ec2.create_volume function + +- **PR** `#41696`_: (*terminalmage*) Handle a few edge/corner cases with non-string input to cmd.run + @ *2017-06-13T18:48:56Z* + + - **ISSUE** `#41691`_: (*jdonofrio728*) Can't pass integers as cmd.run environment variables + | refs: `#41696`_ + * aab55d3 Merge pull request `#41696`_ from terminalmage/issue41691 + * 0623e40 Apparently some funcs are passing tuples to cmd.run_* + + * cdbfb94 Handle a few edge/corner cases with non-string input to cmd.run + +- **PR** `#41697`_: (*terminalmage*) Resubmit `#41545`_ against 2016.11 branch + @ *2017-06-13T16:10:37Z* + + * 97897d7 Merge pull request `#41697`_ from terminalmage/pr-41545 + * faaacf8 Use error name instead of error number + + * 7eacda5 Make print_cli resilient on slow systems + +- **PR** `#41711`_: (*rallytime*) Update deprecated version info in manage.bootstrap func for root_user + @ *2017-06-13T16:04:32Z* + + - **ISSUE** `#40605`_: (*sumeetisp*) Salt-run manage.bootstrap + | refs: `#41711`_ + * 09260d7 Merge pull request `#41711`_ from rallytime/`fix-40605`_ + * 903c2ff Update deprecated version info in manage.bootstrap fucn for root_user + +- **PR** `#41658`_: (*garethgreenaway*) Fixes to the salt scheduler + @ *2017-06-13T16:00:57Z* + + - **ISSUE** `#39668`_: (*mirceaulinic*) Master scheduled job not recorded on the event bus + | refs: `#41658`_ + * d563b3e Merge pull request `#41658`_ from garethgreenaway/39668_schedule_runners_fire_events + * d688a1c Enable jobs scheduled on the master to fire their return data to the event bus + +- **PR** `#41706`_: (*twangboy*) Add missing batch files + @ *2017-06-13T15:32:53Z* + + * 3c3b934 Merge pull request `#41706`_ from twangboy/batch_files + * 0d4be02 Add batch files for master + +- **PR** `#41710`_: (*rallytime*) [2016.11] Merge forward from 2016.3 to 2016.11 + @ *2017-06-13T15:11:38Z* + + - **ISSUE** `#41688`_: (*yannj-fr*) Parted module command "mkfs" fails creating swap + | refs: `#41689`_ + - **ISSUE** `#37322`_: (*kiemlicz*) master_tops generating improper top file + | refs: `#41707`_ + - **PR** `#41707`_: (*terminalmage*) Update version in master-tops docs + - **PR** `#41689`_: (*yannj-fr*) Fix `#41688`_ : fix mkfs command linux-swap support + * 1afc4ad Merge pull request `#41710`_ from rallytime/merge-2016.11 + * 5150916 Merge branch '2016.3' into '2016.11' + + * 5058b0d Merge pull request `#41707`_ from terminalmage/master-tops-docs + + * 6ec9dfb Update version in master-tops docs + + * 1c1964d Merge pull request `#41689`_ from yannj-fr/`fix-41688`_ + + * a47eddc Fix `#41688`_ : fix mkfs command linux-swap support + +- **PR** `#41702`_: (*gtmanfred*) npm 5 and greater requires --force for cache clean + @ *2017-06-12T23:21:56Z* + + * 5d763b9 Merge pull request `#41702`_ from gtmanfred/2016.11 + * 8bd19fc fix version number + + * 0fa380f npm 5 and greater requires --force for cache clean + +- **PR** `#41704`_: (*rallytime*) Back-port `#41670`_ to 2016.11 + @ *2017-06-12T23:20:31Z* + + - **ISSUE** `#41668`_: (*yannj-fr*) Parted modules mkfs command does not work with NTFS + | refs: `#41670`_ + - **PR** `#41670`_: (*yannj-fr*) fixes `#41668`_ ntfs case problem in parted module + | refs: `#41704`_ + * f6519e7 Merge pull request `#41704`_ from rallytime/`bp-41670`_ + * 8afc879 fixes `#41668`_ ntfs case problem in parted module + +- **PR** `#41700`_: (*terminalmage*) roots: return actual link destination when listing symlinks + @ *2017-06-12T22:07:03Z* + + - **ISSUE** `#39939`_: (*martinschipper*) Relative symlinks are changed with file.recurse 2016.11.3 + | refs: `#41700`_ + * 0b89377 Merge pull request `#41700`_ from terminalmage/issue39939 + * bdbb265 roots: return actual link destination when listing symlinks + +- **PR** `#41699`_: (*rallytime*) Remove note about version incompatibility with salt-cloud + @ *2017-06-12T19:44:28Z* + + * 7cf47f9 Merge pull request `#41699`_ from rallytime/troubleshooting-doc-update + * c91ca5f Remove note about version incompatibility with salt-cloud + +- **PR** `#41694`_: (*rallytime*) Add ipcidr options to "Allowed Values" list in LocalClient expr_form docs + @ *2017-06-12T19:06:16Z* + + - **ISSUE** `#40410`_: (*DarrenDai*) Targeting Minions by IP Range via restful API doesn't work + | refs: `#41694`_ + * d68a631 Merge pull request `#41694`_ from rallytime/`fix-40410`_ + * 6de9da1 Add ipcidr options to "Allowed Values" list in LocalClient expr_form docs + +- **PR** `#41659`_: (*lubyou*) Use re.escape to escape paths before handing them to re.match + @ *2017-06-12T18:10:53Z* + + - **ISSUE** `#41365`_: (*lubyou*) file.managed chokes on windows paths when source_hash is set to the URI of a file that contains source hash strings + | refs: `#41659`_ + * 80d4a3a Merge pull request `#41659`_ from lubyou/41365-fix-file-managed + * d49a157 Use re.escape to escape paths, before handing them to re.match + + * ac240fa use correct variable + + * c777eba Use re.escape to escape paths, before handing them to re.match + +- **PR** `#41661`_: (*whiteinge*) Add note about avoiding the `-i` flag for the /keys endpoint + @ *2017-06-09T15:03:40Z* + + * 564d5fd Merge pull request `#41661`_ from whiteinge/rest_cherrypy-keys-headers + * a66ffc9 Add note about avoiding the `-i` flag for the /keys endpoint + +- **PR** `#41660`_: (*garethgreenaway*) Fix to modules/aptpkg.py for unheld + @ *2017-06-09T14:53:23Z* + + - **ISSUE** `#41651`_: (*Sakorah*) pkg.installed fails when unholding and test=true + | refs: `#41660`_ + * 38424f3 Merge pull request `#41660`_ from garethgreenaway/41651_fixing_aptpkg_held_unheld_with_test + * 30da237 Fix when test=True and packages were being set to unheld. + +- **PR** `#41656`_: (*rallytime*) Back-port `#41575`_ to 2016.11 + @ *2017-06-08T22:43:23Z* + + - **PR** `#41575`_: (*dschaller*) Fix 41562 + | refs: `#41656`_ + * a308b96 Merge pull request `#41656`_ from rallytime/`bp-41575`_ + * 4374e6b Replace "tbd" with release version information + + * 8141389 Lint: Add index numbers to format {} calls + + * 3845703 only list top level npm modules during {un)install + +- **PR** `#41456`_: (*bdrung*) Fix pkgrepo.managed always return changes for test=true + @ *2017-06-08T18:21:05Z* + + * e6d37b5 Merge pull request `#41456`_ from bdrung/fix-pkgrepo.managed-changes-check + * d3ce7bf Fix pkgrepo.managed always return changes for test=true + + * 1592687 Document aptpkg architectures parameter + +- **PR** `#41530`_: (*gtmanfred*) Set default for consul_pillar to None + @ *2017-06-08T18:13:15Z* + + - **ISSUE** `#41478`_: (*jf*) security / information leak with consul pillar when subsitution values are not present + | refs: `#41530`_ + * 721e5b6 Merge pull request `#41530`_ from gtmanfred/2016.11 + * 2a4633c Set default for consul_pillar to None + +- **PR** `#41638`_: (*gtmanfred*) don't overwrite args if they are passed to the script + @ *2017-06-08T17:48:48Z* + + - **ISSUE** `#41629`_: (*lubyou*) salt.states.cmd.script: Parameter "args" is overwritten if "name/id" contains spaces + | refs: `#41638`_ + * 8926d1c Merge pull request `#41638`_ from gtmanfred/cmdscript + * 6c7d68b don't overwrite args if they are passed to the script + +- **PR** `#41639`_: (*dmurphy18*) Update notrim check, netstat takes minutes if large number connections + @ *2017-06-07T23:03:24Z* + + * ecb09b8 Merge pull request `#41639`_ from dmurphy18/minion_netstat_check + * 7ab3319 Update notrim check, netstat takes minutes if large number connections - 260K + +- **PR** `#41611`_: (*garethgreenaway*) Additional fixes to states/saltmod.py + @ *2017-06-07T22:58:24Z* + + - **ISSUE** `#38894`_: (*amendlik*) salt.runner and salt.wheel ignore test=True + | refs: `#41309`_ `#41611`_ + * 2913a33 Merge pull request `#41611`_ from garethgreenaway/41309_right_return_res + * fda41ed Updating result values to be None for test cases. + + * 003f2d9 Following the documentation, when passed the test=True argument the runner and wheel functions should return a result value of False. + +- **PR** `#41637`_: (*gtmanfred*) never run bg for onlyif or unless cmd states + @ *2017-06-07T17:37:47Z* + + - **ISSUE** `#41626`_: (*ruiaylin*) When onlyif and bg are used together the + | refs: `#41637`_ + * 334a5fc Merge pull request `#41637`_ from gtmanfred/cmd + * 40fb6c6 never run bg for onlyif or unless cmd states + +- **PR** `#41255`_: (*lordcirth*) linux_syctl.default_config(): only return path, don't create it + @ *2017-06-07T14:13:07Z* + + * 34dd9ea Merge pull request `#41255`_ from lordcirth/fix-sysctl-test-11 + * 0089be4 linux_sysctl: use dirname() as suggested + + * 262d95e linux_syctl.default_config(): only return path, don't create it + + * 277232b linux_sysctl.persist(): create config dir if needed + +- **PR** `#41616`_: (*rallytime*) Back-port `#41551`_ to 2016.11 + @ *2017-06-06T22:44:09Z* + + - **ISSUE** `#35481`_: (*giany*) global_identifier does not work when using Softlayer driver + | refs: `#41551`_ `#41551`_ + - **PR** `#41551`_: (*darenjacobs*) Update __init__.py + | refs: `#41616`_ + * 4cf5777 Merge pull request `#41616`_ from rallytime/`bp-41551`_ + * 53bca96 Update __init__.py + +- **PR** `#41552`_: (*Enquier*) Adding logic so that update_floatingip can dissassociate floatingip's + @ *2017-06-06T18:25:56Z* + + * 846ca54 Merge pull request `#41552`_ from Enquier/neutron-floatingip-remove + * aeed51c Adding port=None default and documentation + + * fcce05e Adding logic so that update_floatingip can dissassociate floatingip's Previously update_floatingip would cause an error if port is set to None. + +- **PR** `#41569`_: (*gtmanfred*) Check all entries in result + @ *2017-06-06T18:18:17Z* + + * b720ecb Merge pull request `#41569`_ from gtmanfred/fix_test_result_check + * 19ea548 remove test that never passed + + * e2a4d5e Check all entries in result + +- **PR** `#41599`_: (*garethgreenaway*) Fixes to modules/archive.py + @ *2017-06-06T18:02:14Z* + + - **ISSUE** `#41540`_: (*UtahDave*) archive.extracted fails on second run + | refs: `#41599`_ `#41599`_ + * d9546c6 Merge pull request `#41599`_ from garethgreenaway/41540_fixes_to_archive_module + * 66a136e Fixing issues raised in `#41540`_ when a zip file is created on a Windows system. The issue has two parts, first directories that end up in the archive end up in the results of aarchive.list twice as they show up as both files and directories because of the logic to handle the fact that Windows doesn't mark them as directories. This issue shows up when an extraction is run a second time since the module verified the file types and the subdirectory is not a file. The second issue is related to permissions, if Salt is told to extract permissions (which is the default) then the directory and files end up being unreadable since the permissions are not available. This change sets the permissions to what the default umask for the user running Salt is. + +- **PR** `#41453`_: (*peter-funktionIT*) Update win_pki.py + @ *2017-06-06T17:15:55Z* + + - **ISSUE** `#40950`_: (*idokaplan*) Import certificate + | refs: `#41383`_ `#41453`_ + - **PR** `#41383`_: (*peter-funktionIT*) Update win_pki.py + | refs: `#41453`_ + * 10ac80e Merge pull request `#41453`_ from peter-funktionIT/fix_win_pki_state_import_cert + * d146fd0 Update win_pki.py + + * ef8e3ef Update win_pki.py + +- **PR** `#41557`_: (*dmurphy18*) Add symbolic link for salt-proxy service similar to other serivce files + @ *2017-06-06T17:13:52Z* + + * 3335fcb Merge pull request `#41557`_ from dmurphy18/fix-proxy-service + * ffe492d Add symbolic link salt-proxy service similar to other service files + +- **PR** `#41597`_: (*rallytime*) Back-port `#41533`_ to 2016.11 + @ *2017-06-06T15:15:09Z* + + - **PR** `#41533`_: (*svinota*) unit tests: add pyroute2 interface dict test + | refs: `#41597`_ + * 65ed230 Merge pull request `#41597`_ from rallytime/`bp-41533`_ + * 535b8e8 Update new pyroute2 unit test to conform with 2016.11 branch standards + + * 5c86dee unit tests: test_pyroute2 -- add skipIf + + * 026b394 unit tests: add encoding clause into test_pyroute2 + + * 9ab203d unit tests: fix absolute imports in test_pyroute2 + + * 1f507cf unit tests: add pyroute2 interface dict test + +- **PR** `#41596`_: (*rallytime*) Back-port `#41487`_ to 2016.11 + @ *2017-06-06T02:44:17Z* + + - **PR** `#41487`_: (*svinota*) clean up `change` attribute from interface dict + | refs: `#41596`_ + * bf8aed1 Merge pull request `#41596`_ from rallytime/`bp-41487`_ + * 7b497d9 clean up `change` attribute from interface dict + +- **PR** `#41509`_: (*seanjnkns*) Add keystone V3 API support for keystone.endpoint_present|absent + @ *2017-06-03T03:01:05Z* + + - **ISSUE** `#41435`_: (*seanjnkns*) 2016.11: Keystone.endpoint_present overwrites all interfaces + | refs: `#41509`_ + * cc6c98a Merge pull request `#41509`_ from seanjnkns/fix-keystone-v3-endpoint_present + * 095e594 Fix unit tests for PR `#41509`_ + + * eb7ef3c Add keystone V3 API support for keystone.endpoint_present|get, endpoint_absent|delete. + +- **PR** `#41539`_: (*gtmanfred*) allow digest to be empty in create_crl + @ *2017-06-02T17:00:04Z* + + - **ISSUE** `#38061`_: (*Ch3LL*) x509.crl_managed ValueError when digest is not specified in the module + | refs: `#41539`_ + * 0a08649 Merge pull request `#41539`_ from gtmanfred/x509 + * 0989be8 allow digest to be empty in create_crl + +- **PR** `#41561`_: (*terminalmage*) Redact HTTP basic authentication in archive.extracted + @ *2017-06-02T15:33:14Z* + + - **ISSUE** `#41154`_: (*mephi42*) archive.extracted outputs password embedded in archive URL + | refs: `#41561`_ + * 3ae8336 Merge pull request `#41561`_ from terminalmage/issue41154 + * cbf8acb Redact HTTP basic authentication in archive.extracted + +- **PR** `#41436`_: (*skizunov*) TCP transport: Fix occasional errors when using salt command + @ *2017-06-01T16:37:43Z* + + * 39840bf Merge pull request `#41436`_ from skizunov/develop2 + * 07d5862 unit.transport.tcp_test: Clean up channel after use + + * 4b6aec7 Preserve original IO Loop on cleanup + + * 892c6d4 TCP transport: Fix occasional errors when using salt command + +- **PR** `#41337`_: (*Foxlik*) Fix `#41335`_ - list index out of range on empty line in authorized_keys + @ *2017-05-31T19:59:17Z* + + - **ISSUE** `#41335`_: (*syphernl*) [2016.11.5] ssh_auth.present: IndexError: list index out of range + | refs: `#41337`_ + * 06ed4f0 Merge pull request `#41337`_ from Foxlik/2016.11 + * 916fecb modify ssh_test.py, to check empty lines and comments in authorized_keys `#41335`_ + + * 011d6d6 Fix `#41335`_ - list index out of range on empty line in authorized_keys + +- **PR** `#41512`_: (*twangboy*) Use psutil where possible in win_status.py + @ *2017-05-31T19:56:00Z* + + * 1ace72d Merge pull request `#41512`_ from twangboy/fix_win_status + * 582d09b Get psutil import + + * fd88bb2 Remove unused imports (lint) + + * 41a39df Use psutil where possible + +- **PR** `#41490`_: (*t0fik*) Backport of SELinux module installation and removal + @ *2017-05-31T19:38:00Z* + + * 683cc5f Merge pull request `#41490`_ from jdsieci/2016.11_selinux + * e2fbada Backport of SELinux module installation and removal + +- **PR** `#41522`_: (*jettero*) Sadly, you can't have '.'s and '$'s in dict keys in a mongodb doc. + @ *2017-05-31T15:55:24Z* + + * 2e7e84b Merge pull request `#41522`_ from jettero/mongodb-keys-are-stupid + * 12648f5 dang, thought I already got that. Apparently only got the bottom one. This should do it. + + * 7c4a763 ugh, forgot about this lint too. This one looks especially terrible. + + * c973988 forgot about the linter pass … fixed + + * da0d9e4 Sadly, you can't have '.'s and '$'s in dict keys in a mongodb doc. + +- **PR** `#41506`_: (*gtmanfred*) check for integer types + @ *2017-05-31T00:48:21Z* + + - **ISSUE** `#41504`_: (*mtkennerly*) Can't set REG_DWORD registry value larger than 0x7FFFFFFF + | refs: `#41506`_ + * 30ad4fd Merge pull request `#41506`_ from gtmanfred/2016.11 + * 5fe2e9b check for integer types + +- **PR** `#41469`_: (*Ch3LL*) Fix keep_jobs keyerror in redis returner + @ *2017-05-30T18:37:42Z* + + * 06ef17d Merge pull request `#41469`_ from Ch3LL/fix_redis_error + * 8ee1251 Fix keep_jobs keyerror in redis returner + +- **PR** `#41473`_: (*twangboy*) Fix win_firewall execution and state modules + @ *2017-05-30T18:35:24Z* + + * 7a09b2b Merge pull request `#41473`_ from twangboy/fix_win_firewall + * e503b45 Fix lint error + + * d3f0f8b Fix win_firewall execution and state modules + +- **PR** `#41499`_: (*rallytime*) [2016.11] Merge forward from 2016.3 to 2016.11 + @ *2017-05-30T18:06:03Z* + + - **PR** `#41439`_: (*terminalmage*) base64 encode binary data sent using salt-cp + * f635cb1 Merge pull request `#41499`_ from rallytime/merge-2016.11 + * 20d893d Merge branch '2016.3' into '2016.11' + + * 964b1ee Merge pull request `#41439`_ from terminalmage/salt-cp-base64 + + * ebf6cc7 base64 encode binary data sent using salt-cp + +- **PR** `#41464`_: (*rallytime*) Back-port `#39850`_ to 2016.11 + @ *2017-05-26T21:22:44Z* + + - **ISSUE** `#35874`_: (*epcim*) keystone.endpoint_present deletes RegionOne endpoints + - **PR** `#39850`_: (*epcim*) Fix endpoint handling per region + | refs: `#41464`_ + * 83f1e48 Merge pull request `#41464`_ from rallytime/`bp-39850`_ + * 9b84b75 Pylint fixes + + * 6db8915 Endpoint handling per region, fixes `#35874`_ - extend tests for multiple regions - region arg by default set to None - print verbose changes to be exec. + +- **PR** `#41443`_: (*UtahDave*) use proper arg number + @ *2017-05-26T20:36:37Z* + + * 960c576 Merge pull request `#41443`_ from UtahDave/fix_args_masterpy + * dfbdc27 use proper arg number + +- **PR** `#41350`_: (*lorengordon*) Supports quoted values in /etc/sysconfig/network + @ *2017-05-26T16:22:03Z* + + - **ISSUE** `#41341`_: (*lorengordon*) TypeError traceback in network.system with retain_settings=True + | refs: `#41350`_ + * 88c28c1 Merge pull request `#41350`_ from lorengordon/issue-41341 + * f2f6da7 Supports quoted values in /etc/sysconfig/network + +- **PR** `#41398`_: (*rallytime*) [2016.11] Merge forward from 2016.3 to 2016.11 + @ *2017-05-26T15:17:49Z* + + - **ISSUE** `#41234`_: (*non7top*) rpm fails to detect already installed packages + | refs: `#41265`_ + - **ISSUE** `#16592`_: (*spo0nman*) salt-cp fails with large files, cp.get_file succeeds + | refs: `#41216`_ + - **ISSUE** `#22`_: (*thatch45*) Make as many modules as we can think of + - **PR** `#41316`_: (*Ch3LL*) [2016.3] Bump latest release version to 2016.11.5 + - **PR** `#41265`_: (*terminalmage*) yumpkg: fix latest_version() when showdupesfromrepos=1 set in /etc/yum.conf + - **PR** `#41216`_: (*terminalmage*) Make salt-cp work with larger files + * 824f2d3 Merge pull request `#41398`_ from rallytime/merge-2016.11 + * 2941e9c Merge pull request `#22`_ from terminalmage/merge-2016.11 + + * 087a958 base64 encode binary data sent using salt-cp + + * 503f925 Add missing import + + * d2d9a3d Merge branch '2016.3' into '2016.11' + + * d617c9f Merge pull request `#41265`_ from terminalmage/issue41234 + + * edf552f Update PKG_TARGETS for RHEL-based distros + + * 0ecc7b9 yumpkg: fix latest_version() when showdupesfromrepos=1 set in /etc/yum.conf + + * 26bd914 Merge pull request `#41316`_ from Ch3LL/update_latest_2016.3 + + * 520740d [2016.13] Bump latest release version to 2016.11.5 + + * 18898b7 Merge pull request `#41216`_ from terminalmage/issue16592 + + * 0e15fdb Update salt-cp integration test to reflect recent changes + + * 10dc695 Make salt-cp work with larger files + + * c078180 Make KeyErrors more specific when interpreting returns + + * fc401c9 Add generator functions for reading files + +- **PR** `#41442`_: (*UtahDave*) use proper arg number + @ *2017-05-26T13:42:50Z* + + * ec08064 Merge pull request `#41442`_ from UtahDave/fix_args + * 0324833 use proper arg number + +- **PR** `#41397`_: (*Enquier*) Updating Nova/Neutron modules to support KeystoneAuth and SSLVerify + @ *2017-05-25T21:16:14Z* + + - **ISSUE** `#37824`_: (*dxiri*) SSLError Trying to use v3 API of Openstack Newton as provider. + | refs: `#41397`_ `#40752`_ + - **ISSUE** `#36548`_: (*abonillasuse*) openstack auth with nova driver + | refs: `#38647`_ + - **PR** `#40752`_: (*Enquier*) Add ability to specify a custom SSL certificate or disable SSL verification in KeystoneAuth v3 + | refs: `#41397`_ + - **PR** `#38647`_: (*gtmanfred*) Allow novaclient to use keystoneauth1 sessions for authentication + | refs: `#41397`_ + * 22096d9 Merge pull request `#41397`_ from Enquier/neutron-ssl-verify + * d25dcf6 Small error in nova that was preventing execution + + * 0e7a100 Updated module docs to include changes made + + * 05e0192 Adding missing os_auth_system + + * 4e0f498 allow service_type to be specified default is now 'network' + + * 991e843 Added non-profile and defaults for Neutron + + * c93f112 Updating Nova Module to include use_keystone Auth + + * 66ab1e5 Re-adding neutron dependency check + + * cce07ee Updating Neutron module to suport KeystoneAuth + +- **PR** `#41409`_: (*garethgreenaway*) Fixes to ipc transport + @ *2017-05-25T21:06:27Z* + + - **ISSUE** `#34460`_: (*Ch3LL*) Receive an error when using salt-api to call a runner + | refs: `#41409`_ + * 14a58cf Merge pull request `#41409`_ from garethgreenaway/34460_fixes_ipc_transport + * 5613b72 Updating the exception variable to be more in line with the rest of the exception code + + * 41eee8b Fixing a potential lint issue + + * 760d561 Fixing a potential lint issue + + * c11bcd0 Changing the approaching and including an except for the action socket.error exception, then logging a trace log if error number is 0 and an error log otherwise. + + * 3f95059 Fixing lint issues. + + * f3a6531 On occasion an exception will occur which results in the event not returning properly, even though the wire_bytes is correctly populated. In this situation, we log to trace and continue. `#34460`_ + +- **PR** `#41421`_: (*UtahDave*) Correct doc to actually blacklist a module + @ *2017-05-25T21:01:46Z* + + * 8244287 Merge pull request `#41421`_ from UtahDave/fix_blacklist_docs + * 5eb2757 Correct doc to actually blacklist a module + +- **PR** `#41431`_: (*terminalmage*) Fix regression in state orchestration + @ *2017-05-25T18:44:53Z* + + - **ISSUE** `#41353`_: (*rmarchei*) Orchestrate runner needs saltenv on 2016.11.5 + | refs: `#41431`_ + * b98d5e0 Merge pull request `#41431`_ from terminalmage/issue41353 + * 16eae64 Fix regression in state orchestration + +- **PR** `#41429`_: (*ricohouse*) Issue `#41338`_: Return false when compare config fails + @ *2017-05-25T17:18:02Z* + + - **ISSUE** `#41338`_: (*ricohouse*) Exception not raised when running config compare and the device (Juniper) returns error + | refs: `#41429`_ + * eeff3dd Merge pull request `#41429`_ from ricohouse/fix-compare-bug + * 9b61665 Issue `#41338`_: Return false when compare config fails + +- **PR** `#41414`_: (*Ch3LL*) Update bootstrap script verstion to latest release(v2017.05.24) + @ *2017-05-24T19:51:49Z* + + * 561a416 Merge pull request `#41414`_ from Ch3LL/update_bootstrap + * d8c03ee Update bootstrap script verstion to latest release(v2017.05.24) + +- **PR** `#41336`_: (*mcalmer*) fix setting and getting locale on SUSE systems + @ *2017-05-24T17:46:08Z* + + * 88fd3c0 Merge pull request `#41336`_ from mcalmer/fix-locale-on-SUSE + * f30f5c8 fix unit tests + + * 428baa9 fix setting and getting locale on SUSE systems + +- **PR** `#41393`_: (*rallytime*) Back-port `#41235`_ to 2016.11 + @ *2017-05-24T16:08:56Z* + + - **PR** `#41235`_: (*moio*) rest_cherrypy: remove sleep call + | refs: `#41393`_ + * 4265959 Merge pull request `#41393`_ from rallytime/`bp-41235`_ + * c79c0e3 rest_cherrypy: remove sleep call + +- **PR** `#41394`_: (*rallytime*) Back-port `#41243`_ to 2016.11 + @ *2017-05-24T16:00:17Z* + + - **PR** `#41243`_: (*arif-ali*) Remove the keys that don't exist in the new change + | refs: `#41394`_ + * 83f5469 Merge pull request `#41394`_ from rallytime/`bp-41243`_ + * a535130 Lint fix + + * 05fadc0 Remove the keys that don't exist in the new change + +- **PR** `#41401`_: (*bdrung*) Add documentation key to systemd service files + @ *2017-05-24T15:49:54Z* + + * 3a45ac3 Merge pull request `#41401`_ from bdrung/systemd-service-documentation-key + * 3f7f308 Add documentation key to systemd service files + +- **PR** `#41404`_: (*bdrung*) Fix typos + @ *2017-05-24T14:42:44Z* + + * d34333c Merge pull request `#41404`_ from bdrung/fix-typos + * 33a7f8b Fix typos + +- **PR** `#41388`_: (*bdrung*) Do not require sphinx-build for cleaning docs + @ *2017-05-23T19:32:41Z* + + * 3083764 Merge pull request `#41388`_ from bdrung/clean-doc-without-sphinx + * 5b79a0a Do not require sphinx-build for cleaning docs + +- **PR** `#41364`_: (*automate-solutions*) Fix issue `#41362`_ invalid parameter used: KeyName.1 instead of KeyName + @ *2017-05-23T17:32:10Z* + + - **ISSUE** `#41362`_: (*automate-solutions*) On AWS EC2: salt-cloud -f delete_keypair ec2 keyname=mykeypair doesn't delete the keypair + * 842875e Merge pull request `#41364`_ from automate-solutions/fix-issue-41362 + * cfd8eb7 Set DescribeKeyPairs back to KeyName.1 according to documentation + + * 6a82ddc Fix issue `#41362`_ invalid parameter used: KeyName.1 instead of KeyName + +- **PR** `#41383`_: (*peter-funktionIT*) Update win_pki.py + | refs: `#41453`_ + @ *2017-05-23T17:26:43Z* + + - **ISSUE** `#40950`_: (*idokaplan*) Import certificate + | refs: `#41383`_ `#41453`_ + * 92f94e6 Merge pull request `#41383`_ from peter-funktionIT/fix-win_pki-get_cert_file + * 4d9bd06 Update win_pki.py + +- **PR** `#41113`_: (*cro*) Rescue proxy_auto_tests PR from git rebase hell + @ *2017-05-22T17:05:07Z* + + - **PR** `#39575`_: (*cro*) WIP: Proxy auto test, feedback appreciated + | refs: `#41113`_ + * 1ba9568 Merge pull request `#41113`_ from cro/proxy_auto_test2 + * 19db038 Fix test--use proxy_config instead of minion_config + + * 7749cea Change default proxy minion opts so only the proxy-specific ones are listed, and the rest are taken from DEFAULT_MINION_OPTS. + + * 106394c Lint. + + * 3be90cc Rescue proxy_auto_tests PR from git rebase hell + +- **PR** `#41360`_: (*cro*) Sysrc on FreeBSD, YAML overeager to coerce to bool and int + @ *2017-05-22T15:54:31Z* + + * 375892d Merge pull request `#41360`_ from cro/sysrc_fix + * 6db31ce Fix problem with sysrc on FreeBSD, YAML overeager to coerce to bool and int. + +- **PR** `#41372`_: (*terminalmage*) Don't use intermediate file when listing contents of tar.xz file + @ *2017-05-22T15:36:45Z* + + - **ISSUE** `#41190`_: (*jheidbrink*) Cannot extract tar.xz archive when it exceeds size of /tmp + | refs: `#41372`_ + * 01b71c7 Merge pull request `#41372`_ from terminalmage/issue41190 + * 1f08936 Remove unused import + + * 68cb897 Replace reference to fileobj + + * 7888744 Remove '*' from mode + + * 3d4b833 Don't use intermediate file when listing contents of tar.xz file + +- **PR** `#41373`_: (*alex-zel*) Allow HTTP authentication to ES. + @ *2017-05-22T15:32:09Z* + + * 5edfcf9 Merge pull request `#41373`_ from alex-zel/patch-3 + * 3192eab Allow HTTP authentication to ES. + +- **PR** `#41287`_: (*garethgreenaway*) Fix to consul cache + @ *2017-05-19T18:32:56Z* + + - **ISSUE** `#40748`_: (*djhaskin987*) Consul backend minion cache does not work + | refs: `#41287`_ + * 29bd7f4 Merge pull request `#41287`_ from garethgreenaway/40748_2016_11_consul + * 5039fe1 Removing chdir as it is no needed with this change + + * 4550c3c 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`_ + +- **PR** `#41309`_: (*garethgreenaway*) Adding test argument for runners & wheel orchestration modules + @ *2017-05-19T18:26:09Z* + + - **ISSUE** `#38894`_: (*amendlik*) salt.runner and salt.wheel ignore test=True + | refs: `#41309`_ `#41611`_ + * 672aaa8 Merge pull request `#41309`_ from garethgreenaway/38894_allowing_test_argument + * e1a88e8 Allowing test=True to be passed for salt.runner and salt.wheel when used with orchestration + +- **PR** `#41319`_: (*lomeroe*) backport `#41307`_ to 2016.11, properly pack version numbers into single + @ *2017-05-19T18:25:00Z* + + - **ISSUE** `#41306`_: (*lomeroe*) win_lgpo does not properly pack group policy version number in gpt.ini + | refs: `#41319`_ `#41307`_ + - **PR** `#41307`_: (*lomeroe*) properly pack/unpack the verison numbers into a number + | refs: `#41319`_ + * 140b042 Merge pull request `#41319`_ from lomeroe/bp_41307 + * 4f0aa57 backport 41307 to 2016.11, properly pack version numbers into single number + +- **PR** `#41327`_: (*Ch3LL*) Add 2016.11.6 Release Notes + @ *2017-05-19T18:05:09Z* + + * 6bdb7cc Merge pull request `#41327`_ from Ch3LL/add_2016.11.6_release + * e5fc0ae Add 2016.11.6 Release Notes + +- **PR** `#41329`_: (*lorengordon*) Corrects versionadded for win_network.get_route + @ *2017-05-19T17:47:57Z* + + * 1faffd3 Merge pull request `#41329`_ from lorengordon/doc-fix + * 3c47124 Corrects versionadded for win_network.get_route + +- **PR** `#41322`_: (*Ch3LL*) Add patched packages warning to 2016.11.5 release notes + @ *2017-05-18T21:53:26Z* + + * 6ca6559 Merge pull request `#41322`_ from Ch3LL/fix_release_2016.11.5_notes + * 9a1bf42 fix url refs in rst + + * cde008f Add patched packages warning to 2016.11.5 release notes + +- **PR** `#41208`_: (*pkazmierczak*) Fix: zypper handling of multiple version packages + @ *2017-05-18T15:44:26Z* + + * 9f359d8 Merge pull request `#41208`_ from pkazmierczak/pkazmierczak-zypper-multiple-ver-pkgs + * d411a91 Reverted back to cascading with statements for python 2.6 compat + + * 7204013 Compacted with statements in the unit test. + + * 6c4c080 Added unit tests and copied the behavior to .upgrade method, too. + + * 5f95200 Fix: zypper handling of multiple version packages + +- **PR** `#41317`_: (*Ch3LL*) [2016.11] Bump latest release version to 2016.11.5 + @ *2017-05-18T15:34:13Z* + + * bcef99a Merge pull request `#41317`_ from Ch3LL/update_latest_2016.11 + * cdb072c [2016.11] Bump latest release version to 2016.11.5 + +- **PR** `#41232`_: (*axmetishe*) Add basic auth for SPM + @ *2017-05-17T19:08:56Z* + + * b8ddd7e Merge pull request `#41232`_ from axmetishe/2016.11 + * 76104f23 Add basic auth for SPM + +- **PR** `#41236`_: (*BenoitKnecht*) states: cron: show correct changes when using `special` + @ *2017-05-17T18:51:58Z* + + * 7bdb66d Merge pull request `#41236`_ from BenoitKnecht/2016.11 + * 33211d0 states: cron: show correct changes when using `special` + +- **PR** `#41269`_: (*isbm*) Bugfix: Unable to use "127" as hostname for the Minion ID + @ *2017-05-17T18:31:15Z* + + * 1c1e092 Merge pull request `#41269`_ from isbm/isbm-minion-id-127-name + * 5168ef8 Add unit test for hostname can be started from 127 + + * 0d03541 Harden to 127. IP part + + * d9c8324 Unit test for accepting hosts names as 127 + + * 65b03c6 Bugfix: unable to use 127 as hostname + +- **PR** `#41289`_: (*garethgreenaway*) Fixing consul cache + @ *2017-05-17T16:54:12Z* + + * d0fa31d Merge pull request `#41289`_ from garethgreenaway/2016_11_5_fix_consul_cache_ls + * 780a28c Swapping the order in the func_alias so the ls function is available. + +- **PR** `#41303`_: (*lomeroe*) backport `#41301`_ -- properly convert packed string to decimal values + @ *2017-05-17T16:32:22Z* + + - **ISSUE** `#41291`_: (*lomeroe*) win_lgpo does not properly convert large decimal values in regpol data + | refs: `#41301`_ `#41303`_ + - **PR** `#41301`_: (*lomeroe*) properly convert packed string to decimal values + | refs: `#41303`_ + * 6566648 Merge pull request `#41303`_ from lomeroe/`bp-41301`_ + * f4b93f9 properly convert packed string to decimal values + +- **PR** `#41283`_: (*terminalmage*) Backport `#41251`_ to 2016.11 + @ *2017-05-16T18:01:17Z* + + - **ISSUE** `#41231`_: (*kaihowl*) PR `#30777`_ misses an update to the documentation for pkg.installed and hold:true + | refs: `#41251`_ + - **ISSUE** `#30733`_: (*ealphonse*) version-controlled packages with hold: True can no longer be upgraded by salt + | refs: `#30777`_ + - **PR** `#41251`_: (*abednarik*) Update apt module regarding upgrade against hold packages. + - **PR** `#30777`_: (*abednarik*) Fix update apt hold pkgs + | refs: `#41251`_ + * 4459861 Merge pull request `#41283`_ from terminalmage/`bp-41251`_ + * ed03ca5 Update apt module regarding upgrade against hold packages. + +- **PR** `#41181`_: (*gtmanfred*) add resolving extra flags to yum upgrade + @ *2017-05-16T04:07:47Z* + + * d8e9676 Merge pull request `#41181`_ from gtmanfred/2016.11 + * 2ca7171 use six and clean_kwargs + + * c9bf09a add resolving extra flags to yum upgrade + +- **PR** `#41220`_: (*rallytime*) Back-port `#40246`_ to 2016.11 + @ *2017-05-15T17:59:38Z* + + - **ISSUE** `#40177`_: (*eldadru*) libcloud_dns state "global name '__salt__' is not defined" in salt.cmd runner + | refs: `#40246`_ `#40246`_ + - **PR** `#40246`_: (*tonybaloney*) Fix libcloud_dns state module bug + | refs: `#41220`_ + * 7594223 Merge pull request `#41220`_ from rallytime/`bp-40246`_ + * 79f1bb2 Remove unused/duplicate imports leftover from merge-conflict resolution + + * 2f61068 remove unused imports + + * 9b7de2e fix unit tests + + * 49d9455 linting + + * 4b260a4 linting + + * 41d1ada fix up tests + + * b3822e0 add fixes for incorrectly importing modules directly instead of using __salt__ + +- **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** `#41242`_: (*pprkut*) Fix changing a mysql user to unix socket authentication. + @ *2017-05-15T17:00:06Z* + + * 895fe58 Merge pull request `#41242`_ from M2Mobi/mysql_socket_auth + * 7d83597 Fix changing a mysql user to unix socket authentication. + +- **PR** `#41101`_: (*terminalmage*) Fix "latest" keyword for version specification when used with aggregation + @ *2017-05-15T16:52:35Z* + + - **ISSUE** `#40940`_: (*djhaskin987*) When `state_aggregate` is set to `True`, the `latest` keyword doesn't work with pkg.installed + | refs: `#41101`_ + * 50d8fde Merge pull request `#41101`_ from terminalmage/issue40940 + * 7fe6421 Add rtag check to integration test for pkg.refresh_db + + * 88a08aa Add comments to explain what removing the rtag file actually does + + * 92011db Fix "latest" keyword for version specification when used with aggregation + +- **PR** `#41146`_: (*terminalmage*) gitfs: Backport performance fixes for getting tree objects + @ *2017-05-12T17:35:47Z* + + - **ISSUE** `#34775`_: (*babilen*) Please allow users to disable branch environment mapping in GitFS + | refs: `#41144`_ + - **PR** `#41144`_: (*terminalmage*) gitfs: Add two new options to affect saltenv mapping + | refs: `#41146`_ + * 049712b Merge pull request `#41146`_ from terminalmage/backport-get_tree-performance-improvement + * f9d6734 gitfs: Backport performance fixes for getting tree objects + +- **PR** `#41161`_: (*The-Loeki*) gpg renderer: fix gpg_keydir always reverting to default + @ *2017-05-12T17:19:07Z* + + - **ISSUE** `#41135`_: (*shallot*) gpg renderer doesn't seem to work with salt-ssh, tries to execute gpg on the minion? + | refs: `#41161`_ + * 4215a0b Merge pull request `#41161`_ from The-Loeki/2016.11 + * 24946fe gpg renderer: fix gpg_keydir always reverting to default + +- **PR** `#41163`_: (*onlyanegg*) Elasticsearch - pass hosts and profile to index_exists() + @ *2017-05-12T17:18:06Z* + + - **ISSUE** `#41162`_: (*onlyanegg*) Elasticsearch module functions should pass hosts and profile to index_exists() + | refs: `#41163`_ + * 5b10fc5 Merge pull request `#41163`_ from onlyanegg/elasticsearch-pass_profile_to_index_exists + * 7f512c7 Pass hosts and profile to index_exists() method + +- **PR** `#41186`_: (*jmarinaro*) Fix package name collisions in chocolatey state + @ *2017-05-12T17:01:31Z* + + - **ISSUE** `#41185`_: (*jmarinaro*) package name collisions in chocolatey state + | refs: `#41186`_ + * d433cf8 Merge pull request `#41186`_ from jmarinaro/fix-chocolatey-package-collision + * 229f3bf apply changes to uninstalled function + + * ffd4c7e Fix package name collisions in chocolatey state + +- **PR** `#41189`_: (*github-abcde*) utils/minions.py: Fixed case where data is an empty dict resulting in… + @ *2017-05-12T16:32:25Z* + + * bb5ef41 Merge pull request `#41189`_ from github-abcde/utils-minions-fix + * 853dc54 utils/minions.py: Fixed case where data is an empty dict resulting in errors. + +- **PR** `#41104`_: (*Ch3LL*) Add test to query results of /jobs call in api + @ *2017-05-10T20:11:08Z* + + * b136b15 Merge pull request `#41104`_ from Ch3LL/add_jobs_test + * dac1658 add test to query results of /jobs call in api + +- **PR** `#41170`_: (*lomeroe*) Backport `#41081`_ to 2016.11 + @ *2017-05-10T19:58:52Z* + + - **PR** `#41081`_: (*lomeroe*) Update win_dns_client to use reg.read_value and set_value + | refs: `#41170`_ + * ca18b4d Merge pull request `#41170`_ from lomeroe/`bp-41081`_ + * 2af89f2 update mock data + + * b7fa115 update win_dns_client tests with correct module names + + * 4d05a22 Update win_dns_client to use reg.read_value and set_value + +- **PR** `#41173`_: (*twangboy*) Add silent action to MsgBox for Path Actions + @ *2017-05-10T19:57:06Z* + + * d7ec37b Merge pull request `#41173`_ from twangboy/fix_installer + * 24b11ff Add release notes + + * 96918dc Add silent action to MsgBox for Path Actions + +- **PR** `#41158`_: (*Ch3LL*) 2016.11.5 release notes: add additional commits + @ *2017-05-09T22:41:40Z* + + * 88e93b7 Merge pull request `#41158`_ from Ch3LL/update_2016.11.5 + * 28371aa 2016.11.5 release notes: add additional commits + +- **PR** `#41148`_: (*rallytime*) [2016.11] Merge forward from 2016.3 to 2016.11 + @ *2017-05-09T20:23:28Z* + + - **PR** `#41123`_: (*terminalmage*) Add note on lack of support for VSTS in older libssh2 releases. + - **PR** `#41122`_: (*terminalmage*) gitfs: refresh env cache during update in masterless + - **PR** `#41090`_: (*bbinet*) rdurations should be floats so that they can be summed when profiling + * d2ae7de Merge pull request `#41148`_ from rallytime/merge-2016.11 + * aba35e2 Merge branch '2016.3' into '2016.11' + + * 2969153 Merge pull request `#41122`_ from terminalmage/masterless-env_cache-fix + + * be732f0 gitfs: refresh env cache during update in masterless + + * b8f0a4f Merge pull request `#41123`_ from terminalmage/gitfs-vsts-note + + * f6a1695 Add note on lack of support for VSTS in older libssh2 releases. + + * 8f79b6f Merge pull request `#41090`_ from bbinet/rdurations_float + + * fd48a63 rdurations should be floats so that they can be summed when profiling + +- **PR** `#41147`_: (*rallytime*) Back-port `#39676`_ to 2016.11 + @ *2017-05-09T18:40:44Z* + + - **PR** `#39676`_: (*F30*) Fix comments about the "hash_type" option + | refs: `#41147`_ + * 2156395 Merge pull request `#41147`_ from rallytime/`bp-39676`_ + * 5b55fb2 Fix comments about the "hash_type" option + +- **PR** `#40852`_: (*isbm*) Isbm fix coregrains constants bsc`#1032931`_ + @ *2017-05-09T18:35:46Z* + + - **ISSUE** `#1032931`_: (**) + * a2f359f Merge pull request `#40852`_ from isbm/isbm-fix-coregrains-constants-bsc`#1032931`_ + * f3b12a3 Do not use multiple variables in "with" statement as of lint issues + + * 35a8d99 Disable the test for a while + + * 76cb1b7 Rewrite test case for using no patch decorators + + * f71af0b Fix lint issues + + * 0e6abb3 Add UT on set_hw_clock on Gentoo + + * a2b1d46 Add UT for set_hwclock on Debian + + * 5356a08 Bugfix: use correct grain name for SUSE platform + + * 88e8184 Add UT set_hwclock on SUSE + + * 0cd590f Fix UT names + + * bee94ad Add UT for set_hwclock on RedHat + + * dfe2610 Add UT for set_hwclock on Arch + + * d000a8a Add UT for set_hwclock on solaris + + * d2614ae Fix docstrings + + * 6d78219 Add UT for set_hwclock on AIX + + * d303e0d Add UT for AIX on get_hwclock + + * 86f2d83 Add UT on Solaris + + * c3cafed Add UT for Debian on get_hwclock + + * d337c09 Add UT for RedHat/SUSE platforms on get_hwclock + + * 501a59c Bugfix: use correct grain for SUSE and RedHat platform + + * f25dc5c Add UT for get_hwclock on SUSE platform + + * 08e00c8 Remove dead code + + * 1216a0b Add UT for get_hwclock on UTC/localtime + + * 39332c7 Remove duplicate code + + * 58676c5 Add UT for Debian on set_zone + + * 1b9ce37 Add UT for gentoo on set_zone + + * cf7f766 Bugfix: use correct os_family grain value for SUSE series + + * 6ed9be9 Adjust UT to use correct grain for SUSE series + + * ce4c836 Add UT for set_zone on SUSE series + + * 155a498 Doc fix + + * a40876c Remove unnecessary mock patch + + * ffab2db Fix doc for RH UT + + * 72388f7 Add UT for RedHat's set_zone + + * 11595d3 Refactor with setup/teardown + + * ce6a06d Bugfix: use correct grain constant for platform + + * 28072c9 Adjust the test so it is using the right grain for SUSE systems + + * 7a0e4be Add unit test for get_zone and various platforms + +- **PR** `#41111`_: (*terminalmage*) Allow "ssl_verify: False" to work with pygit2 + @ *2017-05-09T17:56:12Z* + + - **ISSUE** `#41105`_: (*terminalmage*) ssl_verify gitfs/git_pillar option does not work with pygit2 + | refs: `#41111`_ + * 6fa41dc Merge pull request `#41111`_ from terminalmage/issue41105 + * 8c6410e Add notices about ssl_verify only working in 0.23.2 and newer + + * 98ce829 Support ssl_verify in pygit2 + + * f73c4b7 Add http(s) auth config docs for GitPython + +- **PR** `#41008`_: (*cro*) Look in /opt/*/lib instead of just /opt/local/lib on Illumos distros. + @ *2017-05-09T16:56:00Z* + + * 81add1b Merge pull request `#41008`_ from cro/rsax_smos + * a4f7aa1 Look for libcrypto in both /opt/tools and /opt/local on Illumos-based distros. + +- **PR** `#41124`_: (*gtmanfred*) add user_data to digitalocean + @ *2017-05-09T16:47:42Z* + + * c649725 Merge pull request `#41124`_ from gtmanfred/do + * 2370d93 add user_data to digital ocean + +- **PR** `#41127`_: (*tmeneau*) Fix incorrect service.running state response when enable=None and init script returns 0 + @ *2017-05-09T16:43:35Z* + + - **ISSUE** `#41125`_: (*tmeneau*) service.running returns True if enable=None and init script returns 0 + | refs: `#41127`_ + * d0a3fcf Merge pull request `#41127`_ from xetus-oss/`fix-41125`_-service-running + * d876656 fix incorrect service.running success response + + +.. _`#1032931`: https://github.com/saltstack/salt/issues/1032931 +.. _`#16592`: https://github.com/saltstack/salt/issues/16592 +.. _`#22`: https://github.com/saltstack/salt/issues/22 +.. _`#30733`: https://github.com/saltstack/salt/issues/30733 +.. _`#30777`: https://github.com/saltstack/salt/pull/30777 +.. _`#32743`: https://github.com/saltstack/salt/issues/32743 +.. _`#34460`: https://github.com/saltstack/salt/issues/34460 +.. _`#34775`: https://github.com/saltstack/salt/issues/34775 +.. _`#35481`: https://github.com/saltstack/salt/issues/35481 +.. _`#35874`: https://github.com/saltstack/salt/issues/35874 +.. _`#36548`: https://github.com/saltstack/salt/issues/36548 +.. _`#37322`: https://github.com/saltstack/salt/issues/37322 +.. _`#37824`: https://github.com/saltstack/salt/issues/37824 +.. _`#38061`: https://github.com/saltstack/salt/issues/38061 +.. _`#38647`: https://github.com/saltstack/salt/pull/38647 +.. _`#38894`: https://github.com/saltstack/salt/issues/38894 +.. _`#39575`: https://github.com/saltstack/salt/pull/39575 +.. _`#39668`: https://github.com/saltstack/salt/issues/39668 +.. _`#39676`: https://github.com/saltstack/salt/pull/39676 +.. _`#39850`: https://github.com/saltstack/salt/pull/39850 +.. _`#39918`: https://github.com/saltstack/salt/issues/39918 +.. _`#39939`: https://github.com/saltstack/salt/issues/39939 +.. _`#40155`: https://github.com/saltstack/salt/issues/40155 +.. _`#40177`: https://github.com/saltstack/salt/issues/40177 +.. _`#40246`: https://github.com/saltstack/salt/pull/40246 +.. _`#40410`: https://github.com/saltstack/salt/issues/40410 +.. _`#40446`: https://github.com/saltstack/salt/issues/40446 +.. _`#40605`: https://github.com/saltstack/salt/issues/40605 +.. _`#40748`: https://github.com/saltstack/salt/issues/40748 +.. _`#40752`: https://github.com/saltstack/salt/pull/40752 +.. _`#40837`: https://github.com/saltstack/salt/pull/40837 +.. _`#40852`: https://github.com/saltstack/salt/pull/40852 +.. _`#40902`: https://github.com/saltstack/salt/pull/40902 +.. _`#40912`: https://github.com/saltstack/salt/issues/40912 +.. _`#40934`: https://github.com/saltstack/salt/pull/40934 +.. _`#40940`: https://github.com/saltstack/salt/issues/40940 +.. _`#40950`: https://github.com/saltstack/salt/issues/40950 +.. _`#41008`: https://github.com/saltstack/salt/pull/41008 +.. _`#41081`: https://github.com/saltstack/salt/pull/41081 +.. _`#41090`: https://github.com/saltstack/salt/pull/41090 +.. _`#41101`: https://github.com/saltstack/salt/pull/41101 +.. _`#41104`: https://github.com/saltstack/salt/pull/41104 +.. _`#41105`: https://github.com/saltstack/salt/issues/41105 +.. _`#41111`: https://github.com/saltstack/salt/pull/41111 +.. _`#41113`: https://github.com/saltstack/salt/pull/41113 +.. _`#41122`: https://github.com/saltstack/salt/pull/41122 +.. _`#41123`: https://github.com/saltstack/salt/pull/41123 +.. _`#41124`: https://github.com/saltstack/salt/pull/41124 +.. _`#41125`: https://github.com/saltstack/salt/issues/41125 +.. _`#41127`: https://github.com/saltstack/salt/pull/41127 +.. _`#41135`: https://github.com/saltstack/salt/issues/41135 +.. _`#41144`: https://github.com/saltstack/salt/pull/41144 +.. _`#41146`: https://github.com/saltstack/salt/pull/41146 +.. _`#41147`: https://github.com/saltstack/salt/pull/41147 +.. _`#41148`: https://github.com/saltstack/salt/pull/41148 +.. _`#41154`: https://github.com/saltstack/salt/issues/41154 +.. _`#41158`: https://github.com/saltstack/salt/pull/41158 +.. _`#41161`: https://github.com/saltstack/salt/pull/41161 +.. _`#41162`: https://github.com/saltstack/salt/issues/41162 +.. _`#41163`: https://github.com/saltstack/salt/pull/41163 +.. _`#41170`: https://github.com/saltstack/salt/pull/41170 +.. _`#41173`: https://github.com/saltstack/salt/pull/41173 +.. _`#41181`: https://github.com/saltstack/salt/pull/41181 +.. _`#41185`: https://github.com/saltstack/salt/issues/41185 +.. _`#41186`: https://github.com/saltstack/salt/pull/41186 +.. _`#41189`: https://github.com/saltstack/salt/pull/41189 +.. _`#41190`: https://github.com/saltstack/salt/issues/41190 +.. _`#41208`: https://github.com/saltstack/salt/pull/41208 +.. _`#41216`: https://github.com/saltstack/salt/pull/41216 +.. _`#41220`: https://github.com/saltstack/salt/pull/41220 +.. _`#41230`: https://github.com/saltstack/salt/issues/41230 +.. _`#41231`: https://github.com/saltstack/salt/issues/41231 +.. _`#41232`: https://github.com/saltstack/salt/pull/41232 +.. _`#41234`: https://github.com/saltstack/salt/issues/41234 +.. _`#41235`: https://github.com/saltstack/salt/pull/41235 +.. _`#41236`: https://github.com/saltstack/salt/pull/41236 +.. _`#41242`: https://github.com/saltstack/salt/pull/41242 +.. _`#41243`: https://github.com/saltstack/salt/pull/41243 +.. _`#41244`: https://github.com/saltstack/salt/pull/41244 +.. _`#41251`: https://github.com/saltstack/salt/pull/41251 +.. _`#41255`: https://github.com/saltstack/salt/pull/41255 +.. _`#41265`: https://github.com/saltstack/salt/pull/41265 +.. _`#41269`: https://github.com/saltstack/salt/pull/41269 +.. _`#41283`: https://github.com/saltstack/salt/pull/41283 +.. _`#41287`: https://github.com/saltstack/salt/pull/41287 +.. _`#41289`: https://github.com/saltstack/salt/pull/41289 +.. _`#41291`: https://github.com/saltstack/salt/issues/41291 +.. _`#41301`: https://github.com/saltstack/salt/pull/41301 +.. _`#41303`: https://github.com/saltstack/salt/pull/41303 +.. _`#41306`: https://github.com/saltstack/salt/issues/41306 +.. _`#41307`: https://github.com/saltstack/salt/pull/41307 +.. _`#41309`: https://github.com/saltstack/salt/pull/41309 +.. _`#41316`: https://github.com/saltstack/salt/pull/41316 +.. _`#41317`: https://github.com/saltstack/salt/pull/41317 +.. _`#41319`: https://github.com/saltstack/salt/pull/41319 +.. _`#41322`: https://github.com/saltstack/salt/pull/41322 +.. _`#41327`: https://github.com/saltstack/salt/pull/41327 +.. _`#41329`: https://github.com/saltstack/salt/pull/41329 +.. _`#41335`: https://github.com/saltstack/salt/issues/41335 +.. _`#41336`: https://github.com/saltstack/salt/pull/41336 +.. _`#41337`: https://github.com/saltstack/salt/pull/41337 +.. _`#41338`: https://github.com/saltstack/salt/issues/41338 +.. _`#41341`: https://github.com/saltstack/salt/issues/41341 +.. _`#41350`: https://github.com/saltstack/salt/pull/41350 +.. _`#41353`: https://github.com/saltstack/salt/issues/41353 +.. _`#41360`: https://github.com/saltstack/salt/pull/41360 +.. _`#41362`: https://github.com/saltstack/salt/issues/41362 +.. _`#41364`: https://github.com/saltstack/salt/pull/41364 +.. _`#41365`: https://github.com/saltstack/salt/issues/41365 +.. _`#41372`: https://github.com/saltstack/salt/pull/41372 +.. _`#41373`: https://github.com/saltstack/salt/pull/41373 +.. _`#41383`: https://github.com/saltstack/salt/pull/41383 +.. _`#41388`: https://github.com/saltstack/salt/pull/41388 +.. _`#41393`: https://github.com/saltstack/salt/pull/41393 +.. _`#41394`: https://github.com/saltstack/salt/pull/41394 +.. _`#41397`: https://github.com/saltstack/salt/pull/41397 +.. _`#41398`: https://github.com/saltstack/salt/pull/41398 +.. _`#41401`: https://github.com/saltstack/salt/pull/41401 +.. _`#41404`: https://github.com/saltstack/salt/pull/41404 +.. _`#41409`: https://github.com/saltstack/salt/pull/41409 +.. _`#41414`: https://github.com/saltstack/salt/pull/41414 +.. _`#41421`: https://github.com/saltstack/salt/pull/41421 +.. _`#41429`: https://github.com/saltstack/salt/pull/41429 +.. _`#41431`: https://github.com/saltstack/salt/pull/41431 +.. _`#41435`: https://github.com/saltstack/salt/issues/41435 +.. _`#41436`: https://github.com/saltstack/salt/pull/41436 +.. _`#41439`: https://github.com/saltstack/salt/pull/41439 +.. _`#41442`: https://github.com/saltstack/salt/pull/41442 +.. _`#41443`: https://github.com/saltstack/salt/pull/41443 +.. _`#41453`: https://github.com/saltstack/salt/pull/41453 +.. _`#41456`: https://github.com/saltstack/salt/pull/41456 +.. _`#41464`: https://github.com/saltstack/salt/pull/41464 +.. _`#41469`: https://github.com/saltstack/salt/pull/41469 +.. _`#41473`: https://github.com/saltstack/salt/pull/41473 +.. _`#41478`: https://github.com/saltstack/salt/issues/41478 +.. _`#41487`: https://github.com/saltstack/salt/pull/41487 +.. _`#41490`: https://github.com/saltstack/salt/pull/41490 +.. _`#41499`: https://github.com/saltstack/salt/pull/41499 +.. _`#41504`: https://github.com/saltstack/salt/issues/41504 +.. _`#41506`: https://github.com/saltstack/salt/pull/41506 +.. _`#41509`: https://github.com/saltstack/salt/pull/41509 +.. _`#41512`: https://github.com/saltstack/salt/pull/41512 +.. _`#41522`: https://github.com/saltstack/salt/pull/41522 +.. _`#41530`: https://github.com/saltstack/salt/pull/41530 +.. _`#41533`: https://github.com/saltstack/salt/pull/41533 +.. _`#41539`: https://github.com/saltstack/salt/pull/41539 +.. _`#41540`: https://github.com/saltstack/salt/issues/41540 +.. _`#41545`: https://github.com/saltstack/salt/issues/41545 +.. _`#41551`: https://github.com/saltstack/salt/pull/41551 +.. _`#41552`: https://github.com/saltstack/salt/pull/41552 +.. _`#41557`: https://github.com/saltstack/salt/pull/41557 +.. _`#41561`: https://github.com/saltstack/salt/pull/41561 +.. _`#41569`: https://github.com/saltstack/salt/pull/41569 +.. _`#41575`: https://github.com/saltstack/salt/pull/41575 +.. _`#41596`: https://github.com/saltstack/salt/pull/41596 +.. _`#41597`: https://github.com/saltstack/salt/pull/41597 +.. _`#41599`: https://github.com/saltstack/salt/pull/41599 +.. _`#41611`: https://github.com/saltstack/salt/pull/41611 +.. _`#41616`: https://github.com/saltstack/salt/pull/41616 +.. _`#41626`: https://github.com/saltstack/salt/issues/41626 +.. _`#41629`: https://github.com/saltstack/salt/issues/41629 +.. _`#41637`: https://github.com/saltstack/salt/pull/41637 +.. _`#41638`: https://github.com/saltstack/salt/pull/41638 +.. _`#41639`: https://github.com/saltstack/salt/pull/41639 +.. _`#41651`: https://github.com/saltstack/salt/issues/41651 +.. _`#41654`: https://github.com/saltstack/salt/issues/41654 +.. _`#41655`: https://github.com/saltstack/salt/pull/41655 +.. _`#41656`: https://github.com/saltstack/salt/pull/41656 +.. _`#41658`: https://github.com/saltstack/salt/pull/41658 +.. _`#41659`: https://github.com/saltstack/salt/pull/41659 +.. _`#41660`: https://github.com/saltstack/salt/pull/41660 +.. _`#41661`: https://github.com/saltstack/salt/pull/41661 +.. _`#41663`: https://github.com/saltstack/salt/pull/41663 +.. _`#41668`: https://github.com/saltstack/salt/issues/41668 +.. _`#41670`: https://github.com/saltstack/salt/pull/41670 +.. _`#41688`: https://github.com/saltstack/salt/issues/41688 +.. _`#41689`: https://github.com/saltstack/salt/pull/41689 +.. _`#41691`: https://github.com/saltstack/salt/issues/41691 +.. _`#41692`: https://github.com/saltstack/salt/pull/41692 +.. _`#41693`: https://github.com/saltstack/salt/pull/41693 +.. _`#41694`: https://github.com/saltstack/salt/pull/41694 +.. _`#41696`: https://github.com/saltstack/salt/pull/41696 +.. _`#41697`: https://github.com/saltstack/salt/pull/41697 +.. _`#41699`: https://github.com/saltstack/salt/pull/41699 +.. _`#41700`: https://github.com/saltstack/salt/pull/41700 +.. _`#41702`: https://github.com/saltstack/salt/pull/41702 +.. _`#41704`: https://github.com/saltstack/salt/pull/41704 +.. _`#41706`: https://github.com/saltstack/salt/pull/41706 +.. _`#41707`: https://github.com/saltstack/salt/pull/41707 +.. _`#41710`: https://github.com/saltstack/salt/pull/41710 +.. _`#41711`: https://github.com/saltstack/salt/pull/41711 +.. _`#41723`: https://github.com/saltstack/salt/pull/41723 +.. _`#41731`: https://github.com/saltstack/salt/pull/41731 +.. _`bp-39676`: https://github.com/saltstack/salt/pull/39676 +.. _`bp-39850`: https://github.com/saltstack/salt/pull/39850 +.. _`bp-40246`: https://github.com/saltstack/salt/pull/40246 +.. _`bp-41081`: https://github.com/saltstack/salt/pull/41081 +.. _`bp-41235`: https://github.com/saltstack/salt/pull/41235 +.. _`bp-41243`: https://github.com/saltstack/salt/pull/41243 +.. _`bp-41251`: https://github.com/saltstack/salt/pull/41251 +.. _`bp-41301`: https://github.com/saltstack/salt/pull/41301 +.. _`bp-41487`: https://github.com/saltstack/salt/pull/41487 +.. _`bp-41533`: https://github.com/saltstack/salt/pull/41533 +.. _`bp-41551`: https://github.com/saltstack/salt/pull/41551 +.. _`bp-41575`: https://github.com/saltstack/salt/pull/41575 +.. _`bp-41670`: https://github.com/saltstack/salt/pull/41670 +.. _`fix-40155`: https://github.com/saltstack/salt/issues/40155 +.. _`fix-40410`: https://github.com/saltstack/salt/issues/40410 +.. _`fix-40446`: https://github.com/saltstack/salt/issues/40446 +.. _`fix-40605`: https://github.com/saltstack/salt/issues/40605 +.. _`fix-41125`: https://github.com/saltstack/salt/issues/41125 +.. _`fix-41688`: https://github.com/saltstack/salt/issues/41688 + From 80ac6381c2839b0ab2d4e5924d12b3ea237d78a1 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 14 Jun 2017 15:15:46 -0600 Subject: [PATCH 43/76] Add Windows Master config information --- doc/ref/configuration/master.rst | 135 ++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 18 deletions(-) diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 85a108f75a..82bb3267e7 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -17,6 +17,9 @@ The configuration file for the salt-master is located at configuration file is located at :file:`/usr/local/etc/salt`. The available options are as follows: + +.. _primary-master-configuration: + Primary Master Configuration ============================ @@ -246,7 +249,7 @@ each of Salt's module types such as ``runners``, ``output``, ``wheel``, extension_modules: /root/salt_extmods ``extmod_whitelist/extmod_blacklist`` --------------------- +------------------------------------- .. versionadded:: Nitrogen @@ -852,6 +855,9 @@ what you are doing! Transports are explained in :ref:`Salt Transports ret_port: 4606 zeromq: [] + +.. _salt-ssh-configuration: + Salt-SSH Configuration ====================== @@ -929,6 +935,8 @@ Default: None Identical as `thin_extra_mods`, only applied to the Salt Minimal. +.. _master-security-settings: + Master Security Settings ======================== @@ -1122,7 +1130,7 @@ from the eauth driver each time. .. conf_master:: eauth_acl_module ``eauth_acl_module`` ---------------------- +-------------------- Default: ``''`` @@ -1219,7 +1227,6 @@ signature. The :conf_master:`master_pubkey_signature` must also be set for this. master_use_pubkey_signature: True - .. conf_master:: rotate_aes_key ``rotate_aes_key`` @@ -1236,7 +1243,6 @@ Do not disable this unless it is absolutely clear what this does. rotate_aes_key: True - .. conf_master:: ssl ``ssl`` @@ -1265,7 +1271,7 @@ constant names without ssl module prefix: ``CERT_REQUIRED`` or ``PROTOCOL_SSLv23 .. conf_master:: allow_minion_key_revoke ``allow_minion_key_revoke`` ------------------- +--------------------------- Default: ``True`` @@ -1278,6 +1284,9 @@ the master will drop the request and the minion's key will remain accepted. rotate_aes_key: True + +.. _master-module-management: + Master Module Management ======================== @@ -1310,6 +1319,8 @@ the Salt master. cython_enable: False +.. _master-state-system-settings: + Master State System Settings ============================ @@ -1626,6 +1637,9 @@ If set to ``True``, runner jobs will be saved to job cache (defined by runner_returns: True + +.. _master-file-server-settings: + Master File Server Settings =========================== @@ -1742,7 +1756,7 @@ on a large number of minions. .. conf_master:: fileserver_verify_config ``fileserver_verify_config`` ------------------------------- +---------------------------- .. versionadded:: Nitrogen @@ -3587,6 +3601,9 @@ can be utilized: pillar_cache_backend: disk + +.. _syndic-server-settings: + Syndic Server Settings ====================== @@ -3722,7 +3739,7 @@ check in with their lists of expected minions before giving up. .. conf_master:: syndic_forward_all_events ``syndic_forward_all_events`` -------------------- +----------------------------- .. versionadded:: Nitrogen @@ -3736,6 +3753,8 @@ send events to all connected masters. syndic_forward_all_events: False +.. _peer-publish-settings: + Peer Publish Settings ===================== @@ -3850,7 +3869,6 @@ The level of messages to send to the console. See also :conf_log:`log_level`. log_level: warning - .. conf_master:: log_level_logfile ``log_level_logfile`` @@ -3866,7 +3884,6 @@ it will inherit the level set by :conf_log:`log_level` option. log_level_logfile: warning - .. conf_master:: log_datefmt ``log_datefmt`` @@ -3881,7 +3898,6 @@ The date and time format used in console log messages. See also log_datefmt: '%H:%M:%S' - .. conf_master:: log_datefmt_logfile ``log_datefmt_logfile`` @@ -3896,7 +3912,6 @@ The date and time format used in log file messages. See also log_datefmt_logfile: '%Y-%m-%d %H:%M:%S' - .. conf_master:: log_fmt_console ``log_fmt_console`` @@ -3929,7 +3944,6 @@ The format of the console logging messages. See also log_fmt_console: '%(colorlevel)s %(colormsg)s' log_fmt_console: '[%(levelname)-8s] %(message)s' - .. conf_master:: log_fmt_logfile ``log_fmt_logfile`` @@ -3944,7 +3958,6 @@ The format of the log file logging messages. See also log_fmt_logfile: '%(asctime)s,%(msecs)03d [%(name)-17s][%(levelname)-8s] %(message)s' - .. conf_master:: log_granular_levels ``log_granular_levels`` @@ -3955,6 +3968,9 @@ Default: ``{}`` This can be used to control logging levels more specifically. See also :conf_log:`log_granular_levels`. + +.. _node-groups: + Node Groups =========== @@ -3972,13 +3988,15 @@ A group consists of a group name and a compound target. group2: 'G@os:Debian and foo.domain.com' group3: 'G@os:Debian and N@group1' group4: - - 'G@foo:bar' - - 'or' - - 'G@foo:baz' + - 'G@foo:bar' + - 'or' + - 'G@foo:baz' More information on using nodegroups can be found :ref:`here `. +.. _range-cluster-settings: + Range Cluster Settings ====================== @@ -3994,9 +4012,11 @@ https://github.com/ytoolshed/range/wiki/%22yamlfile%22-module-file-spec .. code-block:: yaml - range_server: range:80 + range_server: range:80 +.. _include-configuration: + Include Configuration ===================== @@ -4018,7 +4038,6 @@ file. files are prefixed with an underscore. A common example of this is the ``_schedule.conf`` file. - .. conf_master:: include ``include`` @@ -4048,6 +4067,7 @@ option then the master will log a warning message. - master.d/* - /etc/roles/webserver + .. _winrepo-master-config-opts: Windows Software Repo Settings @@ -4368,3 +4388,82 @@ configured both globally and for individual remotes. - '+refs/tags/*:refs/tags/*' - '+refs/pull/*/head:refs/remotes/origin/pr/*' - '+refs/pull/*/merge:refs/remotes/origin/merge/*' + + +.. _configure-master-on-windows: + +Configure Master on Windows +=========================== + +The master on Windows requires no additional configuration. You can modify the +master configuration by creating/editing the master config file located at +``c:\salt\conf\master``. The same configuration options available on Linux are +available in Windows, as long as they apply. For example, SSH options wouldn't +apply in Windows. The main differences are the file paths. If you are familiar +with common salt paths, the following table may be useful: + +============= ========= ================= +linux Paths Windows Paths +============= ========= ================= +``/etc/salt`` ``<--->`` ``c:\salt\conf`` +``/`` ``<--->`` ``c:\salt`` +============= ========= ================= + +So, for example, the master config file in Linux is ``/etc/salt/master``. In +Windows the master config file is ``c:\salt\conf\master``. The Linux path +``/etc/salt`` becomes ``c:\salt\conf`` in Windows. + +Common File Locations +--------------------- + +====================================== ============================================= +Linux Paths Windows Paths +====================================== ============================================= +``conf_file: /etc/salt/master`` ``conf_file: c:\salt\conf\master`` +``log_file: /var/log/salt/master`` ``log_file: c:\salt\var\log\salt\master`` +``pidfile: /var/run/salt-master.pid`` ``pidfile: c:\salt\var\run\salt-master.pid`` +====================================== ============================================= + +Common Directories +------------------ + +====================================================== ============================================ +Linux Paths Windows Paths +====================================================== ============================================ +``cachedir: /var/cache/salt/master`` ``cachedir: c:\salt\var\cache\salt\master`` +``extension_modules: /var/cache/salt/master/extmods`` ``c:\salt\var\cache\salt\master\extmods`` +``pki_dir: /etc/salt/pki/master`` ``pki_dir: c:\salt\conf\pki\master`` +``root_dir: /`` ``root_dir: c:\salt`` +``sock_dir: /var/run/salt/master`` ``sock_dir: c:\salt\var\run\salt\master`` +====================================================== ============================================ + +Roots +----- + +**file_roots** + +================== ========================= +Linux Paths Windows Paths +================== ========================= +``/srv/salt`` ``c:\salt\srv\salt`` +``/srv/spm/salt`` ``c:\salt\srv\spm\salt`` +================== ========================= + +**pillar_roots** + +==================== =========================== +Linux Paths Windows Paths +==================== =========================== +``/srv/pillar`` ``c:\salt\srv\pillar`` +``/srv/spm/pillar`` ``c:\salt\srv\spm\pillar`` +==================== =========================== + +Win Repo Settings +----------------- + +========================================== ================================================= +Linux Paths Windows Paths +========================================== ================================================= +``winrepo_dir: /srv/salt/win/repo`` ``winrepo_dir: c:\salt\srv\salt\win\repo`` +``winrepo_dir_ng: /srv/salt/win/repo-ng`` ``winrepo_dir_ng: c:\salt\srv\salt\win\repo-ng`` +========================================== ================================================= From b6cc0b6bf0971a68df7b881f48f875dc71dbca1d Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 15 Jun 2017 08:53:25 -0600 Subject: [PATCH 44/76] Manually backport the changes in PR #41615 The automatic back-porting process did't work for this file since the testing file has been renamed. I manually added the changes to `timezone_test.py` that were present in PR #41615. --- tests/unit/modules/timezone_test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/modules/timezone_test.py b/tests/unit/modules/timezone_test.py index ebf28e28ee..b295348fca 100644 --- a/tests/unit/modules/timezone_test.py +++ b/tests/unit/modules/timezone_test.py @@ -5,6 +5,7 @@ # Import Python Libs from __future__ import absolute_import +import os # Import Salt Testing Libs from salttesting import TestCase, skipIf @@ -260,8 +261,11 @@ class TimezoneTestCase(TestCase): :return: ''' # Incomplete + hwclock = 'localtime' + if not os.path.isfile('/etc/environment'): + hwclock = 'UTC' timezone.__grains__['os_family'] = ['AIX'] - assert timezone.get_hwclock() == 'localtime' + assert timezone.get_hwclock() == hwclock @patch('salt.utils.which', MagicMock(return_value=False)) @patch('os.path.exists', MagicMock(return_value=True)) From c3dc38587e3ea0569bcdbd1e47c81ccc285bfd60 Mon Sep 17 00:00:00 2001 From: twangboy Date: Thu, 15 Jun 2017 09:49:13 -0600 Subject: [PATCH 45/76] Fix indentation --- doc/ref/configuration/master.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ref/configuration/master.rst b/doc/ref/configuration/master.rst index 82bb3267e7..2b417fdc11 100644 --- a/doc/ref/configuration/master.rst +++ b/doc/ref/configuration/master.rst @@ -3988,9 +3988,9 @@ A group consists of a group name and a compound target. group2: 'G@os:Debian and foo.domain.com' group3: 'G@os:Debian and N@group1' group4: - - 'G@foo:bar' - - 'or' - - 'G@foo:baz' + - 'G@foo:bar' + - 'or' + - 'G@foo:baz' More information on using nodegroups can be found :ref:`here `. From b6201bac33c8272ff559a614aa6d53234e59f4d4 Mon Sep 17 00:00:00 2001 From: twangboy Date: Thu, 15 Jun 2017 09:53:57 -0600 Subject: [PATCH 46/76] Fix version numbers --- doc/topics/installation/windows.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/topics/installation/windows.rst b/doc/topics/installation/windows.rst index e4adc4ed66..06219e73e6 100644 --- a/doc/topics/installation/windows.rst +++ b/doc/topics/installation/windows.rst @@ -118,14 +118,14 @@ Here are some examples of using the silent installer: # Install the Salt Minion # Configure the minion and start the service - Salt-Minion-2017.5.1-Py2-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname + Salt-Minion-2017.7.1-Py2-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname .. code-block:: bat # Install the Salt Minion # Configure the minion but don't start the minion service - Salt-Minion-2017.5.1-Py3-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname /start-minion=0 + Salt-Minion-2017.7.1-Py3-AMD64-Setup.exe /S /master=yoursaltmaster /minion-name=yourminionname /start-minion=0 Running the Salt Minion on Windows as an Unprivileged User @@ -282,7 +282,7 @@ Go into the ``salt`` directory and checkout the version of salt to work with .. code-block:: bat cd salt - git checkout 2017.5.2 + git checkout 2017.7.2 2. Setup the Python Environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,7 +334,7 @@ with ``pip`` updated path .. note:: - if ``pip`` is still not recognized make sure that the Python Scripts folder + If ``pip`` is still not recognized make sure that the Python Scripts folder is in the System ``%PATH%``. (``C:\Python2\Scripts``) 4. Setup Salt Configuration @@ -384,12 +384,12 @@ Navigate to the root ``salt`` directory and install Salt. ------------------------------- Navigate to the ``pkg\windows`` directory and run the ``build_pkg.bat`` -with the build version (2017.5.2) and the Python version as parameters. +with the build version (2017.7.2) and the Python version as parameters. .. code-block:: bat cd pkg\windows - build_pkg.bat 2017.5.2 2 + build_pkg.bat 2017.7.2 2 ^^^^^^^^ ^ | | # build version -- | @@ -420,7 +420,7 @@ build. .. code-block:: bat cd salt - git checkout 2017.5.2 + git checkout 2017.7.2 Then navigate to ``pkg\windows`` and run the ``build.bat`` script with the version you're building. @@ -428,7 +428,7 @@ version you're building. .. code-block:: bat cd pkg\windows - build.bat 2017.5.2 3 + build.bat 2017.7.2 3 ^^^^^^^^ ^ | | # build version | From 87ff0eb3adade8c5016abbe550bbfc1a3fc6828e Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Thu, 15 Jun 2017 13:39:17 -0700 Subject: [PATCH 47/76] Adding the force option for situation where the -yes argument needs to be passed along to lvcreate --- salt/modules/linux_lvm.py | 4 ++++ salt/states/lvm.py | 8 ++++++++ tests/unit/modules/test_linux_lvm.py | 15 +++++++++++++++ tests/unit/states/test_lvm.py | 22 ++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py index 0199444c51..be77285e25 100644 --- a/salt/modules/linux_lvm.py +++ b/salt/modules/linux_lvm.py @@ -354,6 +354,7 @@ def lvcreate(lvname, pv=None, thinvolume=False, thinpool=False, + force=False, **kwargs): ''' Create a new logical volume, with option for which physical volume to be used @@ -428,6 +429,9 @@ def lvcreate(lvname, if extra_arguments: cmd.extend(extra_arguments) + if force: + cmd.append('-yes') + out = __salt__['cmd.run'](cmd, python_shell=False).splitlines() lvdev = '/dev/{0}/{1}'.format(vgname, lvname) lvdata = lvdisplay(lvdev) diff --git a/salt/states/lvm.py b/salt/states/lvm.py index 73498ae077..d7f0770007 100644 --- a/salt/states/lvm.py +++ b/salt/states/lvm.py @@ -211,6 +211,7 @@ def lv_present(name, pv='', thinvolume=False, thinpool=False, + force=False, **kwargs): ''' Create a new logical volume @@ -244,6 +245,12 @@ def lv_present(name, thinpool Logical volume is a thin pool + + .. versionadded:: Oxygen + + force + Assume yes to all prompts + ''' ret = {'changes': {}, 'comment': '', @@ -276,6 +283,7 @@ def lv_present(name, pv=pv, thinvolume=thinvolume, thinpool=thinpool, + force=force, **kwargs) if __salt__['lvm.lvdisplay'](lvpath): diff --git a/tests/unit/modules/test_linux_lvm.py b/tests/unit/modules/test_linux_lvm.py index 0435db7ed5..fdc8902b47 100644 --- a/tests/unit/modules/test_linux_lvm.py +++ b/tests/unit/modules/test_linux_lvm.py @@ -254,6 +254,21 @@ class LinuxLVMTestCase(TestCase, LoaderModuleMockMixin): self.assertDictEqual(linux_lvm.lvcreate(None, None, None, 1), {'Output from lvcreate': 'A'}) + def test_lvcreate_with_force(self): + ''' + Test create a new logical volume, with option + for which physical volume to be used + ''' + mock = MagicMock(return_value='A\nB') + with patch.dict(linux_lvm.__salt__, {'cmd.run': mock}): + with patch.object(linux_lvm, 'lvdisplay', return_value={}): + self.assertDictEqual(linux_lvm.lvcreate(None, + None, + None, + 1, + force=True), + {'Output from lvcreate': 'A'}) + def test_vgremove(self): ''' Tests to remove an LVM volume group diff --git a/tests/unit/states/test_lvm.py b/tests/unit/states/test_lvm.py index 46d0cc532d..d1a1d26d66 100644 --- a/tests/unit/states/test_lvm.py +++ b/tests/unit/states/test_lvm.py @@ -149,6 +149,28 @@ class LvmTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(lvm.__opts__, {'test': True}): self.assertDictEqual(lvm.lv_present(name), ret) + def test_lv_present_with_force(self): + ''' + Test to create a new logical volume with force=True + ''' + name = '/dev/sda5' + + comt = ('Logical Volume {0} already present'.format(name)) + + ret = {'name': name, + 'changes': {}, + 'result': True, + 'comment': comt} + + mock = MagicMock(side_effect=[True, False]) + with patch.dict(lvm.__salt__, {'lvm.lvdisplay': mock}): + self.assertDictEqual(lvm.lv_present(name, force=True), ret) + + comt = ('Logical Volume {0} is set to be created'.format(name)) + ret.update({'comment': comt, 'result': None}) + with patch.dict(lvm.__opts__, {'test': True}): + self.assertDictEqual(lvm.lv_present(name, force=True), ret) + # 'lv_absent' function tests: 1 def test_lv_absent(self): From 4f7c6d1161013bc037ab2c857aacb039d2ca4125 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Thu, 15 Jun 2017 16:56:10 -0600 Subject: [PATCH 48/76] use our own mock_open test.support.mock.mock_open specifies a side effect so that if you constantly read a mocked open call, it will only iterate through it once, and then after it will appear as if the end of the file has been reached. This is needed for salt.modules.cp.push to be tested correctly. --- tests/support/mock.py | 136 ++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/tests/support/mock.py b/tests/support/mock.py index 27c61bb33e..0e608c9832 100644 --- a/tests/support/mock.py +++ b/tests/support/mock.py @@ -105,82 +105,86 @@ if NO_MOCK is False: NO_MOCK_REASON = 'you need to upgrade your mock version to >= 0.8.0' -if sys.version_info >= (3,): - from mock import mock_open -else: - # backport mock_open from the python 3 unittest.mock library so that we can - # mock read, readline, readlines, and file iteration properly +# backport mock_open from the python 3 unittest.mock library so that we can +# mock read, readline, readlines, and file iteration properly - file_spec = None +file_spec = None - def _iterate_read_data(read_data): - # Helper for mock_open: - # Retrieve lines from read_data via a generator so that separate calls to - # readline, read, and readlines are properly interleaved - data_as_list = ['{0}\n'.format(l) for l in read_data.split('\n')] - if data_as_list[-1] == '\n': - # If the last line ended in a newline, the list comprehension will have an - # extra entry that's just a newline. Remove this. - data_as_list = data_as_list[:-1] - else: - # If there wasn't an extra newline by itself, then the file being - # emulated doesn't have a newline to end the last line remove the - # newline that our naive format() added - data_as_list[-1] = data_as_list[-1][:-1] +def _iterate_read_data(read_data): + # Helper for mock_open: + # Retrieve lines from read_data via a generator so that separate calls to + # readline, read, and readlines are properly interleaved + data_as_list = ['{0}\n'.format(l) for l in read_data.split('\n')] - for line in data_as_list: + if data_as_list[-1] == '\n': + # If the last line ended in a newline, the list comprehension will have an + # extra entry that's just a newline. Remove this. + data_as_list = data_as_list[:-1] + else: + # If there wasn't an extra newline by itself, then the file being + # emulated doesn't have a newline to end the last line remove the + # newline that our naive format() added + data_as_list[-1] = data_as_list[-1][:-1] + + for line in data_as_list: + yield line + + +def mock_open(mock=None, read_data=''): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` methoddline`, and `readlines` of the + file handle to return. This is an empty string by default. + """ + def _readlines_side_effect(*args, **kwargs): + if handle.readlines.return_value is not None: + return handle.readlines.return_value + return list(_data) + + def _read_side_effect(*args, **kwargs): + if handle.read.return_value is not None: + return handle.read.return_value + return ''.join(_data) + + def _readline_side_effect(): + if handle.readline.return_value is not None: + while True: + yield handle.readline.return_value + for line in _data: yield line - def mock_open(mock=None, read_data=''): - """ - A helper function to create a mock to replace the use of `open`. It works - for `open` called directly or used as a context manager. - - The `mock` argument is the mock object to configure. If `None` (the - default) then a `MagicMock` will be created for you, with the API limited - to methods or attributes available on standard file handles. - - `read_data` is a string for the `read` methoddline`, and `readlines` of the - file handle to return. This is an empty string by default. - """ - def _readlines_side_effect(*args, **kwargs): - if handle.readlines.return_value is not None: - return handle.readlines.return_value - return list(_data) - - def _read_side_effect(*args, **kwargs): - if handle.read.return_value is not None: - return handle.read.return_value - return ''.join(_data) - - def _readline_side_effect(): - if handle.readline.return_value is not None: - while True: - yield handle.readline.return_value - for line in _data: - yield line - - global file_spec - if file_spec is None: + global file_spec + if file_spec is None: + if sys.version_info >= (3,): + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + else: file_spec = file # pylint: disable=undefined-variable - if mock is None: - mock = MagicMock(name='open', spec=open) + if mock is None: + mock = MagicMock(name='open', spec=open) - handle = MagicMock(spec=file_spec) - handle.__enter__.return_value = handle + handle = MagicMock(spec=file_spec) + handle.__enter__.return_value = handle - _data = _iterate_read_data(read_data) + _data = _iterate_read_data(read_data) - handle.write.return_value = None - handle.read.return_value = None - handle.readline.return_value = None - handle.readlines.return_value = None + handle.write.return_value = None + handle.read.return_value = None + handle.readline.return_value = None + handle.readlines.return_value = None - handle.read.side_effect = _read_side_effect - handle.readline.side_effect = _readline_side_effect() - handle.readlines.side_effect = _readlines_side_effect + # This is salt specific and not in the upstream mock + handle.read.side_effect = _read_side_effect + handle.readline.side_effect = _readline_side_effect() + handle.readlines.side_effect = _readlines_side_effect - mock.return_value = handle - return mock + mock.return_value = handle + return mock From 05f2c6660478e724ee5892d268bf4bf2e88e97b6 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Thu, 15 Jun 2017 22:43:40 -0600 Subject: [PATCH 49/76] handle bytes strings in mock_open --- tests/support/mock.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/support/mock.py b/tests/support/mock.py index 0e608c9832..40e3d1f999 100644 --- a/tests/support/mock.py +++ b/tests/support/mock.py @@ -14,6 +14,9 @@ from __future__ import absolute_import import sys +# Import salt libs +import salt.ext.six as six + try: if sys.version_info >= (3,): # Python 3 @@ -115,7 +118,10 @@ def _iterate_read_data(read_data): # Helper for mock_open: # Retrieve lines from read_data via a generator so that separate calls to # readline, read, and readlines are properly interleaved - data_as_list = ['{0}\n'.format(l) for l in read_data.split('\n')] + if six.PY3 and isinstance(read_data, six.binary_type): + data_as_list = ['{0}\n'.format(l.decode(__salt_system_encoding__)) for l in read_data.split(six.b('\n'))] + else: + data_as_list = ['{0}\n'.format(l) for l in read_data.split('\n')] if data_as_list[-1] == '\n': # If the last line ended in a newline, the list comprehension will have an @@ -162,7 +168,7 @@ def mock_open(mock=None, read_data=''): global file_spec if file_spec is None: - if sys.version_info >= (3,): + if six.PY3: import _io file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) else: From 8034d2d5db3334c40257a3a52f2b267708e2576c Mon Sep 17 00:00:00 2001 From: Ashish Disawal Date: Fri, 16 Jun 2017 11:38:24 +0530 Subject: [PATCH 50/76] Fix for #41762 https://github.com/saltstack/salt/issues/41762 iptables.build_rule does not give full rule even when full=True is provided Changed as suggested by Daniel Yes, that should be changed to if full is True --- salt/modules/iptables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/iptables.py b/salt/modules/iptables.py index 9940dd275a..c799b69b48 100644 --- a/salt/modules/iptables.py +++ b/salt/modules/iptables.py @@ -501,7 +501,7 @@ def build_rule(table='filter', chain=None, command=None, position='', full=None, rule += after_jump - if full in ['True', 'true']: + if full is True: if not table: return 'Error: Table needs to be specified' if not chain: From 370c9ab0b691123b3c6df207412da75a9db51eca Mon Sep 17 00:00:00 2001 From: Vasili Syrakis Date: Fri, 16 Jun 2017 17:09:05 +1000 Subject: [PATCH 51/76] Converted cpu/ram to size_dict as discussed in #38814 --- salt/cloud/clouds/vmware.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 414c3fa6d0..5b49a74af4 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -989,8 +989,10 @@ def _format_instance_info_select(vm, selection): cpu = vm["config.hardware.numCPU"] if "config.hardware.numCPU" in vm else "N/A" ram = "{0} MB".format(vm["config.hardware.memoryMB"]) if "config.hardware.memoryMB" in vm else "N/A" vm_select_info['size'] = u"cpu: {0}\nram: {1}".format(cpu, ram) - vm_select_info['cpu'] = cpu - vm_select_info['ram'] = ram + vm_select_info['size_dict'] = { + 'cpu': cpu, + 'memory': ram, + } if 'state' in selection: vm_select_info['state'] = str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A" @@ -1178,8 +1180,10 @@ def _format_instance_info(vm): 'id': str(vm['name']), 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), - 'cpu': cpu, - 'ram': ram, + 'size_dict': { + 'cpu': cpu, + 'memory': ram, + }, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': ip_addresses, 'public_ips': [], @@ -1584,8 +1588,10 @@ def list_nodes(kwargs=None, call=None): 'id': vm["name"], 'image': "{0} (Detected)".format(vm["config.guestFullName"]) if "config.guestFullName" in vm else "N/A", 'size': u"cpu: {0}\nram: {1}".format(cpu, ram), - 'cpu': cpu, - 'ram': ram, + 'size_dict': { + 'cpu': cpu, + 'memory': ram, + }, 'state': str(vm["summary.runtime.powerState"]) if "summary.runtime.powerState" in vm else "N/A", 'private_ips': [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [], 'public_ips': [] From 92381d7b6dda23e262a65ce62b36150dc09e13f0 Mon Sep 17 00:00:00 2001 From: Luke Overend Date: Thu, 15 Jun 2017 17:13:57 +0100 Subject: [PATCH 52/76] Update napalm_syslog engine to use auth class We have changed napalm-logs to have a keep alive so when the server restarts the client automatically re-authenticates. This PR changes the salt engine to make use of the new keep alive. napalm-logs PR https://github.com/napalm-automation/napalm-logs/pull/87 --- salt/engines/napalm_syslog.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/salt/engines/napalm_syslog.py b/salt/engines/napalm_syslog.py index 36bb7c891b..6932616176 100644 --- a/salt/engines/napalm_syslog.py +++ b/salt/engines/napalm_syslog.py @@ -312,9 +312,10 @@ def start(transport='zmq', if not certificate: log.critical('Please use a certificate, or disable the security.') return - priv_key, verify_key = napalm_logs.utils.authenticate(certificate, - address=auth_address, - port=auth_port) + auth = napalm_logs.utils.ClientAuth(certificate, + address=auth_address, + port=auth_port) + transport_recv_fun = _get_transport_recv(name=transport, address=address, port=port) @@ -330,7 +331,7 @@ def start(transport='zmq', log.debug('Received from napalm-logs:') log.debug(raw_object) if not disable_security: - dict_object = napalm_logs.utils.decrypt(raw_object, verify_key, priv_key) + dict_object = auth.decrypt(raw_object) else: dict_object = napalm_logs.utils.unserialize(raw_object) try: From a7974fe508ee69854ef9c6576f04ba388528abc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ry=20Plassat?= Date: Fri, 16 Jun 2017 12:48:15 +0200 Subject: [PATCH 53/76] Patched the windows status test --- tests/unit/modules/test_win_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/modules/test_win_service.py b/tests/unit/modules/test_win_service.py index 54c5c465bd..e179d58d2f 100644 --- a/tests/unit/modules/test_win_service.py +++ b/tests/unit/modules/test_win_service.py @@ -184,6 +184,7 @@ class WinServiceTestCase(TestCase, LoaderModuleMockMixin): with patch.dict(win_service.__salt__, {'task.run': mock_true}): self.assertTrue(win_service.execute_salt_restart_task()) + @skipIf(not WINAPI, 'win32serviceutil not available') def test_status(self): ''' Test to return the status for a service From a268c3454216d0cd51fb6426c995c039324acec7 Mon Sep 17 00:00:00 2001 From: Vladimir Pouzanov Date: Fri, 16 Jun 2017 14:06:26 +0100 Subject: [PATCH 54/76] Refactored grains cache loader. - refresh_grains_cache opt will now give a distinct debug message - if the grains fail to load from cache, or if the cache is vaild but is empty, grains will be reloaded - dramatically reduced nesting by extracting loader to dedicated function and inverting the condition clauses. --- salt/loader.py | 64 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/salt/loader.py b/salt/loader.py index ecf7634f08..366c16affb 100644 --- a/salt/loader.py +++ b/salt/loader.py @@ -590,6 +590,43 @@ def grain_funcs(opts, proxy=None): ) +def _load_cached_grains(opts, cfn): + ''' + Returns the grains cached in cfn, or None if the cache is too old or is + corrupted. + ''' + if not os.path.isfile(cfn): + log.debug('Grains cache file does not exist.') + return None + + grains_cache_age = int(time.time() - os.path.getmtime(cfn)) + if grains_cache_age > opts.get('grains_cache_expiration', 300): + log.debug('Grains cache last modified {0} seconds ago and ' + 'cache expiration is set to {1}. ' + 'Grains cache expired. Refreshing.'.format( + grains_cache_age, + opts.get('grains_cache_expiration', 300) + )) + return None + + if opts.get('refresh_grains_cache', False): + log.debug('refresh_grains_cache requested, Refreshing.') + return None + + log.debug('Retrieving grains from cache') + try: + serial = salt.payload.Serial(opts) + with salt.utils.fopen(cfn, 'rb') as fp_: + cached_grains = serial.load(fp_) + if not cached_grains: + log.debug('Cached grains are empty, cache might be corrupted. Refreshing.') + return None + + return cached_grains + except (IOError, OSError): + return None + + def grains(opts, force_refresh=False, proxy=None): ''' Return the functions for the dynamic grains and the values for the static @@ -616,29 +653,10 @@ def grains(opts, force_refresh=False, proxy=None): opts['cachedir'], 'grains.cache.p' ) - if not force_refresh: - if opts.get('grains_cache', False): - if os.path.isfile(cfn): - grains_cache_age = int(time.time() - os.path.getmtime(cfn)) - if opts.get('grains_cache_expiration', 300) >= grains_cache_age and not \ - opts.get('refresh_grains_cache', False) and not force_refresh: - log.debug('Retrieving grains from cache') - try: - serial = salt.payload.Serial(opts) - with salt.utils.fopen(cfn, 'rb') as fp_: - cached_grains = serial.load(fp_) - return cached_grains - except (IOError, OSError): - pass - else: - log.debug('Grains cache last modified {0} seconds ago and ' - 'cache expiration is set to {1}. ' - 'Grains cache expired. Refreshing.'.format( - grains_cache_age, - opts.get('grains_cache_expiration', 300) - )) - else: - log.debug('Grains cache file does not exist.') + if not force_refresh and opts.get('grains_cache', False): + cached_grains = _load_cached_grains(opts, cfn) + if cached_grains: + return cached_grains else: log.debug('Grains refresh requested. Refreshing grains.') From b65edc786c77dd6689a5e5cd3c7b5aad6fc54055 Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Fri, 16 Jun 2017 08:40:40 -0600 Subject: [PATCH 55/76] handle unordered sets in unique jinja tests --- tests/unit/templates/test_jinja.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unit/templates/test_jinja.py b/tests/unit/templates/test_jinja.py index b4378a37c0..127f915ae9 100644 --- a/tests/unit/templates/test_jinja.py +++ b/tests/unit/templates/test_jinja.py @@ -484,22 +484,22 @@ class TestCustomExtensions(TestCase): dataset = 'foo' unique = set(dataset) env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) - self.assertEqual(rendered, u"{0}".format(unique)) + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") + self.assertEqual(rendered, list(unique)) def test_unique_tuple(self): dataset = ('foo', 'foo', 'bar') unique = set(dataset) env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) - self.assertEqual(rendered, u"{0}".format(unique)) + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") + self.assertEqual(rendered, list(unique)) def test_unique_list(self): dataset = ['foo', 'foo', 'bar'] unique = ['foo', 'bar'] env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) - self.assertEqual(rendered, u"{0}".format(unique)) + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'[]").split("', '") + self.assertEqual(rendered, unique) def test_serialize_json(self): dataset = { From 83dcffb4b3c2be6b6fa755b41d78d71cae766987 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 16 Jun 2017 10:02:31 -0500 Subject: [PATCH 56/76] Don't take hostname from name param when creating docker container Resolves #41781. --- salt/modules/dockermod.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py index 5e665c8c09..55840114e0 100644 --- a/salt/modules/dockermod.py +++ b/salt/modules/dockermod.py @@ -2481,9 +2481,6 @@ def create(image, except Exception: pull(image, client_timeout=client_timeout) - if name is not None and kwargs.get('hostname') is None: - kwargs['hostname'] = name - kwargs, unused_kwargs = _get_create_kwargs( image=image, skip_translate=skip_translate, From a8affc6ce6ff6dbf4471b5d46c8b5039675800d0 Mon Sep 17 00:00:00 2001 From: Ed Pelc Date: Fri, 16 Jun 2017 12:40:22 -0400 Subject: [PATCH 57/76] fix(docker): allow log_driver or log_opt Docker allows either option without the other and the docks make no mention of both options being required. --- salt/utils/docker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/docker/__init__.py b/salt/utils/docker/__init__.py index 24f72b9f69..e186d639d7 100644 --- a/salt/utils/docker/__init__.py +++ b/salt/utils/docker/__init__.py @@ -225,7 +225,7 @@ def translate_input(**kwargs): # format {'Type': log_driver, 'Config': log_opt}. So, we need to # construct this argument to be passed to the API from those two # arguments. - if log_driver is not NOTSET and log_opt is not NOTSET: + if log_driver is not NOTSET or log_opt is not NOTSET: kwargs['log_config'] = { 'Type': log_driver if log_driver is not NOTSET else 'none', 'Config': log_opt if log_opt is not NOTSET else {} From e8d43a42d14788dd07b09a94846691a9f310015c Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 16 Jun 2017 11:39:33 -0500 Subject: [PATCH 58/76] Rename ext_nodes to master_tops in codebase ext_nodes was replaced in favor of the master_tops system a few years ago, this changes references in the codebase to refer to master_tops to make the code more maintainable in the future. --- salt/client/ssh/state.py | 2 +- salt/daemons/masterapi.py | 5 ++--- salt/fileclient.py | 9 ++++----- salt/fileserver/__init__.py | 2 +- salt/master.py | 4 ++-- salt/state.py | 11 +++++------ 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/salt/client/ssh/state.py b/salt/client/ssh/state.py index 9dcf97bc67..8ab3ee49c0 100644 --- a/salt/client/ssh/state.py +++ b/salt/client/ssh/state.py @@ -78,7 +78,7 @@ class SSHHighState(salt.state.BaseHighState): ''' return - def _ext_nodes(self): + def _master_tops(self): ''' Evaluate master_tops locally ''' diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index db0bac5802..5218cd3cc1 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -536,10 +536,9 @@ class RemoteFuncs(object): mopts['jinja_trim_blocks'] = self.opts['jinja_trim_blocks'] return mopts - def _ext_nodes(self, load, skip_verify=False): + def _master_tops(self, load, skip_verify=False): ''' - Return the results from an external node classifier if one is - specified + Return the results from master_tops if configured ''' if not skip_verify: if 'id' not in load: diff --git a/salt/fileclient.py b/salt/fileclient.py index a3faa10cc1..33a16b5694 100644 --- a/salt/fileclient.py +++ b/salt/fileclient.py @@ -988,7 +988,7 @@ class LocalClient(Client): ret.append(saltenv) return ret - def ext_nodes(self): + def master_tops(self): ''' Originally returned information via the external_nodes subsystem. External_nodes was deprecated and removed in @@ -1306,12 +1306,11 @@ class RemoteClient(Client): load = {'cmd': '_master_opts'} return self.channel.send(load) - def ext_nodes(self): + def master_tops(self): ''' - Return the metadata derived from the external nodes system on the - master. + Return the metadata derived from the master_tops system ''' - load = {'cmd': '_ext_nodes', + load = {'cmd': '_master_tops', 'id': self.opts['id'], 'opts': self.opts} if self.auth: diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py index 1496e2898e..e0b3dac091 100644 --- a/salt/fileserver/__init__.py +++ b/salt/fileserver/__init__.py @@ -876,7 +876,7 @@ class FSChan(object): self.opts['__fs_update'] = True else: self.fs.update() - self.cmd_stub = {'ext_nodes': {}} + self.cmd_stub = {'master_tops': {}} def send(self, load, tries=None, timeout=None, raw=False): # pylint: disable=unused-argument ''' diff --git a/salt/master.py b/salt/master.py index 627f4b8105..70f888eb1a 100644 --- a/salt/master.py +++ b/salt/master.py @@ -1113,7 +1113,7 @@ class AESFuncs(object): load.pop('tok') return load - def _ext_nodes(self, load): + def _master_tops(self, load): ''' Return the results from an external node classifier if one is specified @@ -1124,7 +1124,7 @@ class AESFuncs(object): load = self.__verify_load(load, ('id', 'tok')) if load is False: return {} - return self.masterapi._ext_nodes(load, skip_verify=True) + return self.masterapi._master_tops(load, skip_verify=True) def _master_opts(self, load): ''' diff --git a/salt/state.py b/salt/state.py index 39097819fe..0bd85e6db4 100644 --- a/salt/state.py +++ b/salt/state.py @@ -3118,7 +3118,7 @@ class BaseHighState(object): matches[env_key] = [] matches[env_key].append(inc_sls) _filter_matches(match, data, self.opts['nodegroups']) - ext_matches = self._ext_nodes() + ext_matches = self._master_tops() for saltenv in ext_matches: if saltenv in matches: matches[saltenv] = list( @@ -3128,13 +3128,12 @@ class BaseHighState(object): # pylint: enable=cell-var-from-loop return matches - def _ext_nodes(self): + def _master_tops(self): ''' - Get results from an external node classifier. - Override it if the execution of the external node clasifier - needs customization. + Get results from the master_tops system. Override this function if the + execution of the master_tops needs customization. ''' - return self.client.ext_nodes() + return self.client.master_tops() def load_dynamic(self, matches): ''' From 7480bab7985c4455d703fa5b928f5135dc833275 Mon Sep 17 00:00:00 2001 From: Ed Pelc Date: Fri, 16 Jun 2017 12:58:20 -0400 Subject: [PATCH 59/76] add tests for single docker log_config option fix --- tests/unit/utils/test_docker.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit/utils/test_docker.py b/tests/unit/utils/test_docker.py index 8f4c774d74..5b0587f18c 100644 --- a/tests/unit/utils/test_docker.py +++ b/tests/unit/utils/test_docker.py @@ -984,6 +984,28 @@ class TranslateInputTestCase(TestCase): expected ) + # Ensure passing either `log_driver` or `log_opt` works + self.assertEqual( + docker_utils.translate_input( + log_driver='foo' + ), + ( + {'log_config': {'Type': 'foo', + 'Config': {}}}, + {}, [] + ) + ) + self.assertEqual( + docker_utils.translate_input( + log_opt={'foo': 'bar', 'baz': 'qux'} + ), + ( + {'log_config': {'Type': 'none', + 'Config': {'foo': 'bar', 'baz': 'qux'}}}, + {}, [] + ) + ) + @assert_key_equals_value def test_lxc_conf(self): ''' From 760c4758a9bda198d4a7b471a1a222ecf069dd78 Mon Sep 17 00:00:00 2001 From: "C. R. Oldham" Date: Fri, 16 Jun 2017 11:50:21 -0600 Subject: [PATCH 60/76] Sometimes what gmtime returns looks like a float or other #. Cast to str. --- salt/crypt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/crypt.py b/salt/crypt.py index 45c0c6c204..9629c08d01 100644 --- a/salt/crypt.py +++ b/salt/crypt.py @@ -166,7 +166,7 @@ def _get_rsa_key(path): retrieve the key from disk. ''' log.debug('salt.crypt._get_rsa_key: Loading private key') - return _get_key_with_evict(path, os.path.getmtime(path)) + return _get_key_with_evict(path, str(os.path.getmtime(path))) def sign_message(privkey_path, message): From 4bf030ff65cdfe6a24005cbf5b5ea0a3602a8f6d Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Fri, 16 Jun 2017 13:11:51 -0600 Subject: [PATCH 61/76] don't break py2 --- tests/unit/templates/test_jinja.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/unit/templates/test_jinja.py b/tests/unit/templates/test_jinja.py index 127f915ae9..2fc91c455d 100644 --- a/tests/unit/templates/test_jinja.py +++ b/tests/unit/templates/test_jinja.py @@ -484,22 +484,34 @@ class TestCustomExtensions(TestCase): dataset = 'foo' unique = set(dataset) env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") - self.assertEqual(rendered, list(unique)) + if six.PY3: + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") + self.assertEqual(rendered, list(unique)) + else: + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) + self.assertEqual(rendered, u"{0}".format(unique)) def test_unique_tuple(self): dataset = ('foo', 'foo', 'bar') unique = set(dataset) env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") - self.assertEqual(rendered, list(unique)) + if six.PY3: + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") + self.assertEqual(rendered, list(unique)) + else: + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) + self.assertEqual(rendered, u"{0}".format(unique)) def test_unique_list(self): dataset = ['foo', 'foo', 'bar'] unique = ['foo', 'bar'] env = Environment(extensions=[SerializerExtension]) - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'[]").split("', '") - self.assertEqual(rendered, unique) + if six.PY3: + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'[]").split("', '") + self.assertEqual(rendered, unique) + else + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) + self.assertEqual(rendered, u"{0}".format(unique)) def test_serialize_json(self): dataset = { From c90137cf1fac9ba3e80610bb438f96da04ed8f78 Mon Sep 17 00:00:00 2001 From: Ed Pelc Date: Fri, 16 Jun 2017 12:40:22 -0400 Subject: [PATCH 62/76] fix(docker): allow log_driver or log_opt Docker allows either option without the other and the docks make no mention of both options being required. --- salt/utils/docker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/docker/__init__.py b/salt/utils/docker/__init__.py index 24f72b9f69..e186d639d7 100644 --- a/salt/utils/docker/__init__.py +++ b/salt/utils/docker/__init__.py @@ -225,7 +225,7 @@ def translate_input(**kwargs): # format {'Type': log_driver, 'Config': log_opt}. So, we need to # construct this argument to be passed to the API from those two # arguments. - if log_driver is not NOTSET and log_opt is not NOTSET: + if log_driver is not NOTSET or log_opt is not NOTSET: kwargs['log_config'] = { 'Type': log_driver if log_driver is not NOTSET else 'none', 'Config': log_opt if log_opt is not NOTSET else {} From a536111b8356c4e2d200829344166060ee5bbe5e Mon Sep 17 00:00:00 2001 From: Ed Pelc Date: Fri, 16 Jun 2017 12:58:20 -0400 Subject: [PATCH 63/76] add tests for single docker log_config option fix --- tests/unit/utils/test_docker.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit/utils/test_docker.py b/tests/unit/utils/test_docker.py index 8f4c774d74..5b0587f18c 100644 --- a/tests/unit/utils/test_docker.py +++ b/tests/unit/utils/test_docker.py @@ -984,6 +984,28 @@ class TranslateInputTestCase(TestCase): expected ) + # Ensure passing either `log_driver` or `log_opt` works + self.assertEqual( + docker_utils.translate_input( + log_driver='foo' + ), + ( + {'log_config': {'Type': 'foo', + 'Config': {}}}, + {}, [] + ) + ) + self.assertEqual( + docker_utils.translate_input( + log_opt={'foo': 'bar', 'baz': 'qux'} + ), + ( + {'log_config': {'Type': 'none', + 'Config': {'foo': 'bar', 'baz': 'qux'}}}, + {}, [] + ) + ) + @assert_key_equals_value def test_lxc_conf(self): ''' From ff277bc45807379eb0606cc7560be5fe2feace56 Mon Sep 17 00:00:00 2001 From: rallytime Date: Fri, 16 Jun 2017 21:17:33 +0000 Subject: [PATCH 64/76] Add new documenation file references to build system for 2017.7 --- doc/ref/modules/all/index.rst | 2 ++ doc/ref/modules/all/salt.modules.dummyproxy_package.rst | 6 ++++++ doc/ref/modules/all/salt.modules.dummyproxy_service.rst | 6 ++++++ doc/ref/pillar/all/index.rst | 1 + doc/ref/pillar/all/salt.pillar.digicert.rst | 6 ++++++ doc/ref/proxy/all/index.rst | 1 + doc/ref/proxy/all/salt.proxy.dummy.rst | 6 ++++++ doc/ref/runners/all/index.rst | 1 + doc/ref/runners/all/salt.runners.digicertapi.rst | 6 ++++++ 9 files changed, 35 insertions(+) create mode 100644 doc/ref/modules/all/salt.modules.dummyproxy_package.rst create mode 100644 doc/ref/modules/all/salt.modules.dummyproxy_service.rst create mode 100644 doc/ref/pillar/all/salt.pillar.digicert.rst create mode 100644 doc/ref/proxy/all/salt.proxy.dummy.rst create mode 100644 doc/ref/runners/all/salt.runners.digicertapi.rst diff --git a/doc/ref/modules/all/index.rst b/doc/ref/modules/all/index.rst index 59d43b3d7c..e0b0198791 100644 --- a/doc/ref/modules/all/index.rst +++ b/doc/ref/modules/all/index.rst @@ -117,6 +117,8 @@ execution modules drac dracr drbd + dummyproxy_package + dummyproxy_service ebuild eix elasticsearch diff --git a/doc/ref/modules/all/salt.modules.dummyproxy_package.rst b/doc/ref/modules/all/salt.modules.dummyproxy_package.rst new file mode 100644 index 0000000000..a82b3b2e08 --- /dev/null +++ b/doc/ref/modules/all/salt.modules.dummyproxy_package.rst @@ -0,0 +1,6 @@ +salt.modules.dummyproxy_package module +====================================== + +.. automodule:: salt.modules.dummyproxy_package + :members: + :undoc-members: diff --git a/doc/ref/modules/all/salt.modules.dummyproxy_service.rst b/doc/ref/modules/all/salt.modules.dummyproxy_service.rst new file mode 100644 index 0000000000..83a6f6a214 --- /dev/null +++ b/doc/ref/modules/all/salt.modules.dummyproxy_service.rst @@ -0,0 +1,6 @@ +salt.modules.dummyproxy_service module +====================================== + +.. automodule:: salt.modules.dummyproxy_service + :members: + :undoc-members: diff --git a/doc/ref/pillar/all/index.rst b/doc/ref/pillar/all/index.rst index b0d400593e..4e580befd5 100644 --- a/doc/ref/pillar/all/index.rst +++ b/doc/ref/pillar/all/index.rst @@ -17,6 +17,7 @@ pillar modules confidant consul_pillar csvpillar + digicert django_orm ec2_pillar etcd_pillar diff --git a/doc/ref/pillar/all/salt.pillar.digicert.rst b/doc/ref/pillar/all/salt.pillar.digicert.rst new file mode 100644 index 0000000000..ebb0cafa5d --- /dev/null +++ b/doc/ref/pillar/all/salt.pillar.digicert.rst @@ -0,0 +1,6 @@ +salt.pillar.digicert module +=========================== + +.. automodule:: salt.pillar.digicert + :members: + :undoc-members: diff --git a/doc/ref/proxy/all/index.rst b/doc/ref/proxy/all/index.rst index 0e594ac158..2f3287814b 100644 --- a/doc/ref/proxy/all/index.rst +++ b/doc/ref/proxy/all/index.rst @@ -12,6 +12,7 @@ proxy modules chronos cisconso + dummy esxi fx2 junos diff --git a/doc/ref/proxy/all/salt.proxy.dummy.rst b/doc/ref/proxy/all/salt.proxy.dummy.rst new file mode 100644 index 0000000000..49073048ee --- /dev/null +++ b/doc/ref/proxy/all/salt.proxy.dummy.rst @@ -0,0 +1,6 @@ +salt.proxy.dummy module +======================= + +.. automodule:: salt.proxy.dummy + :members: + :undoc-members: diff --git a/doc/ref/runners/all/index.rst b/doc/ref/runners/all/index.rst index 89da21ca00..a6d79e4988 100644 --- a/doc/ref/runners/all/index.rst +++ b/doc/ref/runners/all/index.rst @@ -16,6 +16,7 @@ runner modules cache cloud ddns + digicertapi doc drac error diff --git a/doc/ref/runners/all/salt.runners.digicertapi.rst b/doc/ref/runners/all/salt.runners.digicertapi.rst new file mode 100644 index 0000000000..10919c8a91 --- /dev/null +++ b/doc/ref/runners/all/salt.runners.digicertapi.rst @@ -0,0 +1,6 @@ +salt.runners.digicertapi module +=============================== + +.. automodule:: salt.runners.digicertapi + :members: + :undoc-members: From 2b9554303af95eabf54f22b0afbd94fa59de8844 Mon Sep 17 00:00:00 2001 From: Ashish Disawal Date: Sun, 18 Jun 2017 23:48:08 +0530 Subject: [PATCH 65/76] Checking if 'full' is True Changes for the iptables unit tests. --- salt/modules/iptables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/iptables.py b/salt/modules/iptables.py index c799b69b48..2681768f61 100644 --- a/salt/modules/iptables.py +++ b/salt/modules/iptables.py @@ -501,7 +501,7 @@ def build_rule(table='filter', chain=None, command=None, position='', full=None, rule += after_jump - if full is True: + if full: if not table: return 'Error: Table needs to be specified' if not chain: From fd28d3385c55a7a76ee760280525db1b92c5bbed Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Mon, 19 Jun 2017 09:49:45 +0000 Subject: [PATCH 66/76] Adding Jinja cross ref --- doc/_ext/saltdomain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/_ext/saltdomain.py b/doc/_ext/saltdomain.py index bc0dcbb81e..c1f73ddc39 100644 --- a/doc/_ext/saltdomain.py +++ b/doc/_ext/saltdomain.py @@ -309,3 +309,5 @@ def setup(app): indextemplate="pair: %s; conf/proxy") app.add_crossref_type(directivename="conf_log", rolename="conf_log", indextemplate="pair: %s; conf/logging") + app.add_crossref_type(directivename="jinja_ref", rolename="jinja_ref", + indextemplate="pair: %s; jinja filters") From d8dc8a338b1cabf9142c09343a6ad7da9343d613 Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Mon, 19 Jun 2017 09:52:33 +0000 Subject: [PATCH 67/76] Add redis cache reference --- doc/topics/releases/2017.7.0.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/topics/releases/2017.7.0.rst b/doc/topics/releases/2017.7.0.rst index 05967d468d..83f4ba7524 100644 --- a/doc/topics/releases/2017.7.0.rst +++ b/doc/topics/releases/2017.7.0.rst @@ -579,6 +579,11 @@ Beacons - :mod:`salt.beacons.log ` +Cache +----- + +- :mod:`salt.cache.redis_cache ` + Engines ------- From fae959d24be9309fcc4adaeb7e3ad205e1dd6d1d Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Mon, 19 Jun 2017 09:52:54 +0000 Subject: [PATCH 68/76] Remove duplicate mattermost ref --- doc/topics/releases/2017.7.0.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/topics/releases/2017.7.0.rst b/doc/topics/releases/2017.7.0.rst index 83f4ba7524..5f0d1ae2c5 100644 --- a/doc/topics/releases/2017.7.0.rst +++ b/doc/topics/releases/2017.7.0.rst @@ -606,7 +606,6 @@ Execution modules - :mod:`salt.modules.icinga2 ` - :mod:`salt.modules.logmod ` - :mod:`salt.modules.mattermost ` -- :mod:`salt.modules.mattermost ` - :mod:`salt.modules.namecheap_dns ` - :mod:`salt.modules.namecheap_domains ` - :mod:`salt.modules.namecheap_ns ` From 2a4835961c71ccbb8401868aa6cc8e0f5b78571c Mon Sep 17 00:00:00 2001 From: Alexandru Bleotu Date: Thu, 15 Jun 2017 14:46:36 +0100 Subject: [PATCH 69/76] Injected the __proxy__ dunder in remaining state execution functions --- salt/modules/state.py | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/salt/modules/state.py b/salt/modules/state.py index 48802dd49c..a5ae950d2d 100644 --- a/salt/modules/state.py +++ b/salt/modules/state.py @@ -380,7 +380,11 @@ def template(tem, queue=False, **kwargs): conflict = _check_queue(queue, kwargs) if conflict is not None: return conflict - st_ = salt.state.HighState(__opts__, context=__context__) + try: + st_ = salt.state.HighState(__opts__, context=__context__, + proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(__opts__, context=__context__) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 @@ -1172,8 +1176,13 @@ def top(topfn, 'Pillar data must be formatted as a dictionary, unless pillar_enc ' 'is specified.' ) + try: + st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, + context=__context__, proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, + context=__context__) - st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, context=__context__) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 err = ['Pillar failed to render with the following messages:'] @@ -1229,7 +1238,11 @@ def show_highstate(queue=False, **kwargs): 'is specified.' ) - st_ = salt.state.HighState(__opts__, pillar, pillar_enc=pillar_enc) + try: + st_ = salt.state.HighState(__opts__, pillar, pillar_enc=pillar_enc, + proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(__opts__, pillar, pillar_enc=pillar_enc) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 @@ -1259,7 +1272,10 @@ def show_lowstate(queue=False, **kwargs): if conflict is not None: assert False return conflict - st_ = salt.state.HighState(__opts__) + try: + st_ = salt.state.HighState(__opts__, proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(__opts__) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 @@ -1453,7 +1469,10 @@ def show_low_sls(mods, opts['environment'] = saltenv if pillarenv is not None: opts['pillarenv'] = pillarenv - st_ = salt.state.HighState(opts) + try: + st_ = salt.state.HighState(opts, proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(opts) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 @@ -1535,7 +1554,11 @@ def show_sls(mods, saltenv='base', test=None, queue=False, **kwargs): if 'pillarenv' in kwargs: opts['pillarenv'] = kwargs['pillarenv'] - st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc) + try: + st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc, + proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(opts, pillar, pillar_enc=pillar_enc) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 @@ -1585,7 +1608,10 @@ def show_top(queue=False, **kwargs): conflict = _check_queue(queue, kwargs) if conflict is not None: return conflict - st_ = salt.state.HighState(opts) + try: + st_ = salt.state.HighState(opts, proxy=__proxy__) + except NameError: + st_ = salt.state.HighState(opts) if not _check_pillar(kwargs, st_.opts['pillar']): __context__['retcode'] = 5 From ce2dc9af12fb1cfe034d3d51c8a598c9e63ca286 Mon Sep 17 00:00:00 2001 From: Alexandru Bleotu Date: Fri, 16 Jun 2017 17:57:19 +0100 Subject: [PATCH 70/76] Added decorator and registered additional JINJA tests --- salt/utils/decorators/__init__.py | 25 +++++++++++++++++++++++++ salt/utils/templates.py | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py index c9d7abe4d0..4f24184d93 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py @@ -658,3 +658,28 @@ class JinjaFilter(object): jinja_filter = JinjaFilter + + +class JinjaTest(object): + ''' + This decorator is used to specify that a function is to be loaded as a + Jinja test. + ''' + salt_jinja_tests = {} + + def __init__(self, name=None): + ''' + ''' + self.name = name + + def __call__(self, function): + ''' + ''' + name = self.name or function.__name__ + if name not in self.salt_jinja_tests: + log.debug('Marking "{0}" as a jinja test'.format(name)) + self.salt_jinja_tests[name] = function + return function + + +jinja_test = JinjaFilter diff --git a/salt/utils/templates.py b/salt/utils/templates.py index bcec73e2ac..973fecc90c 100644 --- a/salt/utils/templates.py +++ b/salt/utils/templates.py @@ -32,7 +32,7 @@ from salt.exceptions import ( import salt.utils.jinja import salt.utils.network from salt.utils.odict import OrderedDict -from salt.utils.decorators import JinjaFilter +from salt.utils.decorators import JinjaFilter, JinjaTest from salt import __path__ as saltpath log = logging.getLogger(__name__) @@ -327,6 +327,7 @@ def render_jinja_tmpl(tmplstr, context, tmplpath=None): jinja_env = jinja2.Environment(undefined=jinja2.StrictUndefined, **env_args) + jinja_env.tests.update(JinjaTest.salt_jinja_tests) jinja_env.filters.update(JinjaFilter.salt_jinja_filters) # globals From bca81c98a6c738503e3b974187954850e46af29b Mon Sep 17 00:00:00 2001 From: Alexandru Bleotu Date: Fri, 16 Jun 2017 17:58:27 +0100 Subject: [PATCH 71/76] Added match, equal jinja tests - can be used with the selectattr filter --- salt/utils/decorators/__init__.py | 2 +- salt/utils/jinja.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/salt/utils/decorators/__init__.py b/salt/utils/decorators/__init__.py index 4f24184d93..f1638d3dae 100644 --- a/salt/utils/decorators/__init__.py +++ b/salt/utils/decorators/__init__.py @@ -682,4 +682,4 @@ class JinjaTest(object): return function -jinja_test = JinjaFilter +jinja_test = JinjaTest diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py index e8e379c8fc..fa1c59a26e 100644 --- a/salt/utils/jinja.py +++ b/salt/utils/jinja.py @@ -31,7 +31,7 @@ import salt import salt.fileclient import salt.utils import salt.utils.url -from salt.utils.decorators import jinja_filter +from salt.utils.decorators import jinja_filter, jinja_test from salt.utils.odict import OrderedDict log = logging.getLogger(__name__) @@ -182,6 +182,34 @@ class PrintableDict(OrderedDict): return '{' + ', '.join(output) + '}' +# Additional tests +@jinja_test('match') +def test_match(txt, rgx, ignorecase=False, multiline=False): + ''' + Returns true if a sequence of chars matches a pattern. + + Test name: 'match' + ''' + flag = 0 + if ignorecase: + flag |= re.I + if multiline: + flag |= re.M + compiled_rgx = re.compile(rgx, flag) + return True if compiled_rgx.match(txt) else False + + +@jinja_test('equal') +def test_equal(value, other): + ''' + Returns true if two values are equal. + + Test name: 'equal' + ''' + return value == other + + +# Additional filters @jinja_filter('skip') def skip_filter(data): ''' From dba43cba00d4d0005e7feae86f8a654f247c7093 Mon Sep 17 00:00:00 2001 From: Alexandru Bleotu Date: Mon, 19 Jun 2017 15:48:45 +0100 Subject: [PATCH 72/76] Renamed equal test to equalto and fixed the comments --- salt/utils/jinja.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py index fa1c59a26e..37bfb6a3ae 100644 --- a/salt/utils/jinja.py +++ b/salt/utils/jinja.py @@ -185,11 +185,7 @@ class PrintableDict(OrderedDict): # Additional tests @jinja_test('match') def test_match(txt, rgx, ignorecase=False, multiline=False): - ''' - Returns true if a sequence of chars matches a pattern. - - Test name: 'match' - ''' + '''Returns true if a sequence of chars matches a pattern.''' flag = 0 if ignorecase: flag |= re.I @@ -199,13 +195,9 @@ def test_match(txt, rgx, ignorecase=False, multiline=False): return True if compiled_rgx.match(txt) else False -@jinja_test('equal') -def test_equal(value, other): - ''' - Returns true if two values are equal. - - Test name: 'equal' - ''' +@jinja_test('equalto') +def test_equalto(value, other): + '''Returns true if two values are equal.''' return value == other From 445f6035681a89f13c3cd6725168a7d677598643 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 19 Jun 2017 09:37:00 -0600 Subject: [PATCH 73/76] Fix incorrect indentation --- tests/unit/templates/test_jinja.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/templates/test_jinja.py b/tests/unit/templates/test_jinja.py index 2fc91c455d..c231976bbb 100644 --- a/tests/unit/templates/test_jinja.py +++ b/tests/unit/templates/test_jinja.py @@ -499,8 +499,8 @@ class TestCustomExtensions(TestCase): rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'{}").split("', '") self.assertEqual(rendered, list(unique)) else: - rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) - self.assertEqual(rendered, u"{0}".format(unique)) + rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) + self.assertEqual(rendered, u"{0}".format(unique)) def test_unique_list(self): dataset = ['foo', 'foo', 'bar'] From e42d1172a804b455c9252d0dddef15c79f9f6344 Mon Sep 17 00:00:00 2001 From: Alexandru Bleotu Date: Mon, 19 Jun 2017 17:15:23 +0100 Subject: [PATCH 74/76] Added Tests section in JINJA documentation --- doc/topics/jinja/index.rst | 70 +++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/doc/topics/jinja/index.rst b/doc/topics/jinja/index.rst index 5548b29646..e028403a06 100644 --- a/doc/topics/jinja/index.rst +++ b/doc/topics/jinja/index.rst @@ -1475,7 +1475,75 @@ Returns: /usr/local/salt/virtualenv/bin/salt-master -.. jinja_ref:: jinja-in-files + +Tests +===== + +Saltstack extends `builtin tests`_ with these custom tests: + +.. _`builtin tests`: http://jinja.pocoo.org/docs/templates/#builtin-tests + +.. jinja_ref:: equalto + +``equalto`` +----------- + +Tests the equality between two values. + +Can be used in an ``if`` statement directly: + +.. code-block:: jinja + + {% if 1 is equalto(1) %} + < statements > + {% endif %} + +If clause evaluates to ``True`` + +or with the ``selectattr`` filter: + +.. code-block:: jinja + + {{ [{'value': 1}, {'value': 2} , {'value': 3}] | selectattr('value', 'equalto', 3) | list }} + +Returns: + +.. code-block:: python + + [{'value': 3}] + +.. jinja_ref:: match + +``match`` +--------- + +Tests that a string matches the regex passed as an argument. + +Can be used in a ``if`` statement directly: + +.. code-block:: jinja + + {% if 'a' is match('[a-b]') %} + < statements > + {% endif %} + +If clause evaluates to ``True`` + +or with the ``selectattr`` filter: + +.. code-block:: jinja + + {{ [{'value': 'a'}, {'value': 'b'}, {'value': 'c'}] | selectattr('value', 'match', '[b-e]') | list }} + +Returns: + +.. code-block:: python + + [{'value': 'b'}, {'value': 'c'}] + + +Test supports additional optional arguments: ``ignorecase``, ``multiline`` + Jinja in Files ============== From 5bc7a20327b77a097f4793b5ff71bcb343dd17e3 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Mon, 19 Jun 2017 10:52:45 -0600 Subject: [PATCH 75/76] Missing colon --- tests/unit/templates/test_jinja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/templates/test_jinja.py b/tests/unit/templates/test_jinja.py index c231976bbb..471d626540 100644 --- a/tests/unit/templates/test_jinja.py +++ b/tests/unit/templates/test_jinja.py @@ -509,7 +509,7 @@ class TestCustomExtensions(TestCase): if six.PY3: rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset).strip("'[]").split("', '") self.assertEqual(rendered, unique) - else + else: rendered = env.from_string('{{ dataset|unique }}').render(dataset=dataset) self.assertEqual(rendered, u"{0}".format(unique)) From 42989d5a287a2b5729c592d67c59ea75748a8abb Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 19 Jun 2017 17:29:44 -0600 Subject: [PATCH 76/76] Reduce the number of days an issue is stale by 25 This reduces the amount of time an issue is stale to approximately 3 years, 3 months, and some change. --- .github/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index ebb9b9d957..5b1a2c69e3 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,8 +1,8 @@ # Probot Stale configuration file # Number of days of inactivity before an issue becomes stale -# 1225 is approximately 3 years and 4 months -daysUntilStale: 1225 +# 1200 is approximately 3 years and 3 months +daysUntilStale: 1200 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7