From e174c41887ec9c32df1f897665b00a06387c43ea Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Tue, 11 Aug 2015 20:57:09 -0700 Subject: [PATCH 01/70] Fix to trust_key in gpg module for 2015.5. --- salt/modules/gpg.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/salt/modules/gpg.py b/salt/modules/gpg.py index 69cbd34e302..d3040c2de1c 100644 --- a/salt/modules/gpg.py +++ b/salt/modules/gpg.py @@ -24,6 +24,11 @@ import salt.utils import salt.syspaths from salt.ext.six import string_types +try: + from shlex import quote as _cmd_quote # pylint: disable=E0611 +except ImportError: + from pipes import quote as _cmd_quote + from salt.exceptions import ( SaltInvocationError ) @@ -791,15 +796,15 @@ def trust_key(keyid=None, if trust_level not in _VALID_TRUST_LEVELS: return 'ERROR: Valid trust levels - {0}'.format(','.join(_VALID_TRUST_LEVELS)) - cmd = 'echo {0}:{1} | {2} --import-ownertrust'.format(fingerprint, - NUM_TRUST_DICT[trust_level], - _check_gpg()) + cmd = 'echo {0}:{1} | {2} --import-ownertrust'.format(_cmd_quote(fingerprint), + _cmd_quote(NUM_TRUST_DICT[trust_level]), + _cmd_quote(_check_gpg())) _user = user if user == 'salt': homeDir = os.path.join(salt.syspaths.CONFIG_DIR, 'gpgkeys') cmd = '{0} --homedir {1}'.format(cmd, homeDir) _user = 'root' - res = __salt__['cmd.run_all'](cmd, runas=_user) + res = __salt__['cmd.run_all'](cmd, runas=_user, python_shell=True) if not res['retcode'] == 0: ret['res'] = False From ad444b6e7be91a14f44c48b63f1d7d1d195efcf8 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Mon, 3 Aug 2015 10:07:08 +0200 Subject: [PATCH 02/70] cron identifier: default to state id --- salt/states/cron.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/salt/states/cron.py b/salt/states/cron.py index 5c9cdfdb1fd..9ba21bb9557 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -125,8 +125,7 @@ from salt.ext.six import string_types import salt.utils from salt.modules.cron import ( _needs_change, - _cron_matched, - SALT_CRON_NO_IDENTIFIER + _cron_matched ) @@ -258,7 +257,7 @@ def present(name, ''' name = ' '.join(name.strip().split()) if not identifier: - identifier = SALT_CRON_NO_IDENTIFIER + identifier = name ret = {'changes': {}, 'comment': '', 'name': name, @@ -336,7 +335,7 @@ def absent(name, name = ' '.join(name.strip().split()) if not identifier: - identifier = SALT_CRON_NO_IDENTIFIER + identifier = name ret = {'name': name, 'result': True, 'changes': {}, From f22ad837c32eb89daf70ee51f20ec812a582ccb9 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Wed, 12 Aug 2015 09:11:59 +0200 Subject: [PATCH 03/70] cron: change identifier default value to False this allows the user to set it explicitly to None if they want to manage a cronjob with no identifier. realistically, this is probably a rare usecase. --- salt/states/cron.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/states/cron.py b/salt/states/cron.py index 9ba21bb9557..d194673b6cf 100644 --- a/salt/states/cron.py +++ b/salt/states/cron.py @@ -216,7 +216,7 @@ def present(name, month='*', dayweek='*', comment=None, - identifier=None): + identifier=False): ''' Verifies that the specified cron job is present for the specified user. For more advanced information about what exactly can be set in the cron @@ -256,7 +256,7 @@ def present(name, edits. This defaults to the state id ''' name = ' '.join(name.strip().split()) - if not identifier: + if identifier is False: identifier = name ret = {'changes': {}, 'comment': '', @@ -312,7 +312,7 @@ def present(name, def absent(name, user='root', - identifier=None, + identifier=False, **kwargs): ''' Verifies that the specified cron job is absent for the specified user; only @@ -334,7 +334,7 @@ def absent(name, ### of unsupported arguments will result in a traceback. name = ' '.join(name.strip().split()) - if not identifier: + if identifier is False: identifier = name ret = {'name': name, 'result': True, From 9b18cd90509dd8a76e4237a75f0884bd4b8dc094 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Wed, 12 Aug 2015 09:13:06 +0200 Subject: [PATCH 04/70] cron: more descriptive tests, updated to reflect new behavior --- tests/unit/states/cron_test.py | 206 ++++++++------------------------- 1 file changed, 50 insertions(+), 156 deletions(-) diff --git a/tests/unit/states/cron_test.py b/tests/unit/states/cron_test.py index 4aeef3a05b6..97d5f0b1cfb 100644 --- a/tests/unit/states/cron_test.py +++ b/tests/unit/states/cron_test.py @@ -135,7 +135,8 @@ class CronTestCase(TestCase): cron.present( name='foo', hour='2', - user='root') + user='root', + identifier=None) self.assertEqual( get_crontab(), ('# Lines below here are managed by Salt, do not edit\n' @@ -143,7 +144,7 @@ class CronTestCase(TestCase): '* 2 * * * foo\n' '# SALT_CRON_IDENTIFIER:2\n' '* 2 * * * foo\n' - '* 2 * * * foo\n')) + '* 2 * * * foo')) @patch('salt.modules.cron.raw_cron', new=MagicMock(side_effect=get_crontab)) @@ -192,214 +193,107 @@ class CronTestCase(TestCase): new=MagicMock(side_effect=get_crontab)) @patch('salt.modules.cron._write_cron_lines', new=MagicMock(side_effect=write_crontab)) - def test_aissue_1072(self): + def test_multiline_comments_are_updated(self): set_crontab( '# Lines below here are managed by Salt, do not edit\n' - '# I have a multi-line comment SALT_CRON_IDENTIFIER:1\n' + '# First crontab - single line comment SALT_CRON_IDENTIFIER:1\n' '* 1 * * * foo' ) cron.present( name='foo', hour='1', - comment='1I have a multi-line comment\n2about my script here.\n', + comment='First crontab\nfirst multi-line comment\n', identifier='1', user='root') cron.present( name='foo', hour='1', - comment='3I have a multi-line comment\n3about my script here.\n', + comment='First crontab\nsecond multi-line comment\n', + identifier='1', user='root') cron.present( name='foo', hour='1', - comment='I have a multi-line comment\nabout my script here.\n', + comment='Second crontab\nmulti-line-comment\n', identifier='2', user='root') self.assertEqual( get_crontab(), '# Lines below here are managed by Salt, do not edit\n' - '# 2about my script here. SALT_CRON_IDENTIFIER:1\n' + '# First crontab\n' + '# second multi-line comment SALT_CRON_IDENTIFIER:1\n' '* 1 * * * foo\n' - '# I have a multi-line comment\n' - '# about my script here. SALT_CRON_IDENTIFIER:2\n' + '# Second crontab\n' + '# multi-line comment SALT_CRON_IDENTIFIER:2\n' '* 1 * * * foo') @patch('salt.modules.cron.raw_cron', new=MagicMock(side_effect=get_crontab)) @patch('salt.modules.cron._write_cron_lines', new=MagicMock(side_effect=write_crontab)) - def test_issue_11935(self): + def test_existing_unmanaged_jobs_are_made_managed(self): set_crontab( '# Lines below here are managed by Salt, do not edit\n' - '0 2 * * * find /var/www -type f ' - '-mtime -7 -print0 | xargs -0 ' - 'clamscan -i --no-summary 2>/dev/null' + '0 2 * * * foo' ) - cmd = ( - 'find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null' - ) - self.assertEqual(cron._check_cron('root', cmd, hour='2', minute='0'), - 'present') - ret = cron.present(cmd, 'root', minute='0', hour='2') - self.assertEqual(ret['changes'], {}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null already present') - self.assertEqual(cron._check_cron('root', cmd, hour='3', minute='0'), - 'update') - ret = cron.present(cmd, 'root', minute='0', hour='3') - self.assertEqual(ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/null'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null updated') + ret = cron._check_cron('root', 'foo', hour='2', minute='0') + self.assertEqual(ret, 'present') + ret = cron.present('foo', 'root', minute='0', hour='2') + self.assertEqual(ret['changes'], {'root': 'foo'}) + self.assertEqual(ret['comment'], 'Cron foo updated') self.assertEqual( get_crontab(), '# Lines below here are managed by Salt, do not edit\n' - '0 3 * * * find /var/www -type f -mtime -7 -print0 |' - ' xargs -0 clamscan -i --no-summary 2>/dev/null') + '# SALT_CRON_IDENTIFIER:foo\n' + '0 2 * * * foo') + ret = cron.present('foo', 'root', minute='0', hour='2') + self.assertEqual(ret['changes'], {}) + self.assertEqual(ret['comment'], 'Cron foo already present') @patch('salt.modules.cron.raw_cron', new=MagicMock(side_effect=get_crontab)) @patch('salt.modules.cron._write_cron_lines', new=MagicMock(side_effect=write_crontab)) - def test_issue_11935_with_id(self): + def test_existing_noid_jobs_are_updated_with_identifier(self): set_crontab( '# Lines below here are managed by Salt, do not edit\n' - '# SALT_CRON_IDENTIFIER:1\n' - '0 2 * * * find /var/www -type f ' - '-mtime -7 -print0 | xargs -0 ' - 'clamscan -i --no-summary 2>/dev/null' + '# SALT_CRON_IDENTIFIER:NO ID SET\n' + '1 * * * * foo' ) - cmd = ( - 'find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null' - ) - self.assertEqual(cron._check_cron( - 'root', cmd, hour='2', minute='0', identifier=1), 'present') - ret = cron.present(cmd, 'root', minute='0', hour='2', identifier='1') - self.assertEqual(ret['changes'], {}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null already present') - self.assertEqual(cron._check_cron( - 'root', cmd, hour='3', minute='0', identifier='1'), 'update') - ret = cron.present(cmd, 'root', minute='0', hour='3', identifier='1') - self.assertEqual(ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/null'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null updated') + ret = cron._check_cron('root', 'foo', minute=1) + self.assertEqual(ret, 'present') + ret = cron.present('foo', 'root', minute=1) + self.assertEqual(ret['changes'], {'root': 'foo'}) + self.assertEqual(ret['comment'], 'Cron foo updated') self.assertEqual( get_crontab(), '# Lines below here are managed by Salt, do not edit\n' - '# SALT_CRON_IDENTIFIER:1\n' - '0 3 * * * find /var/www -type f -mtime -7 -print0 |' - ' xargs -0 clamscan -i --no-summary 2>/dev/null') + '# SALT_CRON_IDENTIFIER:foo\n' + '1 * * * * foo') @patch('salt.modules.cron.raw_cron', new=MagicMock(side_effect=get_crontab)) @patch('salt.modules.cron._write_cron_lines', new=MagicMock(side_effect=write_crontab)) - def test_issue_11935_mixed(self): + def test_existing_duplicate_unmanaged_jobs_are_merged_and_given_id(self): set_crontab( '# Lines below here are managed by Salt, do not edit\n' - '0 2 * * * find /var/www -type f ' - '-mtime -7 -print0 | xargs -0 ' - 'clamscan -i --no-summary 2>/dev/null' + '0 2 * * * foo\n' + '0 2 * * * foo' ) - cmd = ( - 'find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null' - ) - self.assertEqual(cron._check_cron('root', cmd, hour='2', minute='0'), - 'present') - ret = cron.present(cmd, 'root', minute='0', hour='2') + ret = cron._check_cron('root', 'foo', hour='2', minute='0') + self.assertEqual(ret, 'present') + ret = cron.present('foo', 'root', minute='0', hour='2') + self.assertEqual(ret['changes'], {'root': 'foo'}) + self.assertEqual(ret['comment'], 'Cron foo updated') + self.assertEqual( + get_crontab(), + '# Lines below here are managed by Salt, do not edit\n' + '# SALT_CRON_IDENTIFIER:foo\n' + '0 2 * * * foo') + ret = cron.present('foo', 'root', minute='0', hour='2') self.assertEqual(ret['changes'], {}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null already present') - self.assertEqual(cron._check_cron('root', cmd, hour='3', minute='0'), - 'update') - ret = cron.present(cmd, 'root', minute='0', hour='3') - self.assertEqual(ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/null'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null updated') - self.assertEqual( - get_crontab(), - '# Lines below here are managed by Salt, do not edit\n' - '0 3 * * * find /var/www -type f -mtime -7 -print0 |' - ' xargs -0 clamscan -i --no-summary 2>/dev/null') - self.assertEqual(cron._check_cron( - 'root', cmd, hour='2', minute='0', identifier='1'), 'update') - ret = cron.present(cmd, 'root', minute='0', hour='2', identifier='1') - self.assertEqual( - ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/null'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null updated') - self.assertEqual(cron._check_cron( - 'root', cmd, hour='3', minute='0', identifier='1'), 'update') - ret = cron.present(cmd, 'root', minute='0', hour='3', identifier='1') - self.assertEqual(ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/null'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 ' - '| xargs -0 clamscan -i --no-summary 2>/dev/null updated') - self.assertEqual( - get_crontab(), - '# Lines below here are managed by Salt, do not edit\n' - '# SALT_CRON_IDENTIFIER:1\n' - '0 3 * * * find /var/www -type f -mtime -7 -print0 |' - ' xargs -0 clamscan -i --no-summary 2>/dev/null') - - set_crontab( - '# Lines below here are managed by Salt, do not edit\n' - '0 2 * * * find /var/www -type f ' - '-mtime -7 -print0 | xargs -0 ' - 'clamscan -i --no-summary 2>/dev/null' - ) - self.assertEqual(cron._check_cron( - 'root', cmd + "a", hour='2', minute='0', identifier='1'), 'absent') - ret = cron.present( - cmd + "a", 'root', minute='0', hour='2', identifier='1') - self.assertEqual( - ret['changes'], - {'root': 'find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/nulla'}) - self.assertEqual( - ret['comment'], - 'Cron find /var/www -type f -mtime -7 -print0 | ' - 'xargs -0 clamscan -i --no-summary 2>/dev/nulla added ' - 'to root\'s crontab') - self.assertEqual( - get_crontab(), - '# Lines below here are managed by Salt, do not edit\n' - '0 2 * * *' - ' find /var/www -type f -mtime -7 -print0' - ' | xargs -0 clamscan -i --no-summary 2>/dev/null\n' - '# SALT_CRON_IDENTIFIER:1\n' - '0 2 * * *' - ' find /var/www -type f -mtime -7 -print0' - ' | xargs -0 clamscan -i --no-summary 2>/dev/nulla') - + self.assertEqual(ret['comment'], 'Cron foo already present') if __name__ == '__main__': from integration import run_tests From 9511e392ce5ff93728c9638517777d5d0cb4da1b Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Wed, 12 Aug 2015 09:54:32 +0200 Subject: [PATCH 05/70] cron: read full length of multi-line comments --- salt/modules/cron.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/salt/modules/cron.py b/salt/modules/cron.py index 5f6df0b6653..ada9be96fcc 100644 --- a/salt/modules/cron.py +++ b/salt/modules/cron.py @@ -265,14 +265,20 @@ def list_tab(user): ret['special'].append(dat) elif line.startswith('#'): # It's a comment! Catch it! - comment = line.lstrip('# ') + comment_line = line.lstrip('# ') + # load the identifier if any - if SALT_CRON_IDENTIFIER in comment: - parts = comment.split(SALT_CRON_IDENTIFIER) - comment = parts[0].rstrip() + if SALT_CRON_IDENTIFIER in comment_line: + parts = comment_line.split(SALT_CRON_IDENTIFIER) + comment_line = parts[0].rstrip() # skip leading : if len(parts[1]) > 1: identifier = parts[1][1:] + + if comment is None: + comment = comment_line + else: + comment += '\n' + comment_line elif len(line.split()) > 5: # Appears to be a standard cron line comps = line.split() From a86b1b7f9453f9486d53d18a51088f8c522b86f2 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Wed, 12 Aug 2015 10:02:39 +0200 Subject: [PATCH 06/70] add release note about cron state changes --- doc/topics/releases/2015.5.4.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/topics/releases/2015.5.4.rst b/doc/topics/releases/2015.5.4.rst index 4965356aa23..77f43878d0e 100644 --- a/doc/topics/releases/2015.5.4.rst +++ b/doc/topics/releases/2015.5.4.rst @@ -9,6 +9,8 @@ Version 2015.5.4 is a bugfix release for :doc:`2015.5.0 Changes: +- The ``cron.present`` state now correctly defaults to state ID as identifier. + - When querying for VMs in ``ditigal_ocean_v2.py``, the number of VMs to include in a page was changed from 20 (default) to 200 to reduce the number of API calls to Digital Ocean. From 1f02e1671bd2ee61a358dc1a5efa3cfacc751822 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Wed, 12 Aug 2015 10:08:43 +0200 Subject: [PATCH 07/70] cron: fix a typo in the tests --- tests/unit/states/cron_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/states/cron_test.py b/tests/unit/states/cron_test.py index 97d5f0b1cfb..0217fed77c7 100644 --- a/tests/unit/states/cron_test.py +++ b/tests/unit/states/cron_test.py @@ -214,7 +214,7 @@ class CronTestCase(TestCase): cron.present( name='foo', hour='1', - comment='Second crontab\nmulti-line-comment\n', + comment='Second crontab\nmulti-line comment\n', identifier='2', user='root') self.assertEqual( From fc187517107f42ad0085609aaa5348e716475bee Mon Sep 17 00:00:00 2001 From: Daniel Hobley Date: Wed, 12 Aug 2015 13:57:31 +0200 Subject: [PATCH 08/70] Fixed documentation to match function name --- salt/states/environ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/states/environ.py b/salt/states/environ.py index 0117362cd7b..a950b4263a3 100644 --- a/salt/states/environ.py +++ b/salt/states/environ.py @@ -61,13 +61,13 @@ def setenv(name, .. code-block:: yaml a_string_env: - environ.set: + environ.setenv: - name: foo - value: bar - update_minion: True a_dict_env: - environ.set: + environ.setenv: - name: does_not_matter - value: foo: bar From 5227aa94bc92ed9183fa371ac7810c063f0b246e Mon Sep 17 00:00:00 2001 From: Nitin Madhok Date: Wed, 12 Aug 2015 10:16:35 -0400 Subject: [PATCH 09/70] Backport additions to VMware cloud driver from develop to 2015.5 branch --- salt/cloud/clouds/vmware.py | 106 ++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/salt/cloud/clouds/vmware.py b/salt/cloud/clouds/vmware.py index 1bf254a032a..c3b6e1d19fa 100644 --- a/salt/cloud/clouds/vmware.py +++ b/salt/cloud/clouds/vmware.py @@ -739,11 +739,10 @@ def _manage_devices(devices, vm): return ret -def _wait_for_vmware_tools(vm_ref, max_wait_minute): +def _wait_for_vmware_tools(vm_ref, max_wait): time_counter = 0 starttime = time.time() - max_wait_second = int(max_wait_minute * 60) - while time_counter < max_wait_second: + while time_counter < max_wait: if time_counter % 5 == 0: log.info("[ {0} ] Waiting for VMware tools to be running [{1} s]".format(vm_ref.name, time_counter)) if str(vm_ref.summary.guest.toolsRunningStatus) == "guestToolsRunning": @@ -752,21 +751,20 @@ def _wait_for_vmware_tools(vm_ref, max_wait_minute): time.sleep(1.0 - ((time.time() - starttime) % 1.0)) time_counter += 1 - log.warning("[ {0} ] Timeout Reached. VMware tools still not running after waiting for {1} minutes".format(vm_ref.name, max_wait_minute)) + log.warning("[ {0} ] Timeout Reached. VMware tools still not running after waiting for {1} seconds".format(vm_ref.name, max_wait)) return False -def _wait_for_ip(vm_ref, max_wait_minute): - max_wait_minute_vmware_tools = max_wait_minute - 5 - max_wait_minute_ip = max_wait_minute - max_wait_minute_vmware_tools - vmware_tools_status = _wait_for_vmware_tools(vm_ref, max_wait_minute_vmware_tools) +def _wait_for_ip(vm_ref, max_wait): + max_wait_vmware_tools = max_wait + max_wait_ip = max_wait + vmware_tools_status = _wait_for_vmware_tools(vm_ref, max_wait_vmware_tools) if not vmware_tools_status: return False time_counter = 0 starttime = time.time() - max_wait_second = int(max_wait_minute_ip * 60) - while time_counter < max_wait_second: + while time_counter < max_wait_ip: if time_counter % 5 == 0: log.info("[ {0} ] Waiting to retrieve IPv4 information [{1} s]".format(vm_ref.name, time_counter)) @@ -783,7 +781,7 @@ def _wait_for_ip(vm_ref, max_wait_minute): return current_ip.ipAddress time.sleep(1.0 - ((time.time() - starttime) % 1.0)) time_counter += 1 - log.warning("[ {0} ] Timeout Reached. Unable to retrieve IPv4 information after waiting for {1} minutes".format(vm_ref.name, max_wait_minute_ip)) + log.warning("[ {0} ] Timeout Reached. Unable to retrieve IPv4 information after waiting for {1} seconds".format(vm_ref.name, max_wait_ip)) return False @@ -888,7 +886,7 @@ def _format_instance_info_select(vm, selection): if 'networks' in selection: vm_select_info['networks'] = network_full_info - if 'devices' in selection or 'mac_addresses' in selection: + if 'devices' in selection or 'mac_address' in selection or 'mac_addresses' in selection: device_full_info = {} device_mac_addresses = [] if "config.hardware.device" in vm: @@ -936,7 +934,7 @@ def _format_instance_info_select(vm, selection): if 'devices' in selection: vm_select_info['devices'] = device_full_info - if 'mac_addresses' in selection: + if 'mac_address' in selection or 'mac_addresses' in selection: vm_select_info['mac_addresses'] = device_mac_addresses if 'storage' in selection: @@ -1564,7 +1562,7 @@ def list_nodes_select(call=None): if 'private_ips' in selection or 'networks' in selection: vm_properties.append("guest.net") - if 'devices' in selection or 'mac_addresses' in selection: + if 'devices' in selection or 'mac_address' in selection or 'mac_addresses' in selection: vm_properties.append("config.hardware.device") if 'storage' in selection: @@ -1642,7 +1640,7 @@ def show_instance(name, call=None): return _format_instance_info(vm) -def avail_images(): +def avail_images(call=None): ''' Return a list of all the templates present in this VMware environment with basic details @@ -1653,6 +1651,11 @@ def avail_images(): salt-cloud --list-images my-vmware-config ''' + if call == 'action': + raise SaltCloudSystemExit( + 'The avail_images function must be called with ' + '-f or --function, or with the --list-images option.' + ) templates = {} vm_properties = [ @@ -1677,6 +1680,74 @@ def avail_images(): return templates +def avail_locations(call=None): + ''' + Return a list of all the available locations/datacenters in this VMware environment + + CLI Example: + + .. code-block:: bash + + salt-cloud --list-locations my-vmware-config + ''' + if call == 'action': + raise SaltCloudSystemExit( + 'The avail_locations function must be called with ' + '-f or --function, or with the --list-locations option.' + ) + + return list_datacenters(call='function') + + +def avail_sizes(call=None): + ''' + Return a list of all the available sizes in this VMware environment. + + CLI Example: + + .. code-block:: bash + + salt-cloud --list-sizes my-vmware-config + + .. note:: + + Since sizes are built into templates, this function will return + an empty dictionary. + + ''' + if call == 'action': + raise SaltCloudSystemExit( + 'The avail_sizes function must be called with ' + '-f or --function, or with the --list-sizes option.' + ) + + log.warning( + 'Because sizes are built into templates with VMware, there are no sizes ' + 'to return.' + ) + + return {} + + +def list_templates(kwargs=None, call=None): + ''' + List all the templates present in this VMware environment + + CLI Example: + + .. code-block:: bash + + salt-cloud -f list_templates my-vmware-config + ''' + if call != 'function': + raise SaltCloudSystemExit( + 'The list_templates function must be called with ' + '-f or --function.' + ) + + return {'Templates': avail_images(call='function')} + + def list_folders(kwargs=None, call=None): ''' List all the folders for this VMware environment @@ -2138,6 +2209,9 @@ def create(vm_): deploy = config.get_cloud_config_value( 'deploy', vm_, __opts__, search_global=False, default=True ) + wait_for_ip_timeout = config.get_cloud_config_value( + 'wait_for_ip_timeout', vm_, __opts__, default=20 * 60 + ) domain = config.get_cloud_config_value( 'domain', vm_, __opts__, search_global=False, default='local' ) @@ -2337,7 +2411,7 @@ def create(vm_): # If it a template or if it does not need to be powered on then do not wait for the IP if not template and power: - ip = _wait_for_ip(new_vm_ref, 20) + ip = _wait_for_ip(new_vm_ref, wait_for_ip_timeout) if ip: log.info("[ {0} ] IPv4 is: {1}".format(vm_name, ip)) # ssh or smb using ip and install salt only if deploy is True From a8bfe5ec1fba350d5e7cf19d54aa1e4389471132 Mon Sep 17 00:00:00 2001 From: Nitin Madhok Date: Wed, 12 Aug 2015 10:30:14 -0400 Subject: [PATCH 10/70] Initial commit of unit tests for vmware cloud driver --- tests/unit/cloud/clouds/vmware_test.py | 388 +++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 tests/unit/cloud/clouds/vmware_test.py diff --git a/tests/unit/cloud/clouds/vmware_test.py b/tests/unit/cloud/clouds/vmware_test.py new file mode 100644 index 00000000000..8b607d14882 --- /dev/null +++ b/tests/unit/cloud/clouds/vmware_test.py @@ -0,0 +1,388 @@ +# -*- coding: utf-8 -*- +''' + :codeauthor: `Nitin Madhok ` + + tests.unit.cloud.clouds.vmware_test + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +''' + +# Import Python libs +from __future__ import absolute_import + +# Import Salt Testing Libs +from salttesting import TestCase, skipIf +from salttesting.mock import MagicMock, NO_MOCK, NO_MOCK_REASON, patch +from salttesting.helpers import ensure_in_syspath + +ensure_in_syspath('../../../') + +# Import Salt Libs +from salt.cloud.clouds import vmware +from salt.exceptions import SaltCloudSystemExit, SaltCloudNotFound + +# Global Variables +vmware.__active_provider_name__ = '' +vmware.__opts__ = {} +VM_NAME = 'test-vm' + + +@skipIf(NO_MOCK, NO_MOCK_REASON) +@patch('salt.cloud.clouds.vmware.__virtual__', MagicMock(return_value='vmware')) +class VMwareTestCase(TestCase): + ''' + Unit TestCase for salt.cloud.clouds.vmware module. + ''' + + def test_test_vcenter_connection_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call test_vcenter_connection + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.test_vcenter_connection, call='action') + + def test_get_vcenter_version_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call get_vcenter_version + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.get_vcenter_version, call='action') + + def test_avail_images_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call avail_images + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.avail_images, call='action') + + def test_avail_locations_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call avail_locations + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.avail_locations, call='action') + + def test_avail_sizes_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call avail_sizes + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.avail_sizes, call='action') + + def test_list_datacenters_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_datacenters + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_datacenters, call='action') + + def test_list_clusters_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_clusters + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_clusters, call='action') + + def test_list_datastore_clusters_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_datastore_clusters + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_datastore_clusters, call='action') + + def test_list_datastores_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_datastores + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_datastores, call='action') + + def test_list_hosts_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_hosts, call='action') + + def test_list_resourcepools_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_resourcepools + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_resourcepools, call='action') + + def test_list_networks_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_networks + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_networks, call='action') + + def test_list_nodes_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_nodes, call='action') + + def test_list_nodes_min_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_min + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_min, call='action') + + def test_list_nodes_full_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_full, call='action') + + def test_list_nodes_select_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_nodes_full + with --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_nodes_select, call='action') + + def test_list_folders_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_folders + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_folders, call='action') + + def test_list_snapshots_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_snapshots + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_snapshots, call='action') + + def test_list_hosts_by_cluster_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_cluster + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_hosts_by_cluster, call='action') + + def test_list_clusters_by_datacenter_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_clusters_by_datacenter + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_clusters_by_datacenter, call='action') + + def test_list_hosts_by_datacenter_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_hosts_by_datacenter + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_hosts_by_datacenter, call='action') + + def test_list_hbas_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_hbas + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_hbas, call='action') + + def test_list_dvs_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_dvs + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_dvs, call='action') + + def test_list_vapps_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_vapps + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_vapps, call='action') + + def test_list_templates_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call list_templates + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.list_templates, call='action') + + def test_create_datacenter_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call create_datacenter + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.create_datacenter, call='action') + + def test_create_cluster_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call create_cluster + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.create_cluster, call='action') + + def test_rescan_hba_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call rescan_hba + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.rescan_hba, call='action') + + def test_upgrade_tools_all_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools_all + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.upgrade_tools_all, call='action') + + def test_enter_maintenance_mode_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call enter_maintenance_mode + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.enter_maintenance_mode, call='action') + + def test_exit_maintenance_mode_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call exit_maintenance_mode + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.exit_maintenance_mode, call='action') + + def test_create_folder_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call create_folder + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.create_folder, call='action') + + def test_add_host_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call add_host + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.add_host, call='action') + + def test_remove_host_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call remove_host + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.remove_host, call='action') + + def test_connect_host_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call connect_host + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.connect_host, call='action') + + def test_disconnect_host_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call disconnect_host + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.disconnect_host, call='action') + + def test_reboot_host_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call reboot_host + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.reboot_host, call='action') + + def test_create_datastore_cluster_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call create_datastore_cluster + with anything other than --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.create_datastore_cluster, call='action') + + def test_show_instance_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call show_instance + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.show_instance, name=VM_NAME, call='function') + + def test_start_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call start + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.start, name=VM_NAME, call='function') + + def test_stop_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call stop + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.stop, name=VM_NAME, call='function') + + def test_suspend_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call suspend + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.suspend, name=VM_NAME, call='function') + + def test_reset_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call reset + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.reset, name=VM_NAME, call='function') + + def test_terminate_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call terminate + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.terminate, name=VM_NAME, call='function') + + def test_destroy_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call destroy + with --function or -f. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.destroy, name=VM_NAME, call='function') + + def test_upgrade_tools_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call upgrade_tools + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.upgrade_tools, name=VM_NAME, call='function') + + def test_create_snapshot_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call create_snapshot + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.create_snapshot, name=VM_NAME, call='function') + + def test_revert_to_snapshot_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call revert_to_snapshot + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.revert_to_snapshot, name=VM_NAME, call='function') + + def test_remove_all_snapshots_call(self): + ''' + Tests that a SaltCloudSystemExit is raised when trying to call remove_all_snapshots + with anything other than --action or -a. + ''' + self.assertRaises(SaltCloudSystemExit, vmware.remove_all_snapshots, name=VM_NAME, call='function') + + def test_avail_sizes(self): + ''' + Tests that avail_sizes returns an empty dictionary. + ''' + self.assertEqual(vmware.avail_sizes(call='foo'), {}) + + +if __name__ == '__main__': + from integration import run_tests + run_tests(VMwareTestCase, needs_daemon=False) From 6cc5f97e92a090eaf75a912c3f6a0e29512694e0 Mon Sep 17 00:00:00 2001 From: Nitin Madhok Date: Wed, 12 Aug 2015 10:47:49 -0400 Subject: [PATCH 11/70] Lint Fix --- tests/unit/cloud/clouds/vmware_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/cloud/clouds/vmware_test.py b/tests/unit/cloud/clouds/vmware_test.py index 8b607d14882..78302e2df10 100644 --- a/tests/unit/cloud/clouds/vmware_test.py +++ b/tests/unit/cloud/clouds/vmware_test.py @@ -18,7 +18,7 @@ ensure_in_syspath('../../../') # Import Salt Libs from salt.cloud.clouds import vmware -from salt.exceptions import SaltCloudSystemExit, SaltCloudNotFound +from salt.exceptions import SaltCloudSystemExit # Global Variables vmware.__active_provider_name__ = '' From dad1920626ff819224ba9db8f9c77ae286be642a Mon Sep 17 00:00:00 2001 From: Julien Cigar Date: Wed, 12 Aug 2015 13:13:59 +0200 Subject: [PATCH 12/70] fix issue #26207 --- salt/modules/pw_group.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/salt/modules/pw_group.py b/salt/modules/pw_group.py index e27ba8d3297..42ff313a30f 100644 --- a/salt/modules/pw_group.py +++ b/salt/modules/pw_group.py @@ -130,3 +130,21 @@ def chgid(name, gid): if post_gid != pre_gid: return post_gid == gid return False + + +def members(name, members_list): + ''' + Replaces members of the group with a provided list. + + CLI Example: + + salt '*' group.members foo 'user1,user2,user3,...' + + Replaces a membership list for a local group 'foo'. + foo:x:1234:user1,user2,user3,... + ''' + + retcode = __salt__['cmd.retcode']('pw groupmod {0} -M {1}'.format( + name, members_list), python_shell=False) + + return not retcode From d57fdbc6a0b7aa6c5823ee33c31c05b54e3e6833 Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 11:04:09 -0600 Subject: [PATCH 13/70] Add versionadded to new members function --- salt/modules/pw_group.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/salt/modules/pw_group.py b/salt/modules/pw_group.py index 42ff313a30f..430f2ff8ad3 100644 --- a/salt/modules/pw_group.py +++ b/salt/modules/pw_group.py @@ -136,6 +136,8 @@ def members(name, members_list): ''' Replaces members of the group with a provided list. + .. versionadded:: 2015.5.4 + CLI Example: salt '*' group.members foo 'user1,user2,user3,...' From d94485d336f40fc5cdbb551fb86d990bbf166461 Mon Sep 17 00:00:00 2001 From: Nitin Madhok Date: Wed, 12 Aug 2015 13:04:17 -0400 Subject: [PATCH 14/70] Fix permission on tests/runtests.py on 2015.5 branch --- tests/runtests.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/runtests.py diff --git a/tests/runtests.py b/tests/runtests.py old mode 100644 new mode 100755 From 714f9766e79ab97b10993dc9c8042a0aa6f0f186 Mon Sep 17 00:00:00 2001 From: Nitin Madhok Date: Wed, 12 Aug 2015 13:30:03 -0400 Subject: [PATCH 15/70] Correct spelling of integration in docs --- doc/topics/development/tests/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/topics/development/tests/index.rst b/doc/topics/development/tests/index.rst index 8151e1fc6d2..64ff575fc3c 100644 --- a/doc/topics/development/tests/index.rst +++ b/doc/topics/development/tests/index.rst @@ -43,7 +43,7 @@ specific groups of tests or individual tests: * Run unit and integration tests for states: ``./tests/runtests.py --state`` * Run integration tests for an individual module: ``./tests/runtests.py -n integration.modules.virt`` * Run unit tests for an individual module: ``./tests/runtests.py -n unit.modules.virt_test`` -* Run an individual test by using the class and test name (this example is for the ``test_default_kvm_profile`` test in the ``integration.module.virt``): ``./tests/runtests.py -n ingtegration.module.virt.VirtTest.test_default_kvm_profile`` +* Run an individual test by using the class and test name (this example is for the ``test_default_kvm_profile`` test in the ``integration.module.virt``): ``./tests/runtests.py -n integration.module.virt.VirtTest.test_default_kvm_profile`` Running Unit Tests Without Integration Test Daemons From 298685bbb2a539afa7863711ee49a9907702dc8e Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 12:04:38 -0600 Subject: [PATCH 16/70] Don't make changes when test=True for openstack present/absent funcs Refs #24882 --- salt/states/openstack_config.py | 67 +++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/salt/states/openstack_config.py b/salt/states/openstack_config.py index e9563af2800..fe95c0a207d 100644 --- a/salt/states/openstack_config.py +++ b/salt/states/openstack_config.py @@ -8,10 +8,12 @@ Manage OpenStack configuration file settings. :platform: linux ''' + +# Import Python Libs from __future__ import absolute_import -# Import salt libs -import salt.exceptions +# Import Salt Libs +from salt.exceptions import CommandExecutionError def __virtual__(): @@ -48,18 +50,30 @@ def present(name, filename, section, value, parameter=None): if parameter is None: parameter = name + ret = {'name': name, + 'changes': {}, + 'result': False, + 'comment': ''} + try: old_value = __salt__['openstack_config.get'](filename=filename, section=section, parameter=parameter) if old_value == value: - return {'name': name, - 'changes': {}, - 'result': True, - 'comment': 'The value is already set to the correct value'} + ret['result'] = True + ret['comment'] = 'The value is already set to the correct value' + return ret - except salt.exceptions.CommandExecutionError as e: + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Value \'{0}\' is set to be changed to \'{1}\'.'.format( + old_value, + value + ) + return ret + + except CommandExecutionError as e: if not str(e).lower().startswith('parameter not found:'): raise @@ -68,10 +82,11 @@ def present(name, filename, section, value, parameter=None): parameter=parameter, value=value) - return {'name': name, - 'changes': {'Value': 'Updated'}, - 'result': True, - 'comment': 'The value has been updated'} + ret['changes'] = {'Value': 'Updated'} + ret['result'] = True + ret['comment'] = 'The value has been updated' + + return ret def absent(name, filename, section, parameter=None): @@ -92,23 +107,35 @@ def absent(name, filename, section, parameter=None): if parameter is None: parameter = name + ret = {'name': name, + 'changes': {}, + 'result': False, + 'comment': ''} + try: old_value = __salt__['openstack_config.get'](filename=filename, section=section, parameter=parameter) - except salt.exceptions.CommandExecutionError as e: + except CommandExecutionError as e: if str(e).lower().startswith('parameter not found:'): - return {'name': name, - 'changes': {}, - 'result': True, - 'comment': 'The value is already absent'} + ret['result'] = True + ret['comment'] = 'The value is already absent' + return ret raise + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Value \'{0}\' is set to be deleted.'.format( + old_value + ) + return ret + __salt__['openstack_config.delete'](filename=filename, section=section, parameter=parameter) - return {'name': name, - 'changes': {'Value': 'Deleted'}, - 'result': True, - 'comment': 'The value has been deleted'} + ret['changes'] = {'Value': 'Deleted'} + ret['result'] = True + ret['comment'] = 'The value has been deleted' + + return ret From 4975300591132ab316b41ff7532c50ce3ed08efd Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 13:15:02 -0600 Subject: [PATCH 17/70] Don't stacktrace on query return in ec2.create_snapshot Fixes #24484 --- salt/cloud/clouds/ec2.py | 44 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 0fe6974d31b..0ee9f181ec3 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -3703,38 +3703,52 @@ def delete_keypair(kwargs=None, call=None): def create_snapshot(kwargs=None, call=None, wait_to_finish=False): ''' - Create a snapshot + Create a snapshot. + + volume_id + The ID of the Volume from which to create a snapshot. + + description + The optional description of the snapshot. + + CLI Exampe: + + .. code-block:: bash + + salt-cloud -f create_snapshot my-ec2-config volume_id=vol-351d8826 + salt-cloud -f create_snapshot my-ec2-config volume_id=vol-351d8826 \\ + description="My Snapshot Description" ''' if call != 'function': - log.error( + raise SaltCloudSystemExit( 'The create_snapshot function must be called with -f ' 'or --function.' ) - return False - if 'volume_id' not in kwargs: - log.error('A volume_id must be specified to create a snapshot.') - return False + if kwargs is None: + kwargs = {} - if 'description' not in kwargs: - kwargs['description'] = '' + volume_id = kwargs.get('volume_id', None) + description = kwargs.get('description', '') - params = {'Action': 'CreateSnapshot'} + if volume_id is None: + raise SaltCloudSystemExit( + 'A volume_id must be specified to create a snapshot.' + ) - if 'volume_id' in kwargs: - params['VolumeId'] = kwargs['volume_id'] - - if 'description' in kwargs: - params['Description'] = kwargs['description'] + params = {'Action': 'CreateSnapshot', + 'VolumeId': volume_id, + 'Description': description} log.debug(params) data = aws.query(params, return_url=True, + return_root=True, location=get_location(), provider=get_provider(), opts=__opts__, - sigver='4') + sigver='4')[0] r_data = {} for d in data: From 787c88a2835e2c4dde329d3872fe610a17320fd8 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 12 Aug 2015 14:14:42 -0600 Subject: [PATCH 18/70] Multiple improvements to reg executionmod and state mod --- salt/modules/reg.py | 310 ++++++++++++++++++++++++++++---------------- salt/states/reg.py | 269 +++++++++++++++++++++++++++++++++----- 2 files changed, 434 insertions(+), 145 deletions(-) diff --git a/salt/modules/reg.py b/salt/modules/reg.py index d039823c56c..eff58c06014 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -1,29 +1,36 @@ # -*- coding: utf-8 -*- ''' -Manage the registry on Windows. +=========================== +Manage the Windows registry +=========================== The read_key and set_key functions will be updated in Boron to reflect proper registry usage. The registry has three main components. Hives, Keys, and Values. -### Hives +----- +Hives +----- Hives are the main sections of the registry and all begin with the word HKEY. - HKEY_LOCAL_MACHINE - HKEY_CURRENT_USER - HKEY_USER -### Keys +---- +Keys +---- Keys are the folders in the registry. Keys can have many nested subkeys. Keys can have a value assigned to them under the (Default) -### Values -Values are name/data pairs. There can be many values in a key. The (Default) -value corresponds to the Key, the rest are their own value pairs. +----------------- +Values or Entries +----------------- +Values/Entries are name/data pairs. There can be many values in a key. The +(Default) value corresponds to the Key, the rest are their own value pairs. :depends: - winreg Python module ''' -# TODO: Figure out the exceptions _winreg can raise and properly catch -# them instead of a bare except that catches any exception at all +# TODO: Figure out the exceptions _winreg can raise and properly catch them # Import third party libs try: @@ -145,44 +152,35 @@ def read_key(hkey, path, key=None): key=path, vname=key) - registry = Registry() - hive = registry.hkeys[hkey] - - try: - value = _winreg.QueryValue(hive, path) - if value: - ret['vdata'] = value - else: - ret['vdata'] = None - ret['comment'] = 'Empty Value' - except WindowsError as exc: # pylint: disable=E0602 - log.debug(exc) - ret['comment'] = '{0}'.format(exc) - ret['success'] = False - - return ret + return read_value(hive=hkey, key=path) def read_value(hive, key, vname=None): r''' - Reads a registry value or the default value for a key. + Reads a registry value entry or the default value for a key. - :param hive: string - The name of the hive. Can be one of the following - - HKEY_LOCAL_MACHINE or HKLM - - HKEY_CURRENT_USER or HKCU - - HKEY_USER or HKU + :param str hive: + The name of the hive. Can be one of the following + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU - :param key: string - The key (looks like a path) to the value name. + :param str key: + The key (looks like a path) to the value name. - :param vname: string - The value name. These are the individual name/data pairs under the key. If - not passed, the key (Default) value will be returned + :param str vname: + The value name. These are the individual name/data pairs under the key. + If not passed, the key (Default) value will be returned - :return: dict - A dictionary containing the passed settings as well as the value_data if - successful. If unsuccessful, sets success to False + :return: + A dictionary containing the passed settings as well as the value_data if + successful. If unsuccessful, sets success to False + + If vname is not passed: + - Returns the first unnamed value (Default) as a string. + - Returns none if first unnamed value is empty. + - Returns False if key not found. + :rtype: dict CLI Example: @@ -208,9 +206,9 @@ def read_value(hive, key, vname=None): try: handle = _winreg.OpenKey(hive, key) - value, vtype = _winreg.QueryValueEx(handle, vname) - if value: - ret['vdata'] = value + vdata, vtype = _winreg.QueryValueEx(handle, vname) + if vdata: + ret['vdata'] = vdata ret['vtype'] = registry.vtype_reverse[vtype] else: ret['comment'] = 'Empty Value' @@ -260,53 +258,45 @@ def set_key(hkey, path, value, key=None, vtype='REG_DWORD', reflection=True): vdata=value, vtype=vtype) - registry = Registry() - hive = registry.hkeys[hkey] - vtype = registry.vtype['REG_SZ'] - - try: - _winreg.SetValue(hive, path, vtype, value) - return True - except WindowsError as exc: # pylint: disable=E0602 - log.error(exc) - return False + return set_value(hive=hkey, key=path, vdata=value, vtype=vtype) def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', reflection=True): ''' - Sets a registry value. + Sets a registry value entry or the default value for a key. - :param hive: string - The name of the hive. Can be one of the following - - HKEY_LOCAL_MACHINE or HKLM - - HKEY_CURRENT_USER or HKCU - - HKEY_USER or HKU + :param str hive: + The name of the hive. Can be one of the following + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU - :param key: string - The key (looks like a path) to the value name. + :param str key: + The key (looks like a path) to the value name. - :param vname: string - The value name. These are the individual name/data pairs under the key. If - not passed, the key (Default) value will be set. + :param str vname: + The value name. These are the individual name/data pairs under the key. + If not passed, the key (Default) value will be set. - :param vdata: string - The value data to be set. + :param str vdata: + The value data to be set. - :param vtype: string - The value type. Can be one of the following: - - REG_BINARY - - REG_DWORD - - REG_EXPAND_SZ - - REG_MULTI_SZ - - REG_SZ + :param str vtype: + The value type. Can be one of the following: + - REG_BINARY + - REG_DWORD + - REG_EXPAND_SZ + - REG_MULTI_SZ + - REG_SZ - :param reflection: boolean - A boolean value indicating that the value should also be set in the - Wow6432Node portion of the registry. Only applies to 64 bit Windows. This - setting is ignored for 32 bit Windows. + :param bool reflection: + A boolean value indicating that the value should also be set in the + Wow6432Node portion of the registry. Only applies to 64 bit Windows. + This setting is ignored for 32 bit Windows. - :return: boolean - Returns True if successful, False if not + :return: + Returns True if successful, False if not + :rtype: bool CLI Example: @@ -324,7 +314,7 @@ def set_value(hive, key, vname=None, vdata=None, vtype='REG_SZ', reflection=True _winreg.SetValueEx(handle, vname, 0, vtype, vdata) _winreg.CloseKey(handle) return True - except WindowsError as exc: # pylint: disable=E0602 + except (WindowsError, ValueError) as exc: # pylint: disable=E0602 log.error(exc) return False @@ -356,7 +346,7 @@ def create_key(hkey, path, key=None, value=None, reflection=True): salt '*' reg.create_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version' '0.97' ''' if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry ' + salt.utils.warn_until('Boron', 'Use reg.set_value to create a registry ' 'value. This functionality will be ' 'removed in Salt Boron') return set_value(hive=hkey, @@ -365,21 +355,10 @@ def create_key(hkey, path, key=None, value=None, reflection=True): vdata=value, vtype='REG_SZ') - registry = Registry() - hive = registry.hkeys[hkey] - key = path - access_mask = registry.reflection_mask[reflection] - - try: - handle = _winreg.CreateKeyEx(hive, key, 0, access_mask) - _winreg.CloseKey(handle) - return True - except WindowsError as exc: # pylint: disable=E0602 - log.error(exc) - return False + return set_value(hive=hkey, key=path) -def delete_key(hkey, path, key=None, reflection=True): +def delete_key(hkey, path, key=None, reflection=True, force=False): ''' *** Incorrect Usage *** The name of this function is misleading and will be changed to reflect @@ -399,29 +378,62 @@ def delete_key(hkey, path, key=None, reflection=True): Delete a registry key - Note: This cannot delete a key with subkeys - CLI Example: .. code-block:: bash salt '*' reg.delete_key HKEY_CURRENT_USER 'SOFTWARE\\Salt' + + :param str hkey: (will be changed to hive) + The name of the hive. Can be one of the following + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU + + :param str path: (will be changed to key) + The key (looks like a path) to remove. + + :param str key: (used incorrectly) + Will be removed in Boron + + :param bool reflection: + A boolean value indicating that the value should also be removed from + the Wow6432Node portion of the registry. Only applies to 64 bit Windows. + This setting is ignored for 32 bit Windows. + + Only applies to delete value. If the key parameter is passed, this + function calls delete_value instead. Will be changed in Boron. + + :param bool force: + A boolean value indicating that all subkeys should be removed as well. + If this is set to False (default) and there are subkeys, the delete_key + function will fail. + + :return: + Returns True if successful, False if not + If force=True, the results of delete_key_recursive are returned. + :rtype: bool ''' if key: # This if statement will be removed in Boron - salt.utils.warn_until('Boron', 'Use reg.set_value to set a registry ' - 'value. This functionality will be ' - 'removed in Salt Boron') + salt.utils.warn_until('Boron', + 'Variable names will be changed to match Windows ' + 'Registry terminology. These changes will be ' + 'made in Boron') return delete_value(hive=hkey, key=path, vname=key, reflection=reflection) + if force: + return delete_key_recursive(hkey, path) + registry = Registry() hive = registry.hkeys[hkey] key = path try: + # Can't use delete_value to delete a key _winreg.DeleteKey(hive, key) return True except WindowsError as exc: # pylint: disable=E0602 @@ -429,30 +441,100 @@ def delete_key(hkey, path, key=None, reflection=True): return False +def delete_key_recursive(hive, key): + ''' + Delete a registry key to include all subkeys. + + :param hive: + The name of the hive. Can be one of the following + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU + + :param key: + The key to remove (looks like a path) + + :return: + A dictionary listing the keys that deleted successfully as well as those + that failed to delete. + :rtype: dict + ''' + # Functions for traversing the registry tree + def subkeys(key): + i = 0 + while True: + try: + subkey = _winreg.EnumKey(key, i) + yield subkey + i += 1 + except WindowsError: + break + + def traverse_registry_tree(hkey, keypath, ret): + key = _winreg.OpenKey(hkey, keypath, 0, _winreg.KEY_READ) + for subkeyname in subkeys(key): + subkeypath = "{0}\{1}".format(keypath, subkeyname) + ret = traverse_registry_tree(hkey, subkeypath, ret) + ret.append('{0}'.format(subkeypath)) + return ret + + # Instantiate the registry object + registry = Registry() + hkey = registry.hkeys[hive] + keypath = key + + # Get a reverse list of registry keys to be deleted + key_list = [] + key_list = traverse_registry_tree(hkey, keypath, key_list) + + ret = {'Deleted': [], + 'Failed': []} + + # Delete all subkeys + for keypath in key_list: + try: + _winreg.DeleteKey(hkey, keypath) + ret['Deleted'].append('{0}\{1}'.format(hive, keypath)) + except WindowsError as exc: # pylint: disable=E0602 + log.error(exc) + ret['Failed'].append('{0}\{1} {2}'.format(hive, key, exc)) + + # Delete the key now that all the subkeys are deleted + try: + _winreg.DeleteKey(hkey, key) + ret['Deleted'].append('{0}\{1}'.format(hive, key)) + except WindowsError as exc: # pylint: disable=E0602 + log.error(exc) + ret['Failed'].append('{0}\{1} {2}'.format(hive, key, exc)) + + return ret + + def delete_value(hive, key, vname=None, reflection=True): ''' - Deletes a registry value. + Delete a registry value entry or the default value for a key. - :param hive: string - The name of the hive. Can be one of the following - - HKEY_LOCAL_MACHINE or HKLM - - HKEY_CURRENT_USER or HKCU - - HKEY_USER or HKU + :param str hive: + The name of the hive. Can be one of the following + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU - :param key: string - The key (looks like a path) to the value name. + :param str key: + The key (looks like a path) to the value name. - :param vname: string - The value name. These are the individual name/data pairs under the key. If - not passed, the key (Default) value will be deleted. + :param str vname: + The value name. These are the individual name/data pairs under the key. + If not passed, the key (Default) value will be deleted. - :param reflection: boolean - A boolean value indicating that the value should also be set in the - Wow6432Node portion of the registry. Only applies to 64 bit Windows. This - setting is ignored for 32 bit Windows. + :param bool reflection: + A boolean value indicating that the value should also be set in the + Wow6432Node portion of the registry. Only applies to 64 bit Windows. + This setting is ignored for 32 bit Windows. - :return: boolean - Returns True if successful, False if not + :return: + Returns True if successful, False if not + :rtype: bool CLI Example: diff --git a/salt/states/reg.py b/salt/states/reg.py index 28d7d1b5748..06cbb074d0a 100644 --- a/salt/states/reg.py +++ b/salt/states/reg.py @@ -1,9 +1,66 @@ # -*- coding: utf-8 -*- ''' -Manage the registry on Windows +=========================== +Manage the Windows registry +=========================== +Many python developers think of registry keys as if they were python keys in a +dictionary which is not the case. The windows registry is broken down into the +following components: + +----- +Hives +----- + +This is the top level of the registry. They all begin with HKEY. +- HKEY_CLASSES_ROOT (HKCR) +- HKEY_CURRENT_USER(HKCU) +- HKEY_LOCAL MACHINE (HKLM) +- HKEY_USER (HKU) +- HKEY_CURRENT_CONFIG + +---- +Keys +---- + +Hives contain keys. These are basically the folders beneath the hives. They can +contain any number of subkeys. + +----------------- +Values or Entries +----------------- + +Values or Entries are the name/data pairs beneath the keys and subkeys. All keys +have a default name/data pair. It is usually "(Default)"="(value not set)". The +actual value for the name and the date is Null. The registry editor will display +"(Default)" and "(value not set)". + +------- +Example +------- + +The following example is taken from the windows startup portion of the registry: +``` +[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] +"RTHDVCPL"="\"C:\\Program Files\\Realtek\\Audio\\HDA\\RtkNGUI64.exe\" -s" +"NvBackend"="\"C:\\Program Files (x86)\\NVIDIA Corporation\\Update Core\\NvBackend.exe\"" +"BTMTrayAgent"="rundll32.exe \"C:\\Program Files (x86)\\Intel\\Bluetooth\\btmshellex.dll\",TrayApp" +``` +In this example these are the values for each: + +Hive: `HKEY_LOCAL_MACHINE` + +Key and subkeys: `SOFTWARE\Microsoft\Windows\CurrentVersion\Run` + +Value: + - There are 3 value names: `RTHDVCPL`, `NvBackend`, and `BTMTrayAgent` + - Each value name has a corresponding value ''' +# Import python libs import logging +# Import salt libs +import salt.utils + log = logging.getLogger(__name__) @@ -21,7 +78,7 @@ def _parse_key_value(key): splt = key.split("\\") hive = splt.pop(0) vname = splt.pop(-1) - key = r'\\'.join(splt) + key = '\\'.join(splt) return hive, key, vname @@ -31,51 +88,128 @@ def _parse_key(key): ''' splt = key.split("\\") hive = splt.pop(0) - key = r'\\'.join(splt) + key = '\\'.join(splt) return hive, key -def present(name, value, vtype='REG_SZ', reflection=True): +def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection=True): ''' - Set a registry value + Ensure a registry key or value is present. - Optionally set ``reflection`` to ``False`` to disable reflection. - ``reflection`` has no effect on a 32-bit OS. + :param str name: + A string value representing the full path of the key to include the + HIVE, Key, and all Subkeys. For example: - In the example below, this will prevent Windows from silently creating - the key in: - ``HKEY_CURRENT_USER\\SOFTWARE\\Wow6432Node\\Salt\\version`` + ``HKEY_LOCAL_MACHINE\\SOFTWARE\\Salt`` + + Valid hive values include: + - HKEY_CURRENT_USER or HKCU + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_USERS or HKU + + :param str value: + Deprecated. Use vname and vdata instead. Included here for backwards + compatability. + + :param str vname: + The name of the value you'd like to create beneath the Key. If this + parameter is not passed it will assume you want to set the (Default) + value + + :param str vdata: + The value you'd like to set for the Key. If a value name (vname) is + passed, this will be the data for that value name. If not, this will be + the (Default) value for the key. + + The type for the (Default) value is always REG_SZ and cannot be changed. + This parameter is optional. If not passed, the Key will be created with. + + :param str vtype: + The value type for the data you wish to store in the registry. Valid + values are: + + - REG_BINARY + - REG_DWORD + - REG_EXPAND_SZ + - REG_MULTI_SZ + - REG_SZ (Default) + + :param bool reflection: + On 64 bit machines a duplicate value will be created in the + ``Wow6432Node`` for 32bit programs. This only applies to the SOFTWARE + key. This option is ignored on 32bit operating systems. This value + defaults to True. Set it to False to disable reflection. + + :return: + Returns a dictionary showing the results of the registry operation. + :rtype: dict + + The following example will set the ``(Default)`` value for the + ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The + value will not be reflected in ``Wow6432Node``: Example: .. code-block:: yaml - HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version: + HKEY_CURRENT_USER\\SOFTWARE\\Salt: reg.present: - - value: 0.15.3 - - vtype: REG_SZ + - vdata: 0.15.3 - reflection: False + The following example will set the value for the ``version`` entry under the + ``SOFTWARE\\Salt`` key in the ``HKEY_CURRENT_USER`` hive to ``0.15.3``. The + value will be reflected in ``Wow6432Node``: + + Example: + + .. code-block:: yaml + + HKEY_CURRENT_USER\\SOFTWARE\\Salt: + reg.present: + - vname: version + - vdata: 0.15.3 + In the above example the path is interpreted as follows: - ``HKEY_CURRENT_USER`` is the hive - ``SOFTWARE\\Salt`` is the key - - ``version`` is the value name - So ``version`` will be created in the ``SOFTWARE\\Salt`` key in the - ``HKEY_CURRENT_USER`` hive and given the ``REG_SZ`` value of ``0.15.3``. + - ``vname`` is the value name ('version') that will be created under the key + - ``vdata`` is the data that will be assigned to 'version' ''' ret = {'name': name, 'result': True, 'changes': {}, 'comment': ''} - hive, key, vname = _parse_key_value(name) + # This is for backwards compatibility + # If 'value' is passed a value, vdata becomes value and the vname is + # obtained from the key path + if value: + hive, key, vname = _parse_key_value(name) + vdata = value + ret['comment'] = 'State file is using deprecated syntax. Please update.' + salt.utils.warn_until( + 'Boron', + 'The \'value\' argument has been deprecated. ' + 'Please use vdata instead.' + ) + else: + hive, key = _parse_key(name) # Determine what to do - if value == __salt__['reg.read_value'](hive, key, vname)['vdata']: - ret['comment'] = '{0} is already configured'.format(name) + reg_current = __salt__['reg.read_value'](hive, key, vname) + + if vdata == reg_current['vdata'] and reg_current['success']: + ret['comment'] = '{0} in {1} is already configured'.\ + format(vname if vname else '(Default)', name) return ret - else: - ret['changes'] = {'reg': 'configured to {0}'.format(value)} + + ret['changes'] = {'reg': { + 'Added': { + 'Key': '{0}\{1}'.format(hive, key), + 'Entry': '{0}'.format(vname if vname else '(Default)'), + 'Value': '{0}'.format(vdata if vdata else '(Empty String)') + }}} # Check for test option if __opts__['test']: @@ -83,19 +217,19 @@ def present(name, value, vtype='REG_SZ', reflection=True): return ret # Configure the value - ret['result'] = __salt__['reg.set_value'](hive, key, vname, value, vtype, + ret['result'] = __salt__['reg.set_value'](hive, key, vname, vdata, vtype, reflection) - if not ret: + if not ret['result']: ret['changes'] = {} - ret['comment'] = 'could not configure the registry key' + ret['comment'] = 'Could not configure the registry key' return ret -def absent(name): +def absent(name, vname=None): ''' - Remove a registry value + Ensure a registry value is removed. To remove a key use key_absent. Example:: @@ -114,14 +248,20 @@ def absent(name): 'changes': {}, 'comment': ''} - hive, key, vname = _parse_key_value(name) + hive, key = _parse_key(name) # Determine what to do if not __salt__['reg.read_value'](hive, key, vname)['success']: - ret['comment'] = '{0} is already absent'.format(name) - return ret - else: - ret['changes'] = {'reg': 'Removed {0}'.format(name)} + hive, key, vname = _parse_key_value(name) + if not __salt__['reg.read_value'](hive, key, vname)['success']: + ret['comment'] = '{0} is already absent'.format(name) + return ret + + ret['changes'] = {'reg': { + 'Removed': { + 'Key': '{0}\{1}'.format(hive, key), + 'Entry': '{0}'.format(vname if vname else '(Default)') + }}} # Check for test option if __opts__['test']: @@ -131,6 +271,73 @@ def absent(name): # Delete the value ret['result'] = __salt__['reg.delete_value'](hive, key, vname) if not ret['result']: + ret['changes'] = {} + ret['comment'] = 'failed to remove {0} from {1}\{2}'.format(name, hive, + key) + + return ret + + +def key_absent(name, force=False): + ''' + Ensure a registry key is removed. This will remove a key and all value + entries it contains. It will fail if the key contains subkeys. + + :param str name: + A string representing the full path to the key to be removed to include + the hive and the keypath. The hive can be any of the following: + - HKEY_LOCAL_MACHINE or HKLM + - HKEY_CURRENT_USER or HKCU + - HKEY_USER or HKU + + :param bool force: + A boolean value indicating that all subkeys should be deleted with the + key. If force=False and subkeys exists beneath the key you want to + delete, key_absent will fail. Use with caution. The default is False. + + :return: + Returns a dictionary showing the results of the registry operation. + :rtype: dict + + The following example will delete the ``SOFTWARE\Salt`` key and all subkeys + under the ``HKEY_CURRENT_USER`` hive. + + Example:: + + 'HKEY_CURRENT_USER\SOFTWARE\Salt': + reg.key_absent: + - force: True + + In the above example the path is interpreted as follows: + - ``HKEY_CURRENT_USER`` is the hive + - ``SOFTWARE\Salt`` is the key + ''' + ret = {'name': name, + 'result': True, + 'changes': {}, + 'comment': ''} + + hive, key = _parse_key(name) + + # Determine what to do + if not __salt__['reg.read_value'](hive, key)['success']: + ret['comment'] = '{0} is already absent'.format(name) + return ret + + ret['changes'] = {'reg': { + 'Removed': { + 'Key': '{0}\{1}'.format(hive, key) + }}} + + # Check for test option + if __opts__['test']: + ret['result'] = None + return ret + + # Delete the value + __salt__['reg.delete_key'](hive, key, force=force) + if __salt__['reg.read_value'](hive, key)['success']: + ret['result'] = False ret['changes'] = {} ret['comment'] = 'failed to remove registry key {0}'.format(name) From 86b8161d22502bdbf073547e97331a95115c4811 Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 14:29:33 -0600 Subject: [PATCH 19/70] Mock test key in __opts__ dict --- tests/unit/states/openstack_config_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/states/openstack_config_test.py b/tests/unit/states/openstack_config_test.py index 73b49445424..bfc8b4c109b 100644 --- a/tests/unit/states/openstack_config_test.py +++ b/tests/unit/states/openstack_config_test.py @@ -22,7 +22,7 @@ ensure_in_syspath('../../') from salt.states import openstack_config openstack_config.__salt__ = {} -openstack_config.__opts__ = {} +openstack_config.__opts__ = {'test': False} @skipIf(NO_MOCK, NO_MOCK_REASON) From 139fbb93bce462810fc33a44204432633becd1ab Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 14:57:07 -0600 Subject: [PATCH 20/70] Fix del_root_vol_on_destroy and del_all_vols_on_destroy functionality on ec2 Fixes #24483 --- salt/cloud/clouds/ec2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 0fe6974d31b..f011c2d2598 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -1600,7 +1600,6 @@ def request_instance(vm_=None, call=None): } try: rd_data = aws.query(rd_params, - return_root=True, location=get_location(), provider=get_provider(), opts=__opts__, @@ -2294,7 +2293,7 @@ def create(vm_=None, call=None): 'volumes': volumes, 'zone': ret['placement']['availabilityZone'], 'instance_id': ret['instanceId'], - 'del_all_vols_on_destroy': vm_.get('set_del_all_vols_on_destroy', False) + 'del_all_vols_on_destroy': vm_.get('del_all_vols_on_destroy', False) }, call='action' ) From 1aad4b1b4facd24c5b1bd6461680f8a27a51f37b Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Wed, 12 Aug 2015 14:19:05 -0700 Subject: [PATCH 21/70] Jobs are enabled by default but schedule.list does not show an enabled jobs as being enabled by default. This change fixes that. --- salt/modules/schedule.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index c147f18dac8..599a8074b07 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -79,6 +79,11 @@ def list_(show_all=False, return_yaml=True): del schedule[job] continue + # if enabled is not included in the job, + # assume job is enabled. + if 'enabled' not in schedule[job]: + schedule[job]['enabled'] = True + for item in pycopy.copy(schedule[job]): if item not in SCHEDULE_CONF: del schedule[job][item] From 7393adf5a833a05d512bb45aa04aa37440cda77a Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 12 Aug 2015 16:00:36 -0600 Subject: [PATCH 22/70] Fixed some lint --- salt/modules/reg.py | 12 ++++++------ salt/states/reg.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/salt/modules/reg.py b/salt/modules/reg.py index eff58c06014..e067bbb5c97 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -467,13 +467,13 @@ def delete_key_recursive(hive, key): subkey = _winreg.EnumKey(key, i) yield subkey i += 1 - except WindowsError: + except WindowsError: # pylint: disable=E0602 break def traverse_registry_tree(hkey, keypath, ret): key = _winreg.OpenKey(hkey, keypath, 0, _winreg.KEY_READ) for subkeyname in subkeys(key): - subkeypath = "{0}\{1}".format(keypath, subkeyname) + subkeypath = r'{0}\{1}'.format(keypath, subkeyname) ret = traverse_registry_tree(hkey, subkeypath, ret) ret.append('{0}'.format(subkeypath)) return ret @@ -494,18 +494,18 @@ def delete_key_recursive(hive, key): for keypath in key_list: try: _winreg.DeleteKey(hkey, keypath) - ret['Deleted'].append('{0}\{1}'.format(hive, keypath)) + ret['Deleted'].append(r'{0}\{1}'.format(hive, keypath)) except WindowsError as exc: # pylint: disable=E0602 log.error(exc) - ret['Failed'].append('{0}\{1} {2}'.format(hive, key, exc)) + ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc)) # Delete the key now that all the subkeys are deleted try: _winreg.DeleteKey(hkey, key) - ret['Deleted'].append('{0}\{1}'.format(hive, key)) + ret['Deleted'].append(r'{0}\{1}'.format(hive, key)) except WindowsError as exc: # pylint: disable=E0602 log.error(exc) - ret['Failed'].append('{0}\{1} {2}'.format(hive, key, exc)) + ret['Failed'].append(r'{0}\{1} {2}'.format(hive, key, exc)) return ret diff --git a/salt/states/reg.py b/salt/states/reg.py index 06cbb074d0a..8a4c417e502 100644 --- a/salt/states/reg.py +++ b/salt/states/reg.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -''' +r''' =========================== Manage the Windows registry =========================== @@ -206,7 +206,7 @@ def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection ret['changes'] = {'reg': { 'Added': { - 'Key': '{0}\{1}'.format(hive, key), + 'Key': r'{0}\{1}'.format(hive, key), 'Entry': '{0}'.format(vname if vname else '(Default)'), 'Value': '{0}'.format(vdata if vdata else '(Empty String)') }}} @@ -259,7 +259,7 @@ def absent(name, vname=None): ret['changes'] = {'reg': { 'Removed': { - 'Key': '{0}\{1}'.format(hive, key), + 'Key': r'{0}\{1}'.format(hive, key), 'Entry': '{0}'.format(vname if vname else '(Default)') }}} @@ -272,14 +272,14 @@ def absent(name, vname=None): ret['result'] = __salt__['reg.delete_value'](hive, key, vname) if not ret['result']: ret['changes'] = {} - ret['comment'] = 'failed to remove {0} from {1}\{2}'.format(name, hive, + ret['comment'] = r'failed to remove {0} from {1}\{2}'.format(name, hive, key) return ret def key_absent(name, force=False): - ''' + r''' Ensure a registry key is removed. This will remove a key and all value entries it contains. It will fail if the key contains subkeys. @@ -326,7 +326,7 @@ def key_absent(name, force=False): ret['changes'] = {'reg': { 'Removed': { - 'Key': '{0}\{1}'.format(hive, key) + 'Key': r'{0}\{1}'.format(hive, key) }}} # Check for test option From 1e0473c04af212fe1743e021b957cd076e189b33 Mon Sep 17 00:00:00 2001 From: Mike Place Date: Wed, 12 Aug 2015 16:08:23 -0600 Subject: [PATCH 23/70] Re-init modules on multi-master reconnect --- salt/minion.py | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/minion.py b/salt/minion.py index 5e26f42dcf2..e8621659e88 100644 --- a/salt/minion.py +++ b/salt/minion.py @@ -1760,6 +1760,7 @@ class Minion(MinionBase): self.socket.connect(self.master_pub) self.poller.register(self.socket, zmq.POLLIN) self.poller.register(self.epull_sock, zmq.POLLIN) + self.functions, self.returners, self.function_errors = self._load_modules() self._fire_master_minion_start() log.info('Minion is ready to receive requests!') From 496474d862f4073203841466de683f807ecf2bd7 Mon Sep 17 00:00:00 2001 From: rallytime Date: Wed, 12 Aug 2015 16:54:42 -0600 Subject: [PATCH 24/70] Handle exception when user is not found in keystone.get_user Refs #26240 --- salt/modules/keystone.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index 1cb5a325089..09372256248 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -49,6 +49,10 @@ Module for handling openstack keystone calls. salt '*' keystone.tenant_list profile=openstack1 ''' +# Import Python Libs +from __future__ import absolute_import +import logging + # Import third party libs HAS_KEYSTONE = False try: @@ -58,6 +62,8 @@ try: except ImportError: pass +log = logging.getLogger(__name__) + def __virtual__(): ''' @@ -699,7 +705,16 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): break if not user_id: return {'Error': 'Unable to resolve user id'} - user = kstone.users.get(user_id) + try: + user = kstone.users.get(user_id) + except keystoneclient.exceptions.NotFound: + log.error( + 'Could not find user \'{0}\''.format( + user_id + ) + ) + return ret + ret[user.name] = {'id': user.id, 'name': user.name, 'email': user.email, From a1274c438d893a89db75aadb595489897a5cadf9 Mon Sep 17 00:00:00 2001 From: twangboy Date: Wed, 12 Aug 2015 17:13:50 -0600 Subject: [PATCH 25/70] I might have fixed some tests... I might have made them worse --- tests/unit/states/reg_test.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/unit/states/reg_test.py b/tests/unit/states/reg_test.py index dd849f43430..a328a6c85f1 100644 --- a/tests/unit/states/reg_test.py +++ b/tests/unit/states/reg_test.py @@ -36,28 +36,35 @@ class RegTestCase(TestCase): ''' Test to set a registry entry. ''' - name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version' - value = '0.15.3' + name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt' + vname = 'version' + vdata = '0.15.3' ret = {'name': name, 'changes': {}, 'result': True, 'comment': '{0} is already configured'.format(name)} - mock = MagicMock(side_effect=[{'vdata': value}, {'vdata': 'a'}, {'vdata': 'a'}]) + mock = MagicMock(side_effect=[{'vdata': vdata}, {'vdata': 'a'}, {'vdata': 'a'}]) mock_t = MagicMock(return_value=True) with patch.dict(reg.__salt__, {'reg.read_value': mock, 'reg.set_value': mock_t}): - self.assertDictEqual(reg.present(name, value), ret) + self.assertDictEqual(reg.present(name, + vname=vname, + vdata=vdata), ret) with patch.dict(reg.__opts__, {'test': True}): ret.update({'comment': '', 'result': None, 'changes': {'reg': 'configured to 0.15.3'}}) - self.assertDictEqual(reg.present(name, value), ret) + self.assertDictEqual(reg.present(name, + vname=vname, + vdata=vdata), ret) with patch.dict(reg.__opts__, {'test': False}): ret.update({'result': True}) - self.assertDictEqual(reg.present(name, value), ret) + self.assertDictEqual(reg.present(name, + vname=vname, + vdata=vdata), ret) # 'absent' function tests: 1 @@ -65,7 +72,8 @@ class RegTestCase(TestCase): ''' Test to remove a registry entry. ''' - name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt\\version' + name = 'HKEY_CURRENT_USER\\SOFTWARE\\Salt' + vname = 'version' ret = {'name': name, 'changes': {}, @@ -76,16 +84,16 @@ class RegTestCase(TestCase): mock_t = MagicMock(return_value=True) with patch.dict(reg.__salt__, {'reg.read_value': mock, 'reg.delete_value': mock_t}): - self.assertDictEqual(reg.absent(name), ret) + self.assertDictEqual(reg.absent(name, vname), ret) with patch.dict(reg.__opts__, {'test': True}): ret.update({'comment': '', 'result': None, 'changes': {'reg': 'Removed {0}'.format(name)}}) - self.assertDictEqual(reg.absent(name), ret) + self.assertDictEqual(reg.absent(name, vname), ret) with patch.dict(reg.__opts__, {'test': False}): ret.update({'result': True}) - self.assertDictEqual(reg.absent(name), ret) + self.assertDictEqual(reg.absent(name, vname), ret) if __name__ == '__main__': From 1f18f4f91e89dbc0e7df0086f33b014194cdcd01 Mon Sep 17 00:00:00 2001 From: Stanislav Blokhin Date: Thu, 13 Aug 2015 14:53:24 +0200 Subject: [PATCH 26/70] Remove explicit version from instance identity URL --- salt/utils/iam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/utils/iam.py b/salt/utils/iam.py index 6b88ed09532..a9e6bd4cff5 100644 --- a/salt/utils/iam.py +++ b/salt/utils/iam.py @@ -68,7 +68,7 @@ def get_iam_region(version='latest', url='http://169.254.169.254', ''' Gets instance identity document and returns region ''' - instance_identity_url = '{0}/{1}/latest/dynamic/instance-identity/document'.format(url, version) + instance_identity_url = '{0}/{1}/dynamic/instance-identity/document'.format(url, version) region = None try: From f46722aaeb3f914a8825ea7f676bbe686e2ae696 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Thu, 13 Aug 2015 18:22:21 +0200 Subject: [PATCH 27/70] allow to delete grains which value is False --- salt/states/grains.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/salt/states/grains.py b/salt/states/grains.py index 76a07685a55..4ee6851a463 100644 --- a/salt/states/grains.py +++ b/salt/states/grains.py @@ -220,8 +220,7 @@ def absent(name, destructive=False): 'changes': {}, 'result': True, 'comment': ''} - grain = __grains__.get(name) - if grain: + if name in __grains__: if __opts__['test']: ret['result'] = None if destructive is True: From 39d3eb66f0cde5333c2ec170a12a1a9ba8b04285 Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 13 Aug 2015 10:39:03 -0600 Subject: [PATCH 28/70] Log error and return error - make returns consistent. --- salt/modules/keystone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index 09372256248..7dca68273ef 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -713,7 +713,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): user_id ) ) - return ret + return {'Could not find user \'{0}\''.format(user_id)} ret[user.name] = {'id': user.id, 'name': user.name, From 5edabfd271ec4c08800de437af0495726f58a1a3 Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 13 Aug 2015 10:40:53 -0600 Subject: [PATCH 29/70] It's a dict - git problems... --- salt/modules/keystone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index 7dca68273ef..9313a9d8ae3 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -713,7 +713,7 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): user_id ) ) - return {'Could not find user \'{0}\''.format(user_id)} + return {'Error': 'Could not find user \'{0}\''.format(user_id)} ret[user.name] = {'id': user.id, 'name': user.name, From 0b6977335e59b2c50a5661016cfd8109f5024c66 Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 13 Aug 2015 10:42:20 -0600 Subject: [PATCH 30/70] Clean it up --- salt/modules/keystone.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/salt/modules/keystone.py b/salt/modules/keystone.py index 9313a9d8ae3..d9d67ed1bfe 100644 --- a/salt/modules/keystone.py +++ b/salt/modules/keystone.py @@ -708,12 +708,9 @@ def user_get(user_id=None, name=None, profile=None, **connection_args): try: user = kstone.users.get(user_id) except keystoneclient.exceptions.NotFound: - log.error( - 'Could not find user \'{0}\''.format( - user_id - ) - ) - return {'Error': 'Could not find user \'{0}\''.format(user_id)} + msg = 'Could not find user \'{0}\''.format(user_id) + log.error(msg) + return {'Error': msg} ret[user.name] = {'id': user.id, 'name': user.name, From a1f90fa07023561909882e8d6d401cadde41df61 Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 13 Aug 2015 10:57:14 -0600 Subject: [PATCH 31/70] Only call convert_to_arn when action name is provided Refs #25192 --- salt/modules/boto_cloudwatch.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/salt/modules/boto_cloudwatch.py b/salt/modules/boto_cloudwatch.py index 136d4141fa3..42454071d5a 100644 --- a/salt/modules/boto_cloudwatch.py +++ b/salt/modules/boto_cloudwatch.py @@ -220,12 +220,25 @@ def create_or_update_alarm( if isinstance(ok_actions, string_types): ok_actions = ok_actions.split(",") - # convert action names into ARN's - alarm_actions = convert_to_arn(alarm_actions, region, key, keyid, profile) - insufficient_data_actions = convert_to_arn( - insufficient_data_actions, region, key, keyid, profile - ) - ok_actions = convert_to_arn(ok_actions, region, key, keyid, profile) + # convert provided action names into ARN's + if alarm_actions: + alarm_actions = convert_to_arn(alarm_actions, + region=region, + key=key, + keyid=keyid, + profile=profile) + if insufficient_data_actions: + insufficient_data_actions = convert_to_arn(insufficient_data_actions, + region=region, + key=key, + keyid=keyid, + profile=profile) + if ok_actions: + ok_actions = convert_to_arn(ok_actions, + region=region, + key=key, + keyid=keyid, + profile=profile) conn = _get_conn(region, key, keyid, profile) if not conn: From 39ef653bc2104b73d671bbb5a73d76018e6090f0 Mon Sep 17 00:00:00 2001 From: Geraint Jones Date: Mon, 15 Jun 2015 12:02:25 +0000 Subject: [PATCH 32/70] Rabbitmq 3.2.4 on Ubuntu has ...done. not ...done, change the if to be more portable --- salt/modules/rabbitmq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/rabbitmq.py b/salt/modules/rabbitmq.py index 8f3f256678c..64d53ac21df 100644 --- a/salt/modules/rabbitmq.py +++ b/salt/modules/rabbitmq.py @@ -72,7 +72,7 @@ def _strip_listing_to_done(output_list): # some versions of rabbitmq have no trailing '...done' line, # which some versions do not output. l_line = ''.join(output_list[-1:]) - if l_line == '...done': + if '...done' in l_line: output_list.pop() return output_list From 3f74a389ce06681a86704ca627445129f29d4427 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 11:05:11 -0600 Subject: [PATCH 33/70] return test results when test=True --- salt/states/reg.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/salt/states/reg.py b/salt/states/reg.py index 8a4c417e502..e7115a2886a 100644 --- a/salt/states/reg.py +++ b/salt/states/reg.py @@ -204,16 +204,14 @@ def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection format(vname if vname else '(Default)', name) return ret - ret['changes'] = {'reg': { - 'Added': { - 'Key': r'{0}\{1}'.format(hive, key), - 'Entry': '{0}'.format(vname if vname else '(Default)'), - 'Value': '{0}'.format(vdata if vdata else '(Empty String)') - }}} + add_change = {'Key': r'{0}\{1}'.format(hive, key), + 'Entry': '{0}'.format(vname if vname else '(Default)'), + 'Value': '{0}'.format(vdata if vdata else '(Empty String)')} # Check for test option if __opts__['test']: ret['result'] = None + ret['changes'] = {'reg': {'Will add': add_change}} return ret # Configure the value @@ -222,7 +220,10 @@ def present(name, value=None, vname=None, vdata=None, vtype='REG_SZ', reflection if not ret['result']: ret['changes'] = {} - ret['comment'] = 'Could not configure the registry key' + ret['comment'] = r'Failed to add {0} to {1}\{2}'.format(name, hive, key) + else: + ret['changes'] = {'reg': {'Added': add_change}} + ret['comment'] = r'Added {0} to {1}\{2}'.format(name, hive, key) return ret @@ -257,23 +258,24 @@ def absent(name, vname=None): ret['comment'] = '{0} is already absent'.format(name) return ret - ret['changes'] = {'reg': { - 'Removed': { - 'Key': r'{0}\{1}'.format(hive, key), - 'Entry': '{0}'.format(vname if vname else '(Default)') - }}} + remove_change = {'Key': r'{0}\{1}'.format(hive, key), + 'Entry': '{0}'.format(vname if vname else '(Default)')} # Check for test option if __opts__['test']: ret['result'] = None + ret['changes'] = {'reg': {'Will remove': remove_change}} return ret # Delete the value ret['result'] = __salt__['reg.delete_value'](hive, key, vname) if not ret['result']: ret['changes'] = {} - ret['comment'] = r'failed to remove {0} from {1}\{2}'.format(name, hive, + ret['comment'] = r'Failed to remove {0} from {1}\{2}'.format(name, hive, key) + else: + ret['changes'] = {'reg': {'Removed': remove_change}} + ret['comment'] = r'Removed {0} from {1}\{2}'.format(name, hive, key) return ret @@ -339,6 +341,6 @@ def key_absent(name, force=False): if __salt__['reg.read_value'](hive, key)['success']: ret['result'] = False ret['changes'] = {} - ret['comment'] = 'failed to remove registry key {0}'.format(name) + ret['comment'] = 'Failed to remove registry key {0}'.format(name) return ret From eb77320786a18bf1f4d4104e57e5d6737cc855bf Mon Sep 17 00:00:00 2001 From: Jeff Quast Date: Thu, 13 Aug 2015 10:44:33 -0700 Subject: [PATCH 34/70] bugfix missing `runas=None' for rabbitmqctl cmds Problem ======= Some rabbitmqctl client commands were executed without honoring the ``runas`` state keyword, resulting in system commands executed as the minion. States that previously succeeded are now failed by parser error traceback when failing to split by expected tabstops output, wheras the output likely contains some error. Solution ======== Forward the ``runas=None`` keyword parameter in the standard pattern for supplementary functions that were introduced by cd0212e8e, ``_check_perms_changes`` and ``_check_tags_changes``. All calls to ``__salt__['rabbtimq.(...)']`` were audited, no further bugs of this pattern found. Example Symptom =============== ``` Failure: rabbitmq_user_|-rabbitmq-user-xxx_|-xxx_|-present: An exception occurred in this state: Traceback (most recent call last): File "/usr/lib/python2.7/site-packages/salt/state.py", line 1561, in call **cdata['kwargs']) File "/usr/lib/python2.7/site-packages/salt/states/rabbitmq_user.py", line 147, in present if _check_tags_changes(name, tags): File "/usr/lib/python2.7/site-packages/salt/states/rabbitmq_user.py", line 70, in _check_tags_changes return __salt__['rabbitmq.list_users']()[name] - set(newtags) File "/usr/lib/python2.7/site-packages/salt/modules/rabbitmq.py", line 116, in list_users return _output_to_dict(res, func) File "/usr/lib/python2.7/site-packages/salt/modules/rabbitmq.py", line 94, in _output_to_dict key, values = row.split('\t', 1) ValueError: need more than 1 value to unpack ``` --- salt/states/rabbitmq_user.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/salt/states/rabbitmq_user.py b/salt/states/rabbitmq_user.py index 535b198bb10..da8556ee7a5 100644 --- a/salt/states/rabbitmq_user.py +++ b/salt/states/rabbitmq_user.py @@ -39,14 +39,14 @@ def __virtual__(): return salt.utils.which('rabbitmqctl') is not None -def _check_perms_changes(name, newperms): +def _check_perms_changes(name, newperms, runas=None): ''' Whether Rabbitmq user's permissions need to be changed ''' if not newperms: return False - existing_perms = __salt__['rabbitmq.list_user_permissions'](name) + existing_perms = __salt__['rabbitmq.list_user_permissions'](name, runas=runas) perm_need_change = False for vhost_perms in newperms: @@ -60,14 +60,14 @@ def _check_perms_changes(name, newperms): return perm_need_change -def _check_tags_changes(name, newtags): +def _check_tags_changes(name, newtags, runas=None): ''' Whether Rabbitmq user's tags need to be changed ''' if newtags: if isinstance(newtags, str): newtags = newtags.split() - return __salt__['rabbitmq.list_users']()[name] - set(newtags) + return __salt__['rabbitmq.list_users'](runas=runas)[name] - set(newtags) else: return [] @@ -144,7 +144,7 @@ def present(name, name, runas=runas) changes['old'] += 'Removed password.\n' - if _check_tags_changes(name, tags): + if _check_tags_changes(name, tags, runas=runas): if __opts__['test']: ret['result'] = None ret['comment'] += ('Tags for user {0} ' @@ -155,7 +155,7 @@ def present(name, ) changes['new'] += 'Set tags: {0}\n'.format(tags) - if _check_perms_changes(name, perms): + if _check_perms_changes(name, perms, runas=runas): if __opts__['test']: ret['result'] = None ret['comment'] += ('Permissions for user {0} ' @@ -164,7 +164,7 @@ def present(name, for vhost_perm in perms: for vhost, perm in vhost_perm.iteritems(): result.update(__salt__['rabbitmq.set_permissions']( - vhost, name, perm[0], perm[1], perm[2], runas) + vhost, name, perm[0], perm[1], perm[2], runas=runas) ) changes['new'] += ( 'Set permissions {0} for vhost {1}' From 1fd6fc6ce3ca5eb521c8631bd83b16f3a38d5dda Mon Sep 17 00:00:00 2001 From: vr-jack Date: Thu, 13 Aug 2015 12:52:41 -0500 Subject: [PATCH 35/70] Keep $HOME from being interpretted by Master shell The command is being sent to a shelled ssh call which allows $HOME to get interpreted by the local shell. This is usually different than the remote user when using sudo (ie, /root vs /home/user) and causes it to fail to find the shim script. Should fix bugs: https://github.com/saltstack/salt/issues/25134 and https://github.com/saltstack/salt/issues/24863 --- salt/client/ssh/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/client/ssh/__init__.py b/salt/client/ssh/__init__.py index 8129561e4c1..d5fa13627e9 100644 --- a/salt/client/ssh/__init__.py +++ b/salt/client/ssh/__init__.py @@ -926,10 +926,10 @@ ARGS = {9}\n'''.format(self.minion_config, pass # Execute shim - ret = self.shell.exec_cmd('/bin/sh $HOME/{0}'.format(target_shim_file)) + ret = self.shell.exec_cmd('/bin/sh \'$HOME/{0}\''.format(target_shim_file)) # Remove shim from target system - self.shell.exec_cmd('rm $HOME/{0}'.format(target_shim_file)) + self.shell.exec_cmd('rm \'$HOME/{0}\''.format(target_shim_file)) return ret From 3348b726c9559c90a59d69cbed7d6da5d4d13c6f Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 11:05:30 -0600 Subject: [PATCH 36/70] fix state/reg unit tests --- tests/unit/states/reg_test.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/tests/unit/states/reg_test.py b/tests/unit/states/reg_test.py index a328a6c85f1..13d2f295b5b 100644 --- a/tests/unit/states/reg_test.py +++ b/tests/unit/states/reg_test.py @@ -43,11 +43,13 @@ class RegTestCase(TestCase): ret = {'name': name, 'changes': {}, 'result': True, - 'comment': '{0} is already configured'.format(name)} + 'comment': '{0} in {1} is already configured'.format(vname, name)} - mock = MagicMock(side_effect=[{'vdata': vdata}, {'vdata': 'a'}, {'vdata': 'a'}]) + mock_read = MagicMock(side_effect=[{'vdata': vdata, 'success': True}, + {'vdata': 'a', 'success': True}, + {'vdata': 'a', 'success': True}]) mock_t = MagicMock(return_value=True) - with patch.dict(reg.__salt__, {'reg.read_value': mock, + with patch.dict(reg.__salt__, {'reg.read_value': mock_read, 'reg.set_value': mock_t}): self.assertDictEqual(reg.present(name, vname=vname, @@ -55,13 +57,19 @@ class RegTestCase(TestCase): with patch.dict(reg.__opts__, {'test': True}): ret.update({'comment': '', 'result': None, - 'changes': {'reg': 'configured to 0.15.3'}}) + 'changes': {'reg': {'Will add': {'Key': name, + 'Entry': vname, + 'Value': vdata}}}}) self.assertDictEqual(reg.present(name, vname=vname, vdata=vdata), ret) with patch.dict(reg.__opts__, {'test': False}): - ret.update({'result': True}) + ret.update({'comment': 'Added {0} to {0}'.format(name), + 'result': True, + 'changes': {'reg': {'Added': {'Key': name, + 'Entry': vname, + 'Value': vdata}}}}) self.assertDictEqual(reg.present(name, vname=vname, vdata=vdata), ret) @@ -80,19 +88,26 @@ class RegTestCase(TestCase): 'result': True, 'comment': '{0} is already absent'.format(name)} - mock = MagicMock(side_effect=[{'success': False}, {'success': True}, {'success': True}]) + mock_read = MagicMock(side_effect=[{'success': False}, + {'success': False}, + {'success': True}, + {'success': True}]) mock_t = MagicMock(return_value=True) - with patch.dict(reg.__salt__, {'reg.read_value': mock, + with patch.dict(reg.__salt__, {'reg.read_value': mock_read, 'reg.delete_value': mock_t}): self.assertDictEqual(reg.absent(name, vname), ret) with patch.dict(reg.__opts__, {'test': True}): ret.update({'comment': '', 'result': None, - 'changes': {'reg': 'Removed {0}'.format(name)}}) + 'changes': {'reg': {'Will remove': {'Entry': vname, + 'Key': name}}}}) self.assertDictEqual(reg.absent(name, vname), ret) with patch.dict(reg.__opts__, {'test': False}): - ret.update({'result': True}) + ret.update({'result': True, + 'changes': {'reg': {'Removed': {'Entry': vname, + 'Key': name}}}, + 'comment': 'Removed {0} from {0}'.format(name)}) self.assertDictEqual(reg.absent(name, vname), ret) From 91ea9645561d3953899069baa0b6dcf8df1611d9 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 11:26:47 -0600 Subject: [PATCH 37/70] add versionadded to reg exec and state mods --- salt/modules/reg.py | 2 ++ salt/states/reg.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/salt/modules/reg.py b/salt/modules/reg.py index e067bbb5c97..1de6f837b1c 100644 --- a/salt/modules/reg.py +++ b/salt/modules/reg.py @@ -443,6 +443,8 @@ def delete_key(hkey, path, key=None, reflection=True, force=False): def delete_key_recursive(hive, key): ''' + .. versionadded:: 2015.5.4 + Delete a registry key to include all subkeys. :param hive: diff --git a/salt/states/reg.py b/salt/states/reg.py index e7115a2886a..9328593e605 100644 --- a/salt/states/reg.py +++ b/salt/states/reg.py @@ -282,6 +282,8 @@ def absent(name, vname=None): def key_absent(name, force=False): r''' + .. versionadded:: 2015.5.4 + Ensure a registry key is removed. This will remove a key and all value entries it contains. It will fail if the key contains subkeys. From 26f5b466f580e4617af68e2b2e1bce6da9c51f2f Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 13:11:28 -0600 Subject: [PATCH 38/70] check for pwd on linux and BSD user exec mods --- salt/modules/pw_user.py | 7 +++++-- salt/modules/useradd.py | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/salt/modules/pw_user.py b/salt/modules/pw_user.py index 4140f8292b1..89eb8374bfd 100644 --- a/salt/modules/pw_user.py +++ b/salt/modules/pw_user.py @@ -6,8 +6,9 @@ Manage users with the useradd command # Import python libs try: import pwd + HAS_PWD = True except ImportError: - pass + HAS_PWD = False import logging import copy @@ -26,7 +27,9 @@ def __virtual__(): ''' Set the user module if the kernel is FreeBSD ''' - return __virtualname__ if __grains__['kernel'] == 'FreeBSD' else False + if HAS_PWD and __grains__['kernel'] == 'FreeBSD': + return __virtualname__ + return False def _get_gecos(name): diff --git a/salt/modules/useradd.py b/salt/modules/useradd.py index 4a81d1f037c..ca5b79c4d8e 100644 --- a/salt/modules/useradd.py +++ b/salt/modules/useradd.py @@ -9,8 +9,9 @@ import re try: import pwd + HAS_PWD = True except ImportError: - pass + HAS_PWD = False import logging import copy @@ -32,10 +33,9 @@ __virtualname__ = 'user' def __virtual__(): ''' Set the user module if the kernel is Linux, OpenBSD or NetBSD - and remove some of the functionality on OS X ''' - if __grains__['kernel'] in ('Linux', 'OpenBSD', 'NetBSD'): + if HAS_PWD and __grains__['kernel'] in ('Linux', 'OpenBSD', 'NetBSD'): return __virtualname__ return False From 7e94989403120e0a8d01b2deaaa0a0f9f0b00ec9 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 13:19:41 -0600 Subject: [PATCH 39/70] mock pwd calls in pw_user exec mod test Fixes #26266. --- tests/unit/modules/pw_user_test.py | 35 +++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/tests/unit/modules/pw_user_test.py b/tests/unit/modules/pw_user_test.py index be25b1b58fb..d409c6c15cd 100644 --- a/tests/unit/modules/pw_user_test.py +++ b/tests/unit/modules/pw_user_test.py @@ -15,7 +15,11 @@ from salttesting.mock import ( # Import Salt Libs from salt.modules import pw_user from salt.exceptions import CommandExecutionError -import pwd +try: + import pwd + HAS_PWD = True +except ImportError: + HAS_PWD = False # Globals @@ -24,6 +28,7 @@ pw_user.__salt__ = {} pw_user.__context__ = {} +@skipIf(not HAS_PWD, 'These tests can only run on systems with the python pwd module') @skipIf(NO_MOCK, NO_MOCK_REASON) class PwUserTestCase(TestCase): ''' @@ -46,16 +51,21 @@ class PwUserTestCase(TestCase): with patch.dict(pw_user.__salt__, {'cmd.run_all': mock}): self.assertTrue(pw_user.delete('A'), 1) - @patch('salt.modules.pw_user.__context__', MagicMock(return_value='A')) def test_getent(self): ''' Test if user.getent already have a value ''' - self.assertTrue(pw_user.getent()) + mock_user = 'saltdude' - mock = MagicMock(return_value='A') - with patch.object(pw_user, 'info', mock): - self.assertEqual(pw_user.getent(True)[0], 'A') + class MockData(object): + pw_name = mock_user + + with patch('pwd.getpwall', MagicMock(return_value=[MockData()])): + with patch.dict(pw_user.__context__, {'user.getent': mock_user}): + self.assertEqual(pw_user.getent(), mock_user) + + with patch.object(pw_user, 'info', MagicMock(return_value=mock_user)): + self.assertEqual(pw_user.getent(True)[0], mock_user) def test_chuid(self): ''' @@ -288,13 +298,22 @@ class PwUserTestCase(TestCase): ''' Return a list of groups the named user belongs to ''' - self.assertEqual(pw_user.list_groups('name'), 'A') + mock_group = 'saltgroup' + + with patch('salt.utils.get_group_list', MagicMock(return_value=[mock_group])): + self.assertEqual(pw_user.list_groups('name'), [mock_group]) def test_list_users(self): ''' Return a list of all users ''' - self.assertTrue(pw_user.list_users()) + mock_user = 'saltdude' + + class MockData(object): + pw_name = mock_user + + with patch('pwd.getpwall', MagicMock(return_value=[MockData()])): + self.assertEqual(pw_user.list_users(), [mock_user]) def test_rename(self): ''' From 1e3f33a03c1d861b403f1363a7896d5d248f9664 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Thu, 13 Aug 2015 14:32:17 -0600 Subject: [PATCH 40/70] autogenerated 2015.5.4 release notes --- doc/topics/releases/2015.5.4.rst | 1827 +++++++++++++++++++++++++++++- 1 file changed, 1825 insertions(+), 2 deletions(-) diff --git a/doc/topics/releases/2015.5.4.rst b/doc/topics/releases/2015.5.4.rst index 77f43878d0e..23695bec73a 100644 --- a/doc/topics/releases/2015.5.4.rst +++ b/doc/topics/releases/2015.5.4.rst @@ -2,8 +2,6 @@ Salt 2015.5.4 Release Notes =========================== -:release: TBA - Version 2015.5.4 is a bugfix release for :doc:`2015.5.0 `. @@ -17,3 +15,1828 @@ Changes: - The ``vmware`` Salt-Cloud driver was back-ported from the develop branch in order for installations of Salt that are older than 2015.8.0 to be able to use the ``vmware`` driver without stack-tracing on various deprecation paths that were implemented in the 2015.8.0 release. + +Changes for v2015.5.3..v2015.5.4 +-------------------------------- + +Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs): + +*Generated at: 2015-08-13T20:23:30Z* + +Statistics: + +- Total Merges: **247** +- Total Issue references: **140** +- Total PR references: **330** + +Changes: + +- **PR** `#26292`_: (*jquast*) Rabbitmq 3.2.4 on Ubuntu has "...done.", not "...done" + @ *2015-08-13T19:53:29Z* + +- **PR** `#26296`_: (*jquast*) bugfix missing `runas=None' for rabbitmqctl cmds (backport to 2015.5) + @ *2015-08-13T19:52:40Z* + +- **PR** `#26293`_: (*jfindlay*) Fix `#26268`_ + @ *2015-08-13T19:48:06Z* + + - **ISSUE** `#25618`_: (*twangboy*) Fix reg.py to work with the registry properly + | refs: `#26268`_ + - **PR** `#26268`_: (*twangboy*) Multiple improvements to reg executionmod and state mod + | refs: `#26293`_ + +- **PR** `#26290`_: (*rallytime*) Only call convert_to_arn when action name is provided + @ *2015-08-13T18:48:58Z* + + - **ISSUE** `#25192`_: (*deuscapturus*) 2015.5.2 boto_cloudwatch_alarm.present not working. + | refs: `#26290`_ + +- **PR** `#26288`_: (*bbinet*) allow to delete grains which value is False + @ *2015-08-13T18:24:36Z* + +- **PR** `#26263`_: (*rallytime*) Don't make changes when test=True for openstack present/absent funcs + @ *2015-08-13T16:30:31Z* + + - **ISSUE** `#24882`_: (*nmadhok*) salt.states.openstack_config.present and salt.states.openstack_config.absent make changes when test=True + | refs: `#26263`_ + +- **PR** `#26265`_: (*rallytime*) Don't stacktrace on query return in ec2.create_snapshot + @ *2015-08-13T16:28:48Z* + + - **ISSUE** `#24484`_: (*codehotter*) clouds/ec2.py: create_snapshot throws exception + | refs: `#26265`_ + +- **PR** `#26285`_: (*stanislavb*) Remove explicit version from instance identity URL + @ *2015-08-13T16:25:32Z* + +- **PR** `#26275`_: (*cachedout*) Re-init modules on multi-master reconnect + @ *2015-08-13T15:52:50Z* + +- **PR** `#26273`_: (*garethgreenaway*) Fixes to schedule module in 2015.5 + @ *2015-08-13T15:34:43Z* + +- **PR** `#26271`_: (*rallytime*) Fix del_root_vol_on_destroy and del_all_vols_on_destroy functionality on ec2 + @ *2015-08-12T23:22:47Z* + + - **ISSUE** `#24483`_: (*codehotter*) clouds/ec2.py: del_root_vol_on_destroy and del_all_vols_on_destroy not working + | refs: `#26271`_ + +- **PR** `#26219`_: (*anlutro*) cron: make identifier default to state ID + @ *2015-08-12T18:42:33Z* + + - **ISSUE** `#25958`_: (*anlutro*) Cron identifier does not default to state ID as documented + | refs: `#26219`_ + +- **PR** `#26257`_: (*rallytime*) Back-port `#26237`_ to 2015.5 + @ *2015-08-12T18:40:35Z* + + - **ISSUE** `#26207`_: (*fullermd*) group members setting fails with obscure error message on FreeBSD + | refs: `#26237`_ + - **PR** `#26237`_: (*silenius*) fix issue `#26207`_ + | refs: `#26257`_ + +- **PR** `#26258`_: (*nmadhok*) Fix permission on tests/runtests.py on 2015.5 branch + @ *2015-08-12T18:40:04Z* + +- **PR** `#26261`_: (*nmadhok*) Correct spelling of integration in docs + @ *2015-08-12T18:14:48Z* + + - **PR** `#2015`_: (*thekuffs*) Esky / bbfreeze support + +- **PR** `#26247`_: (*nmadhok*) Initial commit of unit tests for vmware cloud driver + @ *2015-08-12T16:58:24Z* + +- **PR** `#26246`_: (*nmadhok*) Backport additions to VMware cloud driver from develop to 2015.5 branch + @ *2015-08-12T15:11:26Z* + +- **PR** `#26239`_: (*opdude*) Fixed documentation to match function name + @ *2015-08-12T14:48:52Z* + +- **PR** `#26232`_: (*garethgreenaway*) Fix to trust_key in gpg module for 2015.5. + @ *2015-08-12T04:48:27Z* + +- **PR** `#26084`_: (*twangboy*) Added python_shell=True, quoted user input + @ *2015-08-10T21:29:35Z* + + - **ISSUE** `#25802`_: (*jefftucker*) Running module "npm.list" fails on Windows for masterless minion + | refs: `#26084`_ + +- **PR** `#26183`_: (*cro*) Fix LDAP configuration issue. + @ *2015-08-10T19:09:41Z* + +- **PR** `#26186`_: (*jacobhammons*) regenerated man pages + @ *2015-08-10T19:07:44Z* + +- **PR** `#26182`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5 + @ *2015-08-10T19:00:10Z* + + - **ISSUE** `#25961`_: (*getabc*) [2015.5.3-2] salt-winrepo.git/salt-minion.sls fails certificate '*.wpengine.com' or 'wpengine.com' + | refs: `#26047`_ + - **ISSUE** `#25751`_: (*basepi*) Document `master_finger` more prominently + | refs: `#26088`_ + - **PR** `#26116`_: (*corux*) file.replace fails if repl string is an invalid regex and append/prepend is used + - **PR** `#26088`_: (*jacobhammons*) Master finger + - **PR** `#26047`_: (*jacobhammons*) Updated windows download links in the docs to https://repo.saltstack.com + +- **PR** `#26000`_: (*driskell*) Implement full event caching for subscribed tags + @ *2015-08-10T18:57:17Z* + + - **ISSUE** `#25998`_: (*driskell*) Event subsystem discarding required events during --batch breaking it for slow running commands + | refs: `#26000`_ + +- **PR** `#26175`_: (*rallytime*) Back-port `#26153`_ to 2015.5 + @ *2015-08-10T18:22:32Z* + + - **PR** `#26153`_: (*loa*) Fix dockerio state documentation typo + | refs: `#26175`_ + +- **PR** `#26177`_: (*rallytime*) Back-port `#26147`_ to 2015.5 + @ *2015-08-10T18:22:01Z* + + - **ISSUE** `#26024`_: (*jpic*) lxc_conf_unset in cloud.profile is ignored + - **PR** `#26147`_: (*martinhoefling*) Fixes `#26024`_ + | refs: `#26177`_ + +- **PR** `#26179`_: (*rallytime*) Back-port `#25404`_ to 2015.5 + @ *2015-08-10T18:21:50Z* + + - **ISSUE** `#21082`_: (*clinta*) master_type failover does not failover on DNS errors + | refs: `#25404`_ + - **PR** `#25404`_: (*DmitryKuzmenko*) Fixed minion failover to next master on DNS errors. + | refs: `#26179`_ + +- **PR** `#26180`_: (*jfindlay*) fix processing of state.template + @ *2015-08-10T18:21:38Z* + + - **ISSUE** `#26112`_: (*wt*) state.template fails with unclear error with template with only an include + | refs: `#26180`_ + +- **PR** `#26172`_: (*nmadhok*) [Backport] Make sure variable is a dictionary before popping something from it. + @ *2015-08-10T16:42:50Z* + + - **ISSUE** `#26162`_: (*nmadhok*) VMware cloud driver create function failing with traceback on latest develop + | refs: `#26163`_ `#26172`_ + - **PR** `#26163`_: (*nmadhok*) Make sure variable is a dictionary before popping something from it. + +- **PR** `#26168`_: (*cachedout*) Fix slack docs + @ *2015-08-10T14:57:18Z* + + - **ISSUE** `#26098`_: (*rdinoff*) SALT.STATES.SLACK Doc update + | refs: `#26168`_ + +- **PR** `#26127`_: (*garethgreenaway*) Fixes to salt.utils.http related to cp.get_file_str bug. + @ *2015-08-10T14:38:25Z* + + - **ISSUE** `#24106`_: (*nvx*) fileclient.py#get_url ignores HTTP Auth again (2015.5 regression) + | refs: `#26127`_ + +- **PR** `#26140`_: (*nmadhok*) VMware cloud driver fixes + @ *2015-08-10T13:15:58Z* + + - **ISSUE** `#26141`_: (*nmadhok*) salt-cloud VMware driver fails with error in parsing configuration file + | refs: `#26140`_ + - **ISSUE** `#25809`_: (*o-sleep*) vmware cloud module error message + | refs: `#26140`_ + - **ISSUE** `#25625`_: (*steverweber*) cloud vmware driver does not provide mac_address unless vmware tools is running + | refs: `#26137`_ `#26140`_ + +- **PR** `#26137`_: (*steverweber*) use device mac address if vmtools not active + @ *2015-08-09T03:05:36Z* + + - **ISSUE** `#25625`_: (*steverweber*) cloud vmware driver does not provide mac_address unless vmware tools is running + | refs: `#26137`_ `#26140`_ + +- **PR** `#26119`_: (*jodv*) Backport eauth bugfix to 2015.5 + @ *2015-08-09T02:19:52Z* + +- **PR** `#26135`_: (*cro*) Fix proxy minions in 2015.5 and significantly update documentation. + @ *2015-08-09T02:19:21Z* + +- **PR** `#26132`_: (*TheBigBear*) minor edit + @ *2015-08-08T21:05:34Z* + +- **PR** `#26133`_: (*amontalban*) Fixed `#25915`_ in salt/modules/pkgng.py and salt/states/pkg.py + @ *2015-08-08T21:05:05Z* + + - **ISSUE** `#25915`_: (*ari*) FreeBSD pkg install fails + +- **PR** `#26111`_: (*anlutro*) Better error messages when virtualenv creation fails + @ *2015-08-07T21:42:09Z* + +- **PR** `#26110`_: (*jfindlay*) check for sources before adding them to cmd str + @ *2015-08-07T21:33:23Z* + + - **ISSUE** `#26093`_: (*freedba*) archive.tar bug + | refs: `#26110`_ + +- **PR** `#26106`_: (*vr-jack*) Update __init__.py + @ *2015-08-07T21:15:55Z* + +- **PR** `#26101`_: (*rallytime*) Back-port `#25984`_ to 2015.5 + @ *2015-08-07T18:56:26Z* + + - **ISSUE** `#25983`_: (*jmdcal*) Trying to get md5 of local zip + | refs: `#25984`_ + - **PR** `#25984`_: (*jmdcal*) Support local files without md5sum + | refs: `#26101`_ + +- **PR** `#26080`_: (*techhat*) Fix string checking in s3fs + @ *2015-08-06T23:36:09Z* + +- **PR** `#26079`_: (*cachedout*) Update docs to remove state.over + @ *2015-08-06T23:35:26Z* + + - **ISSUE** `#26039`_: (*basepi*) Update scheduler docs to use orchestrate instead of overstate + | refs: `#26079`_ + +- **PR** `#26058`_: (*opdude*) Fix choco version on chocolatey versions below 0.9.9 + @ *2015-08-06T18:50:10Z* + +- **PR** `#26068`_: (*jfindlay*) fix autoruns.list looking in wrong directory + @ *2015-08-06T18:49:48Z* + +- **PR** `#26065`_: (*s0undt3ch*) [2015.5] Update to latest bootstrap stable release v2015.06.08 + @ *2015-08-06T17:09:35Z* + + - **ISSUE** `#634`_: (*loupgaroublond*) /srv/salt/_grains/ not documented + | refs: `#26065`_ + - **ISSUE** `#631`_: (*fatbox*) Can't extend the same item multiple times + | refs: `#26065`_ + - **ISSUE** `#625`_: (*whiteinge*) `cmd.run` state `user` flag is not working + | refs: `#25506`_ `#632`_ + - **PR** `#640`_: (*terminalmage*) fix syntax errors introduced in 0f776c13 + | refs: `#26065`_ + - **PR** `#638`_: (*blast-hardcheese*) Tightened up configuration documentation + | refs: `#26065`_ + - **PR** `#633`_: (*epoelke*) Bug fix to salt-key + | refs: `#26065`_ + - **PR** `#632`_: (*whiteinge*) Change the ``cmd.run`` state to use the new ``runas`` arg + | refs: `#26065`_ + +- **PR** `#26061`_: (*gmcwhistler*) Patch for issue `#25994`_ + @ *2015-08-06T17:07:34Z* + + - **ISSUE** `#25994`_: (*gmcwhistler*) module.ilo tempfile creation in __execute_cmd results in TypeError: cannot concatenate 'str' and 'int' objects + +- **PR** `#26064`_: (*s0undt3ch*) Don't stacktrace when trying to get the default locale. + @ *2015-08-06T16:11:05Z* + + - **ISSUE** `#26063`_: (*saltstack-bot*) not working with salt-cloud shows unknown locale error + | refs: `#26064`_ + +- **PR** `#26048`_: (*jacobhammons*) Updated windows download links in the docs to https://repo.saltstack.com + @ *2015-08-05T22:59:50Z* + +- **PR** `#26044`_: (*rallytime*) Make sure the key we're comparing is also lowercase + @ *2015-08-05T19:23:54Z* + + - **ISSUE** `#25616`_: (*rallytime*) [2015.5] Provisioning Linodes Stacktraces + | refs: `#26044`_ + +- **PR** `#26042`_: (*jfindlay*) fix test mode logic in state docs + @ *2015-08-05T19:23:07Z* + +- **PR** `#26036`_: (*nicholascapo*) survey.hash: Remove manually printed text + @ *2015-08-05T19:21:59Z* + + - **ISSUE** `#24460`_: (*nicholascapo*) Survey runner does not follow `--out` flag + | refs: `#26036`_ + +- **PR** `#26030`_: (*opdude*) Fix a bug in choco version that returned odd data + @ *2015-08-05T16:30:25Z* + +- **PR** `#26032`_: (*jfindlay*) add test logic to state reult doc + @ *2015-08-05T16:28:32Z* + +- **PR** `#26031`_: (*alekti*) Revert "Add file as supported protocol for file source_hash. Fixes `#23764`_" + @ *2015-08-05T15:32:01Z* + + - **ISSUE** `#23764`_: (*es1o*) source_hash from local file is not supported. + | refs: `#25750`_ + +- **PR** `#26021`_: (*anlutro*) Documentation: Specify versionadded for git.present shared argument + @ *2015-08-05T14:17:38Z* + +- **PR** `#26020`_: (*alekti*) Correctly resolve conflict merging pull 25750 to 2015.5 + @ *2015-08-05T14:16:58Z* + + - **ISSUE** `#23764`_: (*es1o*) source_hash from local file is not supported. + | refs: `#25750`_ + - **PR** `#25750`_: (*alekti*) Add file as supported protocol for file source_hash. Fixes `#25701`_. + | refs: `#26020`_ + +- **PR** `#26016`_: (*basepi*) Revert "Deep merge of pillar lists" + @ *2015-08-05T04:59:52Z* + + - **ISSUE** `#22241`_: (*masterkorp*) Salt master not properly generating the map + | refs: `#25358`_ + - **PR** `#25358`_: (*dkiser*) Deep merge of pillar lists + | refs: `#26016`_ + +- **PR** `#25992`_: (*twangboy*) Refactor win_system.py + @ *2015-08-05T04:54:18Z* + + - **ISSUE** `#12255`_: (*eliasp*) 'system.set_computer_desc' fails with non-ASCII chars + | refs: `#25992`_ + - **ISSUE** `#3`_: (*thatch45*) libvirt module + +- **PR** `#26002`_: (*twangboy*) Fixed regex to account for comment character followed by whitespace + @ *2015-08-04T22:28:11Z* + + - **ISSUE** `#25948`_: (*twangboy*) Fix uncomment function to handle spaces + | refs: `#26002`_ + +- **PR** `#25970`_: (*jfindlay*) accept addition of layman overlay + @ *2015-08-04T15:42:28Z* + + - **ISSUE** `#25949`_: (*godlike64*) layman.add does not work with unofficial overlays + | refs: `#25970`_ + +- **PR** `#25971`_: (*basepi*) [2015.5] salt.modules.reg Add spaces for strings split across multiple lines + @ *2015-08-04T15:39:48Z* + +- **PR** `#25990`_: (*rallytime*) Back-port `#25976`_ to 2015.5 + @ *2015-08-04T14:36:53Z* + + - **PR** `#25976`_: (*fleaflicker*) Typo in help output + | refs: `#25990`_ + +- **PR** `#25996`_: (*attiasr*) fix msiexec package remove + @ *2015-08-04T14:36:31Z* + +- **PR** `#25966`_: (*rallytime*) Back-port `#25864`_ to 2015.5 + @ *2015-08-03T18:48:26Z* + + - **ISSUE** `#25863`_: (*peterdemin*) pkg.installed fails on already installed package if it is in versionlock.list + | refs: `#25864`_ + - **PR** `#25864`_: (*peterdemin*) `#25863`_ state.pkg.installed fix + | refs: `#25966`_ + +- **PR** `#25967`_: (*rallytime*) Back-port `#25917`_ to 2015.5 + @ *2015-08-03T18:48:02Z* + + - **PR** `#25917`_: (*jmdcal*) adding missing format string + | refs: `#25967`_ + +- **PR** `#25895`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5 + @ *2015-08-03T17:12:37Z* + + - **ISSUE** `#23764`_: (*es1o*) source_hash from local file is not supported. + | refs: `#25750`_ + - **PR** `#25750`_: (*alekti*) Add file as supported protocol for file source_hash. Fixes `#25701`_. + | refs: `#26020`_ + - **PR** `#25704`_: (*cachedout*) Ensure prior alignment with master_type in 2014.7 + - **PR** `#25657`_: (*MrCitron*) Add the ability to specify a base pattern for carbon returner + - **PR** `#25633`_: (*AkhterAli*) Update loader.py + +- **PR** `#25941`_: (*jfindlay*) add timelib to dependency versions + @ *2015-08-03T12:23:42Z* + + - **ISSUE** `#25850`_: (*ssgward*) Need to add packages to --versions-report + | refs: `#25941`_ + +- **PR** `#25951`_: (*garethgreenaway*) Log when event.fire and event.fire_master fail. + @ *2015-08-03T00:19:45Z* + +- **PR** `#25942`_: (*jfindlay*) typo in minion doc + @ *2015-07-31T23:34:55Z* + + - **ISSUE** `#25838`_: (*grep4linux*) docs disable_modules documentation typo + | refs: `#25942`_ + +- **PR** `#25938`_: (*jacobhammons*) Doc on using syndic with multimaster + @ *2015-07-31T23:05:05Z* + + - **PR** `#14690`_: (*jacksontj*) Multi syndic + | refs: `#25938`_ + +- **PR** `#25848`_: (*twangboy*) Added allusers="1" when installing msi + @ *2015-07-31T20:33:17Z* + + - **ISSUE** `#25839`_: (*twangboy*) ALLUSERS="1" should be a default when installing MSI's + | refs: `#25848`_ + +- **PR** `#25898`_: (*jfindlay*) clarify and expand syndic docs + @ *2015-07-31T20:01:23Z* + +- **PR** `#25927`_: (*jacksontj*) Pass actual renderers to the Reactor's Compiler + @ *2015-07-31T20:00:17Z* + + - **ISSUE** `#25852`_: (*UtahDave*) Salt loader is not loading Salt vars in reactor python renderer + | refs: `#25927`_ + +- **PR** `#25921`_: (*cachedout*) Handle non-ascii in state log + @ *2015-07-31T17:41:30Z* + + - **ISSUE** `#25810`_: (*nvx*) winpkg highstate fails when a new package name contains a unicide character + | refs: `#25921`_ + +- **PR** `#25919`_: (*TheBigBear*) Minor update to msi un-installer info + @ *2015-07-31T17:39:48Z* + +- **PR** `#25905`_: (*rallytime*) Back-port `#25982`_ to 2015.5 + @ *2015-07-30T23:24:19Z* + + - **PR** `#25892`_: (*TheBigBear*) Update 7-zip msi un-installer instructions + | refs: `#25905`_ + +- **PR** `#25890`_: (*rallytime*) Back-port `#25698`_ to 2015.5 + @ *2015-07-30T23:12:09Z* + + - **ISSUE** `#25577`_: (*yellow1912*) Wrong indentation in document + | refs: `#25696`_ + - **PR** `#25698`_: (*rallytime*) Back-port `#25659`_ to 2015.8 + | refs: `#25890`_ + - **PR** `#25696`_: (*AkhterAli*) Update schedule.py + - **PR** `#25659`_: (*isbm*) Bugfix: crash at getting non-existing repo + | refs: `#25698`_ + +- **PR** `#25894`_: (*jacobhammons*) Minor doc bug fixes + @ *2015-07-30T23:02:34Z* + + - **ISSUE** `#25650`_: (*jacksontj*) state.running documentation is incorrect + | refs: `#25894`_ + - **ISSUE** `#24042`_: (*whiteinge*) The state_events setting is not documented + | refs: `#25894`_ + - **ISSUE** `#23788`_: (*k5jj*) functions in drac.py module do not match documentation + | refs: `#25894`_ + - **ISSUE** `#21296`_: (*Lothiraldan*) Possible minion enumeration using saltutil.find_job and eauth + | refs: `#25894`_ + +- **PR** `#25877`_: (*rallytime*) Protect against passing a map file in addition to VM names with --destroy + @ *2015-07-30T21:55:45Z* + + - **ISSUE** `#24036`_: (*arthurlogilab*) [salt-cloud] Protect against passing command line arguments as names for the --destroy command in map files + | refs: `#25877`_ + +- **PR** `#25870`_: (*rallytime*) Back-port `#25824`_ to 2015.5 + @ *2015-07-30T21:54:35Z* + + - **PR** `#25824`_: (*klyr*) Fix get_managed() in file.py module for local files + | refs: `#25870`_ + +- **PR** `#25885`_: (*t0rrant*) Update Debian changelog + @ *2015-07-30T20:05:59Z* + +- **PR** `#25875`_: (*rallytime*) Back-port `#25862`_ to 2015.5 + @ *2015-07-30T17:34:02Z* + + - **ISSUE** `#25478`_: (*zyio*) salt-ssh - Unable to locate current thin version + | refs: `#25862`_ + - **ISSUE** `#25026`_: (*sylvia-wang*) salt-ssh "Failure deploying thin" when using salt module functions + | refs: `#25862`_ + - **PR** `#25862`_: (*zyio*) Adding SCP_NOT_FOUND exit code + | refs: `#25875`_ + +- **PR** `#25873`_: (*rallytime*) Back-port `#25855`_ to 2015.5 + @ *2015-07-30T17:33:55Z* + + - **PR** `#25855`_: (*puneetk*) Patch 3 + | refs: `#25873`_ + +- **PR** `#25871`_: (*rallytime*) Back-port `#25829`_ to 2015.5 + @ *2015-07-30T17:33:43Z* + + - **PR** `#25829`_: (*peterdemin*) Fixed typo in salt.states.saltmod.function doc string + | refs: `#25871`_ + +- **PR** `#25869`_: (*rallytime*) Back-port `#25788`_ to 2015.5 + @ *2015-07-30T17:33:33Z* + + - **ISSUE** `#24002`_: (*csakoda*) File lock contention on windows minions causing highstate crash + | refs: `#25788`_ + - **PR** `#25788`_: (*opdude*) Catch a hard crash when running highstate on windows + | refs: `#25869`_ + +- **PR** `#25853`_: (*davidjb*) Make ssh-id-wrapper accessible to non-root users + @ *2015-07-30T16:49:47Z* + + - **ISSUE** `#19532`_: (*stolendog*) salt-ssh running git clone with not root user + | refs: `#25853`_ + +- **PR** `#25856`_: (*jfindlay*) expand minion reauth scalability documentation + @ *2015-07-30T15:33:17Z* + + - **ISSUE** `#25447`_: (*spo0nman*) SaltMaster is crippled with Minion Re-Authentication + | refs: `#25856`_ + +- **PR** `#25840`_: (*jfindlay*) add note to winrepo state docs about required grain + @ *2015-07-30T14:38:27Z* + + - **ISSUE** `#25801`_: (*themalkolm*) Update docs that salt.states.winrepo requires `roles:salt-master` in grains. + | refs: `#25840`_ + +- **PR** `#25846`_: (*jfindlay*) rework deprecation documentation for release names + @ *2015-07-30T13:26:21Z* + + - **ISSUE** `#25827`_: (*0xf10e*) "Deprecating Code" doesn't mention Usage of warn_until() w/ Release Names + | refs: `#25846`_ + +- **PR** `#25833`_: (*jahamn*) Allows cp.push to recreate empty files + @ *2015-07-29T16:14:48Z* + + - **ISSUE** `#23288`_: (*UtahDave*) cp.push fails to recreate empty files. + | refs: `#25833`_ + +- **PR** `#25831`_: (*rallytime*) Add salt:// to key_url options to docs for pkgrepo.managed + @ *2015-07-29T15:38:43Z* + + - **ISSUE** `#11474`_: (*JensRantil*) pkgrepo.managed key_url: salt:// always use `base` env + | refs: `#25831`_ + +- **PR** `#25807`_: (*rallytime*) Provide helpful error when using actions with a mapfile + @ *2015-07-29T15:30:15Z* + + - **ISSUE** `#22699`_: (*arthurlogilab*) salt-cloud fails on KeyError when given a nonexistant action + | refs: `#25807`_ + +- **PR** `#25818`_: (*jfindlay*) fix autoruns list + @ *2015-07-29T15:29:20Z* + +- **PR** `#25826`_: (*anlutro*) Check that "onchanges" is a list + @ *2015-07-29T15:00:28Z* + +- **PR** `#25798`_: (*twangboy*) Fixed stacktrace on package name not found + @ *2015-07-28T22:40:14Z* + + - **ISSUE** `#25258`_: (*nickw8*) windows minion repo not updating + | refs: `#25798`_ + +- **PR** `#25797`_: (*twangboy*) Changed repocache back to cached_repo + @ *2015-07-28T22:39:32Z* + + - **ISSUE** `#25437`_: (*lorengordon*) Stacktrace on Windows when running pkg.list_pkgs + | refs: `#25598`_ `#25763`_ + - **PR** `#25763`_: (*twangboy*) Fix 25437 + | refs: `#25797`_ + +- **PR** `#25793`_: (*rallytime*) Back-port `#25730`_ to 2015.5 + @ *2015-07-28T19:37:34Z* + + - **PR** `#25730`_: (*sjorge*) patchelf lives in pkgsrc + | refs: `#25793`_ + +- **PR** `#25792`_: (*rallytime*) Back-port `#25688`_ to 2015.5 + @ *2015-07-28T19:37:17Z* + + - **PR** `#25688`_: (*bclermont*) Don't acquire lock if there is no formatter + | refs: `#25792`_ + +- **PR** `#25796`_: (*cachedout*) Remove debug from docs + @ *2015-07-28T17:35:59Z* + +- **PR** `#25749`_: (*jahamn*) Allow zpool.create on character devices + @ *2015-07-28T16:01:40Z* + + - **ISSUE** `#24920`_: (*voileux*) module.zpool.create on character device is not possible by salt + | refs: `#25749`_ + +- **PR** `#25685`_: (*twangboy*) Fixed regex issues with comment and uncomment + @ *2015-07-28T15:29:49Z* + +- **PR** `#25763`_: (*twangboy*) Fix 25437 + | refs: `#25797`_ + @ *2015-07-28T15:29:27Z* + + - **ISSUE** `#25437`_: (*lorengordon*) Stacktrace on Windows when running pkg.list_pkgs + | refs: `#25598`_ `#25763`_ + +- **PR** `#25752`_: (*thatch45*) State top saltenv + @ *2015-07-28T01:02:10Z* + +- **PR** `#25755`_: (*twangboy*) Fixed problem with dunder functions not being passed + @ *2015-07-27T19:31:22Z* + + - **ISSUE** `#25717`_: (*twangboy*) Problem with chocolatey module not loading + | refs: `#25755`_ + +- **PR** `#25648`_: (*twangboy*) Clarified functionality of reg module, fixed state to work with new module + @ *2015-07-27T19:30:33Z* + + - **ISSUE** `#25352`_: (*m03*) reg.absent reporting incorrect results + | refs: `#25648`_ + - **ISSUE** `#1`_: (*thatch45*) Enable regex on the salt cli + +- **PR** `#25740`_: (*rallytime*) Back-port `#25722`_ to 2015.5 + @ *2015-07-27T16:08:40Z* + + - **ISSUE** `#25154`_: (*uvsmtid*) All data mixed on STDOUT together should generate valid JSON output + | refs: `#25722`_ + - **ISSUE** `#25153`_: (*uvsmtid*) Multiple results should generate valid JSON output + | refs: `#25722`_ + - **PR** `#25722`_: (*uvsmtid*) Minor docs changes to emphasize JSON output problems without `--static` option + | refs: `#25740`_ + +- **PR** `#25739`_: (*rallytime*) Back-port `#25709`_ to 2015.5 + @ *2015-07-27T16:08:27Z* + + - **PR** `#25709`_: (*colekowalski*) add direct-io-mode to mount_invisible_options + | refs: `#25739`_ + - **PR** `#25699`_: (*rallytime*) Back-port `#25660`_ to 2015.5 + | refs: `#25709`_ + - **PR** `#25660`_: (*colekowalski*) add glusterfs' direct-io-mode to mount_invisible_keys + | refs: `#25699`_ `#25709`_ + +- **PR** `#25738`_: (*rallytime*) Back-port `#25671`_ to 2015.5 + @ *2015-07-27T16:08:23Z* + + - **PR** `#25671`_: (*niq000*) added a parameter so verifying SSL is now optional instead of hard-coded + | refs: `#25738`_ + +- **PR** `#25737`_: (*rallytime*) Back-port `#25608`_ to 2015.5 + @ *2015-07-27T16:08:18Z* + + - **ISSUE** `#25229`_: (*rall0r*) Module git.latest kills target directory when test=True + | refs: `#25608`_ + - **PR** `#25608`_: (*rall0r*) Fix: prevent git.latest from removing target + | refs: `#25737`_ + +- **PR** `#25733`_: (*davidjb*) Avoid IndexError when listing mounts if mount output ends in newline + @ *2015-07-27T16:08:05Z* + +- **PR** `#25705`_: (*blackduckx*) Support for setm augeas command. + @ *2015-07-27T16:07:10Z* + + - **ISSUE** `#22460`_: (*onmeac*) Command setm is not supported (yet) + | refs: `#25705`_ + +- **PR** `#25703`_: (*cachedout*) Return to `str` for master_type for 2015.5 + @ *2015-07-27T16:06:22Z* + +- **PR** `#25702`_: (*twangboy*) Fixed win_user module for groups with spaces in the name + @ *2015-07-27T15:06:33Z* + + - **ISSUE** `#25144`_: (*johnccfm*) user.present on Windows fails to add user to groups if group name contains a space + | refs: `#25702`_ + +- **PR** `#25711`_: (*twangboy*) Fixed problem with win_servermanager.list_installed + @ *2015-07-27T15:05:48Z* + + - **ISSUE** `#25351`_: (*m03*) win_servermanager.list_installed failing with "IndexError: list index out of range" + | refs: `#25711`_ + +- **PR** `#25714`_: (*cachedout*) Display warning when progressbar can't be loaded + @ *2015-07-25T00:10:13Z* + + - **ISSUE** `#25435`_: (*yee379*) progressbar dependency missing + | refs: `#25714`_ + +- **PR** `#25699`_: (*rallytime*) Back-port `#25660`_ to 2015.5 + | refs: `#25709`_ + @ *2015-07-24T22:11:40Z* + + - **PR** `#25660`_: (*colekowalski*) add glusterfs' direct-io-mode to mount_invisible_keys + | refs: `#25699`_ `#25709`_ + +- **PR** `#25694`_: (*s0undt3ch*) Salt-SSH fix for `#25689`_ + @ *2015-07-24T21:41:57Z* + + - **ISSUE** `#25689`_: (*anlutro*) Minion log in salt-ssh + | refs: `#25694`_ + +- **PR** `#25710`_: (*jahamn*) Integration Testcase for Issue 25250 + @ *2015-07-24T20:57:33Z* + + - **ISSUE** `#25250`_: (*wipfs*) 'force' option in copy state deletes target file + | refs: `#25461`_ `#25710`_ + +- **PR** `#25680`_: (*basepi*) [2015.5] Move cmd.run jinja aliasing to a wrapper class to prevent side effects + @ *2015-07-24T19:52:10Z* + + - **PR** `#25049`_: (*terminalmage*) Fix cmd.run when cross-called in a state/execution module + | refs: `#25680`_ + +- **PR** `#25682`_: (*basepi*) [2015.5] Fix parsing args with just a hash (#) + @ *2015-07-24T19:52:01Z* + +- **PR** `#25695`_: (*stanislavb*) Configurable AWS region & region from IAM metadata + @ *2015-07-24T19:36:40Z* + +- **PR** `#25645`_: (*kev009*) Fix pkgng provider to work with a sources list and the underlying pkg… + @ *2015-07-24T16:33:18Z* + +- **PR** `#25677`_: (*aneeshusa*) Fix pacman.list_upgrades when refresh=True. + @ *2015-07-24T16:30:06Z* + +- **PR** `#25675`_: (*UtahDave*) Use OS line endings with contents on file.managed + @ *2015-07-24T16:29:50Z* + + - **ISSUE** `#25674`_: (*UtahDave*) file.managed with contents parameter uses wrong line endings on Windows + | refs: `#25675`_ + +- **PR** `#25676`_: (*basepi*) Update release candidate docs to 2015.8.0rc2 + @ *2015-07-23T20:29:37Z* + +- **PR** `#25666`_: (*nmadhok*) Check if the properties exist before looping over them causing KeyError + @ *2015-07-23T17:55:40Z* + + - **ISSUE** `#25665`_: (*nmadhok*) salt-cloud VMware driver fails with KeyErrors if there's any existing machine in the VMware infrastructure in (invalid state) + | refs: `#25666`_ + +- **PR** `#25656`_: (*anlutro*) Fix locale detection in debian/gentoo + @ *2015-07-23T16:46:40Z* + +- **PR** `#25661`_: (*rallytime*) Back-port `#25624`_ to 2015.5 + @ *2015-07-23T16:26:48Z* + + - **PR** `#25624`_: (*bobrik*) Fix typo in get_routes example for debian_ip + | refs: `#25661`_ + +- **PR** `#25662`_: (*rallytime*) Back-port `#25638`_ to 2015.5 + @ *2015-07-23T16:26:40Z* + + - **ISSUE** `#15209`_: (*hubez*) file.manage: source_hash not working with s3:// (2014.7.0rc1) + | refs: `#25638`_ + - **PR** `#25638`_: (*TronPaul*) fix bad merge in 99fc7ec + | refs: `#25662`_ + +- **PR** `#25644`_: (*cachedout*) pillar doc fix + @ *2015-07-22T22:57:23Z* + + - **ISSUE** `#25413`_: (*zizkebab*) pillar_opts default behavior is not reflected in the docs + | refs: `#25644`_ + +- **PR** `#25642`_: (*cachedout*) Warn on pillar schedule delete + @ *2015-07-22T22:04:12Z* + + - **ISSUE** `#25540`_: (*dennisjac*) salt highstate schedule cannot be removed + | refs: `#25642`_ + +- **PR** `#25598`_: (*twangboy*) Fixed problem trying to load file with name of boolean type + @ *2015-07-22T17:07:49Z* + + - **ISSUE** `#25437`_: (*lorengordon*) Stacktrace on Windows when running pkg.list_pkgs + | refs: `#25598`_ `#25763`_ + * 7b79e433 Merge pull request `#25598`_ from twangboy/fix_25437 + +- **PR** `#25604`_: (*terminalmage*) Move patching of mock_open to within test + @ *2015-07-22T16:53:55Z* + + - **ISSUE** `#25323`_: (*terminalmage*) unit.modules.tls_test fails with older mock + | refs: `#25604`_ + +- **PR** `#25609`_: (*s0undt3ch*) [2015.5] Update the bootstrap script to latest release v2015.07.22 + @ *2015-07-22T16:28:52Z* + + - **ISSUE** `#630`_: (*syphernl*) Allow for an include statement in config files + | refs: `#25609`_ + - **PR** `#627`_: (*chjohnst*) add saltversion grain + | refs: `#25609`_ + +- **PR** `#25603`_: (*terminalmage*) Add version_cmp function to yumpkg.py + @ *2015-07-22T15:42:29Z* + + - **ISSUE** `#21912`_: (*rvora*) pkg.latest not updating the package on CentOS though yum reports an update available + | refs: `#25603`_ + +- **PR** `#25590`_: (*garethgreenaway*) 2015.5 scheduled jobs return data + @ *2015-07-21T21:57:42Z* + + - **ISSUE** `#25560`_: (*dennisjac*) scheduled highstate runs don't return results to the job cache + | refs: `#25590`_ + +- **PR** `#25584`_: (*rallytime*) Back-port `#24054`_ and `#25576`_ to 2015.5 + @ *2015-07-21T21:16:38Z* + + - **PR** `#25576`_: (*pcn*) s3fs breaks when fetching files from s3 + | refs: `#25584`_ + - **PR** `#24054`_: (*mgwilliams*) s3.head: return useful data + | refs: `#25584`_ + +- **PR** `#25589`_: (*jahamn*) Fixes ssh_known_host not taking port into account + @ *2015-07-21T21:15:06Z* + + - **ISSUE** `#23626`_: (*mirko*) salt state 'ssh_known_hosts' doesn't take 'port' into account + | refs: `#25589`_ + +- **PR** `#25573`_: (*EvaSDK*) Do not execute bootstrap script twice + @ *2015-07-21T18:20:04Z* + + - **PR** `#25465`_: (*EvaSDK*) 2015.5.3 LXC module fixes + | refs: `#25573`_ + +- **PR** `#25580`_: (*attiasr*) use explicit utf-8 decoding (`#25532`_) + @ *2015-07-21T15:40:49Z* + + - **ISSUE** `#25532`_: (*attiasr*) salt/modules/win_pkg.py list_pkgs is broken (encoding issues) + | refs: `#25556`_ `#25580`_ + +- **PR** `#25568`_: (*twangboy*) Fixed win_useradd module to add fullname + @ *2015-07-21T14:30:25Z* + + - **ISSUE** `#25206`_: (*jfindlay*) fullname issues with user.add state on windows + | refs: `#25568`_ + +- **PR** `#25561`_: (*twangboy*) Fixed the gem module to work on windows... without injection + @ *2015-07-20T21:12:15Z* + + - **ISSUE** `#21041`_: (*deuscapturus*) state module gem.installed not working on Windows. + | refs: `#25430`_ `#25561`_ `#25428`_ + - **PR** `#25428`_: (*twangboy*) Fixed the gem module to work on windows + | refs: `#25561`_ + +- **PR** `#25521`_: (*cachedout*) Fix outputter for state.orch + @ *2015-07-20T19:30:14Z* + +- **PR** `#25563`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5 + @ *2015-07-20T19:27:36Z* + + - **PR** `#25416`_: (*cachedout*) Fix broken keyword + +- **PR** `#25559`_: (*cachedout*) Lint win_pkg + @ *2015-07-20T17:46:29Z* + +- **PR** `#25556`_: (*attiasr*) fix for `#25532`_ + @ *2015-07-20T17:45:11Z* + + - **ISSUE** `#25532`_: (*attiasr*) salt/modules/win_pkg.py list_pkgs is broken (encoding issues) + | refs: `#25556`_ `#25580`_ + +- **PR** `#25554`_: (*jfindlay*) verify_ssl=True for s3 ext pillar + @ *2015-07-20T17:43:38Z* + + - **ISSUE** `#25538`_: (*stanislavb*) S3 ext_pillar configuration requires verify_ssl + | refs: `#25554`_ + +- **PR** `#25551`_: (*rallytime*) Backport `#25530`_ to 2015.5 + @ *2015-07-20T17:43:00Z* + + - **PR** `#25530`_: (*andre-luiz-dos-santos*) The variable name must be last + | refs: `#25551`_ + +- **PR** `#25533`_: (*attiasr*) port 445 for windows bootstraping + @ *2015-07-20T15:13:06Z* + +- **PR** `#25525`_: (*gtmanfred*) add make _prepare an alias for postinitio + @ *2015-07-20T15:12:38Z* + + - **ISSUE** `#25432`_: (*gtmanfred*) [2015.5.3][raet] raet error with SaltRaetRoadStackJoiner + | refs: `#25525`_ + +- **PR** `#25519`_: (*rallytime*) Backport vmware driver to 2015.5 branch + @ *2015-07-20T15:11:26Z* + + - **ISSUE** `#25511`_: (*rallytime*) Make provider --> driver change backward compatible + | refs: `#25519`_ `#25519`_ + - **ISSUE** `#23574`_: (*CedNantes*) Failed to Deploy Salt-Minion on a Win 2012 R2 using wmware Cloud Driver from Develop branch + | refs: `#25519`_ + +- **PR** `#25542`_: (*Oro*) Fix hipchat.send_message when using API v2 + @ *2015-07-20T15:09:13Z* + +- **PR** `#25531`_: (*rallytime*) Back-port `#25529`_ to 2015.5 + @ *2015-07-18T19:16:10Z* + + - **PR** `#25529`_: (*davidjb*) Fix minor typo in best practice example + | refs: `#25531`_ + +- **PR** `#25528`_: (*davidjb*) Fix typo in extend declaration doco + @ *2015-07-18T14:22:06Z* + +- **PR** `#25517`_: (*rallytime*) Back-port `#25486`_ to 2015.5 + @ *2015-07-17T21:49:26Z* + + - **ISSUE** `#25486`_: (*whiteinge*) Highstate outputter not used for state.apply + | refs: `#25517`_ + - **PR** `#25485`_: (*attiasr*) fix file downloads on windows + +- **PR** `#25516`_: (*rallytime*) Back-port `#25483`_ to 2015.5 + @ *2015-07-17T21:49:05Z* + + - **ISSUE** `#25479`_: (*alexandrsushko*) multiple mount.mounted of one device + | refs: `#25483`_ + - **PR** `#25483`_: (*alexandrsushko*) Added 'none' to the set of specialFSes + | refs: `#25516`_ + +- **PR** `#25513`_: (*garethgreenaway*) fixes to schedule.add documentation in 2015.5 + @ *2015-07-17T17:03:24Z* + + - **ISSUE** `#25493`_: (*blackduckx*) Issue with job_args on schedule.add command + | refs: `#25513`_ + +- **PR** `#25465`_: (*EvaSDK*) 2015.5.3 LXC module fixes + | refs: `#25573`_ + @ *2015-07-17T15:57:54Z* + +- **PR** `#25506`_: (*s0undt3ch*) [2015.5] Update bootstrap script to latest stable release, v2015.07.17 + @ *2015-07-17T15:40:38Z* + + - **ISSUE** `#25456`_: (*julienlavergne*) [2015.8.0rc1] salt-bootstrap fails to install salt master + | refs: `#25506`_ + - **ISSUE** `#25270`_: (*iggy*) [2015.8.0rc1] salt-bootstrap fails to properly install a minion + | refs: `#25506`_ + - **ISSUE** `#625`_: (*whiteinge*) `cmd.run` state `user` flag is not working + | refs: `#25506`_ `#632`_ + - **ISSUE** `#611`_: (*fatbox*) Peer interface fails to return data occasionally + | refs: `#25506`_ + - **ISSUE** `#607`_: (*thatch45*) next level -X support + | refs: `#25506`_ + - **ISSUE** `#598`_: (*syphernl*) Explanation on how to execute interactive installs + | refs: `#25506`_ + - **ISSUE** `#455`_: (*whiteinge*) Document common troubleshooting tips + | refs: `#25506`_ + - **PR** `#624`_: (*chjohnst*) Docs are not correct with network.ping as args are not supported + | refs: `#25506`_ + - **PR** `#621`_: (*akoumjian*) Adding ec2 cloud-init bootstrap docs + | refs: `#25506`_ + - **PR** `#606`_: (*terminalmage*) need empty line before code blocks. added ones that were missing. + | refs: `#25506`_ + - **PR** `#602`_: (*terminalmage*) State-related documentation changes + | refs: `#25506`_ + +- **PR** `#25498`_: (*jfindlay*) only read /proc/1/cmdline if it exists + @ *2015-07-17T15:35:33Z* + + - **ISSUE** `#25454`_: (*mschiff*) Regression: salt 2015.5 not working in secure chroot anymore. + | refs: `#25498`_ + +- **PR** `#25487`_: (*rallytime*) Back-port `#25464`_ to 2015.5 + @ *2015-07-16T16:58:36Z* + + - **PR** `#25464`_: (*jquast*) docfix: "cache_jobs: False" => grains_cache: False" + | refs: `#25487`_ + +- **PR** `#25482`_: (*oeuftete*) Fix docker.running detection of running container + @ *2015-07-16T16:58:29Z* + + - **PR** `#2015`_: (*thekuffs*) Esky / bbfreeze support + +- **PR** `#25468`_: (*joejulian*) Add support for pyOpenSSL > 0.10 + @ *2015-07-16T15:10:30Z* + + - **ISSUE** `#25384`_: (*rickh563*) pyopenssl 0.14 requirement in 2015.5.3 does not work in RHEL6 : ZD-364 + | refs: `#25468`_ + +- **PR** `#25467`_: (*rallytime*) Add lxml dependency to opennebula docs + @ *2015-07-16T15:09:57Z* + +- **PR** `#25461`_: (*jahamn*) Update file, if force option and content not same + @ *2015-07-15T20:15:07Z* + + - **ISSUE** `#25250`_: (*wipfs*) 'force' option in copy state deletes target file + | refs: `#25461`_ `#25710`_ + - **ISSUE** `#24647`_: (*nmadhok*) salt.states.file.copy does not copy the file if it already exists with force=True + | refs: `#25461`_ + +- **PR** `#25438`_: (*rallytime*) Reduce digital_ocean_v2 API call frequency + @ *2015-07-15T19:40:18Z* + + - **ISSUE** `#25431`_: (*namcois*) Digital Ocean v2 reducing API calls by adding per_page + | refs: `#25438`_ + +- **PR** `#25457`_: (*jacksontj*) Saltnado + @ *2015-07-15T17:50:12Z* + + - **PR** `#25427`_: (*tony-cocco*) Saltnado runner client results in blocking call despite being set-up as Runner.async + | refs: `#25457`_ + +- **PR** `#25459`_: (*jahamn*) Fixed 'defulats' typo in verify.py + @ *2015-07-15T16:53:06Z* + +- **PR** `#25426`_: (*jquast*) bugfix: trailing "...done" in rabbitmq output (backport from 'develop' to 2015.5) + @ *2015-07-15T14:48:05Z* + +- **PR** `#25433`_: (*jleroy*) Support for IPv6 addresses scopes in network.interfaces (ifconfig) + @ *2015-07-15T14:44:09Z* + + - **PR** `#25151`_: (*jleroy*) Support for IPv6 addresses scopes in network.interfaces + | refs: `#25274`_ `#25433`_ + +- **PR** `#25430`_: (*twangboy*) Disabled rbenv execution module for Windows + @ *2015-07-15T14:41:18Z* + + - **ISSUE** `#21041`_: (*deuscapturus*) state module gem.installed not working on Windows. + | refs: `#25430`_ `#25561`_ `#25428`_ + +* c4b1584 Additional test case for question raised in `#1846`_ + + - **ISSUE** `#1846`_: (*seanchannel*) development dependencies + +- **PR** `#25420`_: (*techhat*) Move S3 to use AWS Signature Version 4 + @ *2015-07-14T22:03:09Z* + +- **PR** `#25418`_: (*twangboy*) Fixed problem with file.managed test=True + @ *2015-07-14T21:26:59Z* + + - **ISSUE** `#20441`_: (*deuscapturus*) State module file.managed returns an error on Windows and test=Test + | refs: `#25418`_ + +- **PR** `#25417`_: (*ahus1*) extended documentation about dependencies for dig module + @ *2015-07-14T20:49:51Z* + +- **PR** `#25411`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5 + @ *2015-07-14T17:55:26Z* + + - **PR** `#25375`_: (*cachedout*) Fix error in config.py for master_type + - **PR** `#25324`_: (*jacobhammons*) Latest help theme updates + +- **PR** `#25406`_: (*anlutro*) Force arguments to aptpkg.version_cmp into strings + @ *2015-07-14T16:15:41Z* + +- **PR** `#25408`_: (*rallytime*) Back-port `#25399`_ to 2015.5 + @ *2015-07-14T16:09:06Z* + + - **PR** `#25399`_: (*jarpy*) Demonstrate per-minion client_acl. + | refs: `#25408`_ + +- **PR** `#25240`_: (*tankywoo*) file make os.walk only be called one + @ *2015-07-14T16:04:49Z* + +- **PR** `#25395`_: (*rallytime*) Back-port `#25389`_ to 2015.5 + @ *2015-07-14T03:26:34Z* + + - **PR** `#25389`_: (*l2ol33rt*) Adding entropy note for gpg renderer + | refs: `#25395`_ + +- **PR** `#25392`_: (*rallytime*) Back-port `#25256`_ to 2015.5 + @ *2015-07-14T03:25:13Z* + + - **PR** `#25256`_: (*yanatan16*) Dont assume source_hash exists + | refs: `#25392`_ + +- **PR** `#25398`_: (*twangboy*) Fix date + @ *2015-07-14T03:21:17Z* + +- **PR** `#25397`_: (*GideonRed*) Introduce standard error output when cli exits with non-zero status + @ *2015-07-14T03:20:24Z* + +- **PR** `#25386`_: (*cachedout*) Lint `#25383`_ + @ *2015-07-13T21:01:10Z* + + - **ISSUE** `#24444`_: (*michaelkrupp*) file.managed does not handle dead symlinks + | refs: `#25383`_ + - **PR** `#25383`_: (*jahamn*) Fix manage_file function in salt/modules/file.py to handle broken sym… + +- **PR** `#25383`_: (*jahamn*) Fix manage_file function in salt/modules/file.py to handle broken sym… + @ *2015-07-13T20:58:23Z* + + - **ISSUE** `#24444`_: (*michaelkrupp*) file.managed does not handle dead symlinks + | refs: `#25383`_ + +- **PR** `#25369`_: (*anlutro*) Fix aptpkg.version_cmp + @ *2015-07-13T20:18:45Z* + +- **PR** `#25379`_: (*jfindlay*) check for cwd before getting it + @ *2015-07-13T19:50:27Z* + + - **ISSUE** `#25337`_: (*eliasp*) `salt-call` from non-existend cwd backtraces + | refs: `#25379`_ + +- **PR** `#25334`_: (*jfindlay*) return all cmd info back to zypper fcn + @ *2015-07-13T17:03:29Z* + + - **ISSUE** `#25320`_: (*podloucky-init*) zypper module list_upgrades broken (2015.5.2) + | refs: `#25334`_ + +- **PR** `#25339`_: (*jfindlay*) update orchestration docs + @ *2015-07-13T16:04:26Z* + +- **PR** `#25358`_: (*dkiser*) Deep merge of pillar lists + | refs: `#26016`_ + @ *2015-07-13T15:51:01Z* + + - **ISSUE** `#22241`_: (*masterkorp*) Salt master not properly generating the map + | refs: `#25358`_ + +- **PR** `#25346`_: (*bechtoldt*) set correct indention in states/requisites.rst (docs), fixes `#25281`_ + @ *2015-07-13T15:34:45Z* + + - **ISSUE** `#25281`_: (*shinshenjs*) Unless usage in Official Doc syntax error? + +- **PR** `#25336`_: (*terminalmage*) Don't try to read init binary if it wasn't found + @ *2015-07-13T09:45:30Z* + +- **PR** `#25350`_: (*davidjb*) Fix documentation for file.blockreplace + @ *2015-07-13T03:41:20Z* + +- **PR** `#25326`_: (*rallytime*) Back-port `#20972`_ to 2015.5 + @ *2015-07-10T18:49:44Z* + + - **ISSUE** `#19288`_: (*oba11*) AssociatePublicIpAddress doesnt work with salt-cloud 2014.7.0 + | refs: `#20972`_ `#25326`_ + - **PR** `#20972`_: (*JohannesEbke*) Fix interface cleanup when using AssociatePublicIpAddress in `#19288`_ + | refs: `#25326`_ + +- **PR** `#25327`_: (*rallytime*) Back-port `#25290`_ to 2015.5 + @ *2015-07-10T18:49:37Z* + + - **ISSUE** `#24433`_: (*chrimi*) Salt locale state fails, if locale has not been generated + | refs: `#25290`_ + - **PR** `#25290`_: (*pcdummy*) Simple fix for locale.present on Ubuntu. + | refs: `#25327`_ + +- **PR** `#25328`_: (*rallytime*) Back-port `#25309`_ to 2015.5 + @ *2015-07-10T17:22:59Z* + + - **ISSUE** `#24827`_: (*yermulnik*) locale.present doesn't generate locales + | refs: `#25309`_ + - **PR** `#25309`_: (*davidjb*) Format /etc/locale.gen correctly in salt.modules.localemod.gen_locale + | refs: `#25328`_ + +- **PR** `#25322`_: (*jacobhammons*) version change to 2015.5.3 + @ *2015-07-10T16:11:24Z* + +- **PR** `#25308`_: (*jacksontj*) Make clear commands trace level logging + @ *2015-07-10T14:20:06Z* + + - **PR** `#24737`_: (*jacksontj*) Move AES command logging to trace + | refs: `#25308`_ + +- **PR** `#25269`_: (*jfindlay*) Extract tomcat war version + @ *2015-07-10T01:28:21Z* + + - **ISSUE** `#24520`_: (*nvx*) Tomcat module fails to extract version number from snapshot builds (2015.5 regression) + | refs: `#24927`_ + - **PR** `#24927`_: (*egarbi*) Tomcat module fails to extract version number from snapshot builds `#2`_… + | refs: `#25269`_ + +- **PR** `#25238`_: (*DmitryKuzmenko*) Pillarenv backport 2015.5 + @ *2015-07-10T01:25:07Z* + + - **ISSUE** `#18808`_: (*amendlik*) Add command line argument to select pillar environment + | refs: `#25238`_ + - **PR** `#23719`_: (*DmitryKuzmenko*) Support pillarenv cmdline in state.sls + +- **PR** `#25299`_: (*twangboy*) Added -NonInteractive so powershell doesn't hang waiting for input + @ *2015-07-09T21:00:16Z* + + - **ISSUE** `#13943`_: (*Supermathie*) Powershell commands that expect input hang forever + | refs: `#25299`_ + +- **PR** `#25301`_: (*jacobhammons*) bug fix for module function display in help + @ *2015-07-09T20:46:34Z* + +- **PR** `#25279`_: (*jacobhammons*) Additional docs on external and master job cache, assorted doc fixes + @ *2015-07-09T16:46:26Z* + + - **ISSUE** `#25277`_: (*jacobhammons*) CherryPy recommended versions + | refs: `#25279`_ + +- **PR** `#25274`_: (*jleroy*) Fix for issue `#25268`_ + @ *2015-07-09T13:36:26Z* + + - **ISSUE** `#25268`_: (*lichtamberg*) Salt not working anymore in 2015.8/develop: ValueError: 'scope' is not in list + | refs: `#25274`_ + - **PR** `#25151`_: (*jleroy*) Support for IPv6 addresses scopes in network.interfaces + | refs: `#25274`_ `#25433`_ + +- **PR** `#25272`_: (*twangboy*) Fixed problem with service not starting + @ *2015-07-08T23:29:48Z* + +- **PR** `#25225`_: (*nmadhok*) Backporting fix for issue `#25223`_ on 2015.5 branch + @ *2015-07-08T15:16:18Z* + + - **ISSUE** `#25223`_: (*nmadhok*) Runner occasionally fails with a RuntimeError when fired by a reactor + | refs: `#25225`_ + +- **PR** `#25214`_: (*rallytime*) A couple of doc fixes for the http tutorial + @ *2015-07-07T22:23:07Z* + +- **PR** `#25194`_: (*rallytime*) Update moto version check in boto_vpc_test and update min version + @ *2015-07-07T18:27:32Z* + + - **ISSUE** `#24272`_: (*rallytime*) Fix boto_vpc_test moto version check + | refs: `#25194`_ + +- **PR** `#25205`_: (*basepi*) Update releasecandidate docs + @ *2015-07-07T15:25:24Z* + +- **PR** `#25187`_: (*UtahDave*) Doc fixes: Fix misspelling and remove extraneous double spaces + @ *2015-07-07T01:07:04Z* + +- **PR** `#25182`_: (*cachedout*) Try to re-pack long floats as strs + @ *2015-07-07T01:06:43Z* + +- **PR** `#25185`_: (*rallytime*) Back-port `#25128`_ to 2015.5 + @ *2015-07-07T00:58:00Z* + + - **ISSUE** `#23822`_: (*sidcarter*) Zip file extracted permissions are incorrect + | refs: `#25128`_ + - **PR** `#25128`_: (*stanislavb*) Use cmd_unzip to preserve permissions + | refs: `#25185`_ + +- **PR** `#25181`_: (*rallytime*) Back-port `#25102`_ to 2015.5 + @ *2015-07-07T00:57:13Z* + + - **PR** `#25102`_: (*derBroBro*) Update win_network.py + | refs: `#25181`_ + +- **PR** `#25179`_: (*rallytime*) Back-port `#25059`_ to 2015.5 + @ *2015-07-07T00:56:44Z* + + - **ISSUE** `#24301`_: (*iggy*) influxdb_user and influxdb_database states need virtual functions + | refs: `#25059`_ + - **PR** `#25059`_: (*babilen*) Add virtual functions to influxdb state modules + | refs: `#25179`_ + +- **PR** `#25196`_: (*twangboy*) Fixed `#18919`_ false-positive on pkg.refresh + @ *2015-07-07T00:24:13Z* + + - **ISSUE** `#18919`_: (*giner*) Windows: pkg.refresh_db returns false-positive success + | refs: `#25196`_ + +- **PR** `#25180`_: (*rallytime*) Back-port `#25088`_ to 2015.5 + @ *2015-07-06T20:33:45Z* + + - **PR** `#25088`_: (*supertom*) Update + | refs: `#25180`_ + +- **PR** `#25191`_: (*basepi*) Add extrndest back to fileclient.is_cached in 2015.5 + @ *2015-07-06T19:35:24Z* + + - **PR** `#25117`_: (*basepi*) Fix fileclient.is_cached + | refs: `#25191`_ + +- **PR** `#25175`_: (*rallytime*) Back-port `#25020`_ to 2015.5 + @ *2015-07-06T18:53:19Z* + + - **ISSUE** `#25016`_: (*martinhoefling*) salt-run doc.execution fails with AttributeError + - **PR** `#25020`_: (*martinhoefling*) Fix for issue `#25016`_ + | refs: `#25175`_ + +- **PR** `#25173`_: (*rallytime*) Partial back-port of `#25019`_ + @ *2015-07-06T18:52:59Z* + + - **ISSUE** `#21879`_: (*bechtoldt*) Reference pages in documentation are outdated again + | refs: `#25019`_ + - **ISSUE** `#19262`_: (*bechtoldt*) salt.pillar.file_tree doesn't appear in the documentation + | refs: `#25019`_ + - **PR** `#25019`_: (*bechtoldt*) add missing module documentation to references + | refs: `#25173`_ + - **PR** `#24421`_: (*bechtoldt*) add missing module documentation + | refs: `#25019`_ + - **PR** `#21880`_: (*bechtoldt*) update references, fixes `#21879`_ + | refs: `#25019`_ + - **PR** `#20039`_: (*bechtoldt*) completing some doc references + | refs: `#25019`_ + +- **PR** `#25171`_: (*rallytime*) Back-port `#25001`_ to 2015.5 + @ *2015-07-06T18:51:53Z* + + - **PR** `#25001`_: (*jasonkeene*) Add docs for key arg in ssh_known_hosts.present + | refs: `#25171`_ + +- **PR** `#25170`_: (*rallytime*) Back-port `#24982`_ to 2015.5 + @ *2015-07-06T16:34:43Z* + + - **PR** `#24982`_: (*asyncsrc*) ec2 network_interfaces fix + | refs: `#25170`_ + +- **PR** `#25161`_: (*aneeshusa*) Allow checking for non-normalized systemd units. + @ *2015-07-06T15:15:31Z* + +- **PR** `#25151`_: (*jleroy*) Support for IPv6 addresses scopes in network.interfaces + | refs: `#25274`_ `#25433`_ + @ *2015-07-06T14:43:03Z* + +- **PR** `#25166`_: (*cachedout*) Lint `#25149`_ + @ *2015-07-06T14:40:29Z* + + - **ISSUE** `#24979`_: (*mavenAtHouzz*) [Discussion] Support for more than 1 netapi.rest_tornado server process + | refs: `#25149`_ + - **PR** `#25149`_: (*jacksontj*) Saltnado multiprocess support + | refs: `#25166`_ + +- **PR** `#25149`_: (*jacksontj*) Saltnado multiprocess support + | refs: `#25166`_ + @ *2015-07-06T14:38:43Z* + + - **ISSUE** `#24979`_: (*mavenAtHouzz*) [Discussion] Support for more than 1 netapi.rest_tornado server process + | refs: `#25149`_ + +- **PR** `#25120`_: (*d--j*) add missing continue for exeption case + @ *2015-07-02T19:38:45Z* + +- **PR** `#25117`_: (*basepi*) Fix fileclient.is_cached + | refs: `#25191`_ + @ *2015-07-02T19:38:26Z* + +- **PR** `#25087`_: (*0xf10e*) Fix execution module for glance - now based on 2015.5! + @ *2015-07-02T19:36:27Z* + +- **PR** `#25129`_: (*basepi*) [2015.5] Merge forward from 2014.7 to 2015.5 + @ *2015-07-02T17:37:40Z* + + - **ISSUE** `#18447`_: (*ryan-lane*) Can't install salt with raet using pip -e git + - **PR** `#25093`_: (*jaybocc2*) quick fix for issue `#18447`_ + - **PR** `#25069`_: (*puneetk*) Add a helper module function called list_enabled + +- **PR** `#25114`_: (*jfindlay*) Revert "Revert "adding states/postgres_database unit test case."" + @ *2015-07-02T01:01:29Z* + + - **PR** `#24798`_: (*jtand*) Revert "adding states/postgres_database unit test case." + | refs: `#25114`_ + - **PR** `#24329`_: (*jayeshka*) adding states/postgres_database unit test case. + | refs: `#24798`_ + +- **PR** `#24362`_: (*jayeshka*) adding states/postgres_user unit test case. + @ *2015-07-01T21:45:31Z* + +- **PR** `#24361`_: (*jayeshka*) adding states/postgres_schema unit test case. + @ *2015-07-01T21:44:56Z* + +- **PR** `#24331`_: (*jayeshka*) adding states/postgres_extension unit test case. + @ *2015-07-01T21:43:58Z* + +.. _`#1`: https://github.com/saltstack/salt/issues/1 +.. _`#11474`: https://github.com/saltstack/salt/issues/11474 +.. _`#12255`: https://github.com/saltstack/salt/issues/12255 +.. _`#13943`: https://github.com/saltstack/salt/issues/13943 +.. _`#14690`: https://github.com/saltstack/salt/pull/14690 +.. _`#15209`: https://github.com/saltstack/salt/issues/15209 +.. _`#18447`: https://github.com/saltstack/salt/issues/18447 +.. _`#1846`: https://github.com/saltstack/salt/issues/1846 +.. _`#18808`: https://github.com/saltstack/salt/issues/18808 +.. _`#18919`: https://github.com/saltstack/salt/issues/18919 +.. _`#19262`: https://github.com/saltstack/salt/issues/19262 +.. _`#19288`: https://github.com/saltstack/salt/issues/19288 +.. _`#19532`: https://github.com/saltstack/salt/issues/19532 +.. _`#2`: https://github.com/saltstack/salt/issues/2 +.. _`#20039`: https://github.com/saltstack/salt/pull/20039 +.. _`#2015`: https://github.com/saltstack/salt/pull/2015 +.. _`#20441`: https://github.com/saltstack/salt/issues/20441 +.. _`#20972`: https://github.com/saltstack/salt/pull/20972 +.. _`#21041`: https://github.com/saltstack/salt/issues/21041 +.. _`#21082`: https://github.com/saltstack/salt/issues/21082 +.. _`#21296`: https://github.com/saltstack/salt/issues/21296 +.. _`#21879`: https://github.com/saltstack/salt/issues/21879 +.. _`#21880`: https://github.com/saltstack/salt/pull/21880 +.. _`#21912`: https://github.com/saltstack/salt/issues/21912 +.. _`#22241`: https://github.com/saltstack/salt/issues/22241 +.. _`#22460`: https://github.com/saltstack/salt/issues/22460 +.. _`#22699`: https://github.com/saltstack/salt/issues/22699 +.. _`#23288`: https://github.com/saltstack/salt/issues/23288 +.. _`#23574`: https://github.com/saltstack/salt/issues/23574 +.. _`#23626`: https://github.com/saltstack/salt/issues/23626 +.. _`#23719`: https://github.com/saltstack/salt/pull/23719 +.. _`#23764`: https://github.com/saltstack/salt/issues/23764 +.. _`#23788`: https://github.com/saltstack/salt/issues/23788 +.. _`#23822`: https://github.com/saltstack/salt/issues/23822 +.. _`#24002`: https://github.com/saltstack/salt/issues/24002 +.. _`#24036`: https://github.com/saltstack/salt/issues/24036 +.. _`#24042`: https://github.com/saltstack/salt/issues/24042 +.. _`#24054`: https://github.com/saltstack/salt/pull/24054 +.. _`#24106`: https://github.com/saltstack/salt/issues/24106 +.. _`#24272`: https://github.com/saltstack/salt/issues/24272 +.. _`#24301`: https://github.com/saltstack/salt/issues/24301 +.. _`#24329`: https://github.com/saltstack/salt/pull/24329 +.. _`#24331`: https://github.com/saltstack/salt/pull/24331 +.. _`#24361`: https://github.com/saltstack/salt/pull/24361 +.. _`#24362`: https://github.com/saltstack/salt/pull/24362 +.. _`#24421`: https://github.com/saltstack/salt/pull/24421 +.. _`#24433`: https://github.com/saltstack/salt/issues/24433 +.. _`#24444`: https://github.com/saltstack/salt/issues/24444 +.. _`#24460`: https://github.com/saltstack/salt/issues/24460 +.. _`#24483`: https://github.com/saltstack/salt/issues/24483 +.. _`#24484`: https://github.com/saltstack/salt/issues/24484 +.. _`#24520`: https://github.com/saltstack/salt/issues/24520 +.. _`#24647`: https://github.com/saltstack/salt/issues/24647 +.. _`#24737`: https://github.com/saltstack/salt/pull/24737 +.. _`#24798`: https://github.com/saltstack/salt/pull/24798 +.. _`#24827`: https://github.com/saltstack/salt/issues/24827 +.. _`#24882`: https://github.com/saltstack/salt/issues/24882 +.. _`#24920`: https://github.com/saltstack/salt/issues/24920 +.. _`#24927`: https://github.com/saltstack/salt/pull/24927 +.. _`#24979`: https://github.com/saltstack/salt/issues/24979 +.. _`#24982`: https://github.com/saltstack/salt/pull/24982 +.. _`#25001`: https://github.com/saltstack/salt/pull/25001 +.. _`#25016`: https://github.com/saltstack/salt/issues/25016 +.. _`#25019`: https://github.com/saltstack/salt/pull/25019 +.. _`#25020`: https://github.com/saltstack/salt/pull/25020 +.. _`#25026`: https://github.com/saltstack/salt/issues/25026 +.. _`#25049`: https://github.com/saltstack/salt/pull/25049 +.. _`#25059`: https://github.com/saltstack/salt/pull/25059 +.. _`#25069`: https://github.com/saltstack/salt/pull/25069 +.. _`#25087`: https://github.com/saltstack/salt/pull/25087 +.. _`#25088`: https://github.com/saltstack/salt/pull/25088 +.. _`#25093`: https://github.com/saltstack/salt/pull/25093 +.. _`#25102`: https://github.com/saltstack/salt/pull/25102 +.. _`#25114`: https://github.com/saltstack/salt/pull/25114 +.. _`#25117`: https://github.com/saltstack/salt/pull/25117 +.. _`#25120`: https://github.com/saltstack/salt/pull/25120 +.. _`#25128`: https://github.com/saltstack/salt/pull/25128 +.. _`#25129`: https://github.com/saltstack/salt/pull/25129 +.. _`#25144`: https://github.com/saltstack/salt/issues/25144 +.. _`#25149`: https://github.com/saltstack/salt/pull/25149 +.. _`#25151`: https://github.com/saltstack/salt/pull/25151 +.. _`#25153`: https://github.com/saltstack/salt/issues/25153 +.. _`#25154`: https://github.com/saltstack/salt/issues/25154 +.. _`#25161`: https://github.com/saltstack/salt/pull/25161 +.. _`#25166`: https://github.com/saltstack/salt/pull/25166 +.. _`#25170`: https://github.com/saltstack/salt/pull/25170 +.. _`#25171`: https://github.com/saltstack/salt/pull/25171 +.. _`#25173`: https://github.com/saltstack/salt/pull/25173 +.. _`#25175`: https://github.com/saltstack/salt/pull/25175 +.. _`#25179`: https://github.com/saltstack/salt/pull/25179 +.. _`#25180`: https://github.com/saltstack/salt/pull/25180 +.. _`#25181`: https://github.com/saltstack/salt/pull/25181 +.. _`#25182`: https://github.com/saltstack/salt/pull/25182 +.. _`#25185`: https://github.com/saltstack/salt/pull/25185 +.. _`#25187`: https://github.com/saltstack/salt/pull/25187 +.. _`#25191`: https://github.com/saltstack/salt/pull/25191 +.. _`#25192`: https://github.com/saltstack/salt/issues/25192 +.. _`#25194`: https://github.com/saltstack/salt/pull/25194 +.. _`#25196`: https://github.com/saltstack/salt/pull/25196 +.. _`#25205`: https://github.com/saltstack/salt/pull/25205 +.. _`#25206`: https://github.com/saltstack/salt/issues/25206 +.. _`#25214`: https://github.com/saltstack/salt/pull/25214 +.. _`#25223`: https://github.com/saltstack/salt/issues/25223 +.. _`#25225`: https://github.com/saltstack/salt/pull/25225 +.. _`#25229`: https://github.com/saltstack/salt/issues/25229 +.. _`#25238`: https://github.com/saltstack/salt/pull/25238 +.. _`#25240`: https://github.com/saltstack/salt/pull/25240 +.. _`#25250`: https://github.com/saltstack/salt/issues/25250 +.. _`#25256`: https://github.com/saltstack/salt/pull/25256 +.. _`#25258`: https://github.com/saltstack/salt/issues/25258 +.. _`#25268`: https://github.com/saltstack/salt/issues/25268 +.. _`#25269`: https://github.com/saltstack/salt/pull/25269 +.. _`#25270`: https://github.com/saltstack/salt/issues/25270 +.. _`#25272`: https://github.com/saltstack/salt/pull/25272 +.. _`#25274`: https://github.com/saltstack/salt/pull/25274 +.. _`#25277`: https://github.com/saltstack/salt/issues/25277 +.. _`#25279`: https://github.com/saltstack/salt/pull/25279 +.. _`#25281`: https://github.com/saltstack/salt/issues/25281 +.. _`#25290`: https://github.com/saltstack/salt/pull/25290 +.. _`#25299`: https://github.com/saltstack/salt/pull/25299 +.. _`#25301`: https://github.com/saltstack/salt/pull/25301 +.. _`#25308`: https://github.com/saltstack/salt/pull/25308 +.. _`#25309`: https://github.com/saltstack/salt/pull/25309 +.. _`#25320`: https://github.com/saltstack/salt/issues/25320 +.. _`#25322`: https://github.com/saltstack/salt/pull/25322 +.. _`#25323`: https://github.com/saltstack/salt/issues/25323 +.. _`#25324`: https://github.com/saltstack/salt/pull/25324 +.. _`#25326`: https://github.com/saltstack/salt/pull/25326 +.. _`#25327`: https://github.com/saltstack/salt/pull/25327 +.. _`#25328`: https://github.com/saltstack/salt/pull/25328 +.. _`#25334`: https://github.com/saltstack/salt/pull/25334 +.. _`#25336`: https://github.com/saltstack/salt/pull/25336 +.. _`#25337`: https://github.com/saltstack/salt/issues/25337 +.. _`#25339`: https://github.com/saltstack/salt/pull/25339 +.. _`#25346`: https://github.com/saltstack/salt/pull/25346 +.. _`#25350`: https://github.com/saltstack/salt/pull/25350 +.. _`#25351`: https://github.com/saltstack/salt/issues/25351 +.. _`#25352`: https://github.com/saltstack/salt/issues/25352 +.. _`#25358`: https://github.com/saltstack/salt/pull/25358 +.. _`#25369`: https://github.com/saltstack/salt/pull/25369 +.. _`#25375`: https://github.com/saltstack/salt/pull/25375 +.. _`#25379`: https://github.com/saltstack/salt/pull/25379 +.. _`#25383`: https://github.com/saltstack/salt/pull/25383 +.. _`#25384`: https://github.com/saltstack/salt/issues/25384 +.. _`#25386`: https://github.com/saltstack/salt/pull/25386 +.. _`#25389`: https://github.com/saltstack/salt/pull/25389 +.. _`#25392`: https://github.com/saltstack/salt/pull/25392 +.. _`#25395`: https://github.com/saltstack/salt/pull/25395 +.. _`#25397`: https://github.com/saltstack/salt/pull/25397 +.. _`#25398`: https://github.com/saltstack/salt/pull/25398 +.. _`#25399`: https://github.com/saltstack/salt/pull/25399 +.. _`#25404`: https://github.com/saltstack/salt/pull/25404 +.. _`#25406`: https://github.com/saltstack/salt/pull/25406 +.. _`#25408`: https://github.com/saltstack/salt/pull/25408 +.. _`#25411`: https://github.com/saltstack/salt/pull/25411 +.. _`#25413`: https://github.com/saltstack/salt/issues/25413 +.. _`#25416`: https://github.com/saltstack/salt/pull/25416 +.. _`#25417`: https://github.com/saltstack/salt/pull/25417 +.. _`#25418`: https://github.com/saltstack/salt/pull/25418 +.. _`#25420`: https://github.com/saltstack/salt/pull/25420 +.. _`#25426`: https://github.com/saltstack/salt/pull/25426 +.. _`#25427`: https://github.com/saltstack/salt/pull/25427 +.. _`#25428`: https://github.com/saltstack/salt/pull/25428 +.. _`#25430`: https://github.com/saltstack/salt/pull/25430 +.. _`#25431`: https://github.com/saltstack/salt/issues/25431 +.. _`#25432`: https://github.com/saltstack/salt/issues/25432 +.. _`#25433`: https://github.com/saltstack/salt/pull/25433 +.. _`#25435`: https://github.com/saltstack/salt/issues/25435 +.. _`#25437`: https://github.com/saltstack/salt/issues/25437 +.. _`#25438`: https://github.com/saltstack/salt/pull/25438 +.. _`#25447`: https://github.com/saltstack/salt/issues/25447 +.. _`#25454`: https://github.com/saltstack/salt/issues/25454 +.. _`#25456`: https://github.com/saltstack/salt/issues/25456 +.. _`#25457`: https://github.com/saltstack/salt/pull/25457 +.. _`#25459`: https://github.com/saltstack/salt/pull/25459 +.. _`#25461`: https://github.com/saltstack/salt/pull/25461 +.. _`#25464`: https://github.com/saltstack/salt/pull/25464 +.. _`#25465`: https://github.com/saltstack/salt/pull/25465 +.. _`#25467`: https://github.com/saltstack/salt/pull/25467 +.. _`#25468`: https://github.com/saltstack/salt/pull/25468 +.. _`#25478`: https://github.com/saltstack/salt/issues/25478 +.. _`#25479`: https://github.com/saltstack/salt/issues/25479 +.. _`#25482`: https://github.com/saltstack/salt/pull/25482 +.. _`#25483`: https://github.com/saltstack/salt/pull/25483 +.. _`#25485`: https://github.com/saltstack/salt/pull/25485 +.. _`#25486`: https://github.com/saltstack/salt/issues/25486 +.. _`#25487`: https://github.com/saltstack/salt/pull/25487 +.. _`#25493`: https://github.com/saltstack/salt/issues/25493 +.. _`#25498`: https://github.com/saltstack/salt/pull/25498 +.. _`#25506`: https://github.com/saltstack/salt/pull/25506 +.. _`#25511`: https://github.com/saltstack/salt/issues/25511 +.. _`#25513`: https://github.com/saltstack/salt/pull/25513 +.. _`#25516`: https://github.com/saltstack/salt/pull/25516 +.. _`#25517`: https://github.com/saltstack/salt/pull/25517 +.. _`#25519`: https://github.com/saltstack/salt/pull/25519 +.. _`#25521`: https://github.com/saltstack/salt/pull/25521 +.. _`#25525`: https://github.com/saltstack/salt/pull/25525 +.. _`#25528`: https://github.com/saltstack/salt/pull/25528 +.. _`#25529`: https://github.com/saltstack/salt/pull/25529 +.. _`#25530`: https://github.com/saltstack/salt/pull/25530 +.. _`#25531`: https://github.com/saltstack/salt/pull/25531 +.. _`#25532`: https://github.com/saltstack/salt/issues/25532 +.. _`#25533`: https://github.com/saltstack/salt/pull/25533 +.. _`#25538`: https://github.com/saltstack/salt/issues/25538 +.. _`#25540`: https://github.com/saltstack/salt/issues/25540 +.. _`#25542`: https://github.com/saltstack/salt/pull/25542 +.. _`#25551`: https://github.com/saltstack/salt/pull/25551 +.. _`#25554`: https://github.com/saltstack/salt/pull/25554 +.. _`#25556`: https://github.com/saltstack/salt/pull/25556 +.. _`#25559`: https://github.com/saltstack/salt/pull/25559 +.. _`#25560`: https://github.com/saltstack/salt/issues/25560 +.. _`#25561`: https://github.com/saltstack/salt/pull/25561 +.. _`#25563`: https://github.com/saltstack/salt/pull/25563 +.. _`#25568`: https://github.com/saltstack/salt/pull/25568 +.. _`#25573`: https://github.com/saltstack/salt/pull/25573 +.. _`#25576`: https://github.com/saltstack/salt/pull/25576 +.. _`#25577`: https://github.com/saltstack/salt/issues/25577 +.. _`#25580`: https://github.com/saltstack/salt/pull/25580 +.. _`#25584`: https://github.com/saltstack/salt/pull/25584 +.. _`#25589`: https://github.com/saltstack/salt/pull/25589 +.. _`#25590`: https://github.com/saltstack/salt/pull/25590 +.. _`#25598`: https://github.com/saltstack/salt/pull/25598 +.. _`#25603`: https://github.com/saltstack/salt/pull/25603 +.. _`#25604`: https://github.com/saltstack/salt/pull/25604 +.. _`#25608`: https://github.com/saltstack/salt/pull/25608 +.. _`#25609`: https://github.com/saltstack/salt/pull/25609 +.. _`#25616`: https://github.com/saltstack/salt/issues/25616 +.. _`#25618`: https://github.com/saltstack/salt/issues/25618 +.. _`#25624`: https://github.com/saltstack/salt/pull/25624 +.. _`#25625`: https://github.com/saltstack/salt/issues/25625 +.. _`#25633`: https://github.com/saltstack/salt/pull/25633 +.. _`#25638`: https://github.com/saltstack/salt/pull/25638 +.. _`#25642`: https://github.com/saltstack/salt/pull/25642 +.. _`#25644`: https://github.com/saltstack/salt/pull/25644 +.. _`#25645`: https://github.com/saltstack/salt/pull/25645 +.. _`#25648`: https://github.com/saltstack/salt/pull/25648 +.. _`#25650`: https://github.com/saltstack/salt/issues/25650 +.. _`#25656`: https://github.com/saltstack/salt/pull/25656 +.. _`#25657`: https://github.com/saltstack/salt/pull/25657 +.. _`#25659`: https://github.com/saltstack/salt/pull/25659 +.. _`#25660`: https://github.com/saltstack/salt/pull/25660 +.. _`#25661`: https://github.com/saltstack/salt/pull/25661 +.. _`#25662`: https://github.com/saltstack/salt/pull/25662 +.. _`#25665`: https://github.com/saltstack/salt/issues/25665 +.. _`#25666`: https://github.com/saltstack/salt/pull/25666 +.. _`#25671`: https://github.com/saltstack/salt/pull/25671 +.. _`#25674`: https://github.com/saltstack/salt/issues/25674 +.. _`#25675`: https://github.com/saltstack/salt/pull/25675 +.. _`#25676`: https://github.com/saltstack/salt/pull/25676 +.. _`#25677`: https://github.com/saltstack/salt/pull/25677 +.. _`#25680`: https://github.com/saltstack/salt/pull/25680 +.. _`#25682`: https://github.com/saltstack/salt/pull/25682 +.. _`#25685`: https://github.com/saltstack/salt/pull/25685 +.. _`#25688`: https://github.com/saltstack/salt/pull/25688 +.. _`#25689`: https://github.com/saltstack/salt/issues/25689 +.. _`#25694`: https://github.com/saltstack/salt/pull/25694 +.. _`#25695`: https://github.com/saltstack/salt/pull/25695 +.. _`#25696`: https://github.com/saltstack/salt/pull/25696 +.. _`#25698`: https://github.com/saltstack/salt/pull/25698 +.. _`#25699`: https://github.com/saltstack/salt/pull/25699 +.. _`#25701`: https://github.com/saltstack/salt/issues/25701 +.. _`#25702`: https://github.com/saltstack/salt/pull/25702 +.. _`#25703`: https://github.com/saltstack/salt/pull/25703 +.. _`#25704`: https://github.com/saltstack/salt/pull/25704 +.. _`#25705`: https://github.com/saltstack/salt/pull/25705 +.. _`#25709`: https://github.com/saltstack/salt/pull/25709 +.. _`#25710`: https://github.com/saltstack/salt/pull/25710 +.. _`#25711`: https://github.com/saltstack/salt/pull/25711 +.. _`#25714`: https://github.com/saltstack/salt/pull/25714 +.. _`#25717`: https://github.com/saltstack/salt/issues/25717 +.. _`#25722`: https://github.com/saltstack/salt/pull/25722 +.. _`#25730`: https://github.com/saltstack/salt/pull/25730 +.. _`#25733`: https://github.com/saltstack/salt/pull/25733 +.. _`#25737`: https://github.com/saltstack/salt/pull/25737 +.. _`#25738`: https://github.com/saltstack/salt/pull/25738 +.. _`#25739`: https://github.com/saltstack/salt/pull/25739 +.. _`#25740`: https://github.com/saltstack/salt/pull/25740 +.. _`#25749`: https://github.com/saltstack/salt/pull/25749 +.. _`#25750`: https://github.com/saltstack/salt/pull/25750 +.. _`#25751`: https://github.com/saltstack/salt/issues/25751 +.. _`#25752`: https://github.com/saltstack/salt/pull/25752 +.. _`#25755`: https://github.com/saltstack/salt/pull/25755 +.. _`#25763`: https://github.com/saltstack/salt/pull/25763 +.. _`#25788`: https://github.com/saltstack/salt/pull/25788 +.. _`#25792`: https://github.com/saltstack/salt/pull/25792 +.. _`#25793`: https://github.com/saltstack/salt/pull/25793 +.. _`#25796`: https://github.com/saltstack/salt/pull/25796 +.. _`#25797`: https://github.com/saltstack/salt/pull/25797 +.. _`#25798`: https://github.com/saltstack/salt/pull/25798 +.. _`#25801`: https://github.com/saltstack/salt/issues/25801 +.. _`#25802`: https://github.com/saltstack/salt/issues/25802 +.. _`#25807`: https://github.com/saltstack/salt/pull/25807 +.. _`#25809`: https://github.com/saltstack/salt/issues/25809 +.. _`#25810`: https://github.com/saltstack/salt/issues/25810 +.. _`#25818`: https://github.com/saltstack/salt/pull/25818 +.. _`#25824`: https://github.com/saltstack/salt/pull/25824 +.. _`#25826`: https://github.com/saltstack/salt/pull/25826 +.. _`#25827`: https://github.com/saltstack/salt/issues/25827 +.. _`#25829`: https://github.com/saltstack/salt/pull/25829 +.. _`#25831`: https://github.com/saltstack/salt/pull/25831 +.. _`#25833`: https://github.com/saltstack/salt/pull/25833 +.. _`#25838`: https://github.com/saltstack/salt/issues/25838 +.. _`#25839`: https://github.com/saltstack/salt/issues/25839 +.. _`#25840`: https://github.com/saltstack/salt/pull/25840 +.. _`#25846`: https://github.com/saltstack/salt/pull/25846 +.. _`#25848`: https://github.com/saltstack/salt/pull/25848 +.. _`#25850`: https://github.com/saltstack/salt/issues/25850 +.. _`#25852`: https://github.com/saltstack/salt/issues/25852 +.. _`#25853`: https://github.com/saltstack/salt/pull/25853 +.. _`#25855`: https://github.com/saltstack/salt/pull/25855 +.. _`#25856`: https://github.com/saltstack/salt/pull/25856 +.. _`#25862`: https://github.com/saltstack/salt/pull/25862 +.. _`#25863`: https://github.com/saltstack/salt/issues/25863 +.. _`#25864`: https://github.com/saltstack/salt/pull/25864 +.. _`#25869`: https://github.com/saltstack/salt/pull/25869 +.. _`#25870`: https://github.com/saltstack/salt/pull/25870 +.. _`#25871`: https://github.com/saltstack/salt/pull/25871 +.. _`#25873`: https://github.com/saltstack/salt/pull/25873 +.. _`#25875`: https://github.com/saltstack/salt/pull/25875 +.. _`#25877`: https://github.com/saltstack/salt/pull/25877 +.. _`#25885`: https://github.com/saltstack/salt/pull/25885 +.. _`#25890`: https://github.com/saltstack/salt/pull/25890 +.. _`#25892`: https://github.com/saltstack/salt/pull/25892 +.. _`#25894`: https://github.com/saltstack/salt/pull/25894 +.. _`#25895`: https://github.com/saltstack/salt/pull/25895 +.. _`#25898`: https://github.com/saltstack/salt/pull/25898 +.. _`#25905`: https://github.com/saltstack/salt/pull/25905 +.. _`#25915`: https://github.com/saltstack/salt/issues/25915 +.. _`#25917`: https://github.com/saltstack/salt/pull/25917 +.. _`#25919`: https://github.com/saltstack/salt/pull/25919 +.. _`#25921`: https://github.com/saltstack/salt/pull/25921 +.. _`#25927`: https://github.com/saltstack/salt/pull/25927 +.. _`#25938`: https://github.com/saltstack/salt/pull/25938 +.. _`#25941`: https://github.com/saltstack/salt/pull/25941 +.. _`#25942`: https://github.com/saltstack/salt/pull/25942 +.. _`#25948`: https://github.com/saltstack/salt/issues/25948 +.. _`#25949`: https://github.com/saltstack/salt/issues/25949 +.. _`#25951`: https://github.com/saltstack/salt/pull/25951 +.. _`#25958`: https://github.com/saltstack/salt/issues/25958 +.. _`#25961`: https://github.com/saltstack/salt/issues/25961 +.. _`#25966`: https://github.com/saltstack/salt/pull/25966 +.. _`#25967`: https://github.com/saltstack/salt/pull/25967 +.. _`#25970`: https://github.com/saltstack/salt/pull/25970 +.. _`#25971`: https://github.com/saltstack/salt/pull/25971 +.. _`#25976`: https://github.com/saltstack/salt/pull/25976 +.. _`#25982`: https://github.com/saltstack/salt/issues/25982 +.. _`#25983`: https://github.com/saltstack/salt/issues/25983 +.. _`#25984`: https://github.com/saltstack/salt/pull/25984 +.. _`#25990`: https://github.com/saltstack/salt/pull/25990 +.. _`#25992`: https://github.com/saltstack/salt/pull/25992 +.. _`#25994`: https://github.com/saltstack/salt/issues/25994 +.. _`#25996`: https://github.com/saltstack/salt/pull/25996 +.. _`#25998`: https://github.com/saltstack/salt/issues/25998 +.. _`#26000`: https://github.com/saltstack/salt/pull/26000 +.. _`#26002`: https://github.com/saltstack/salt/pull/26002 +.. _`#26016`: https://github.com/saltstack/salt/pull/26016 +.. _`#26020`: https://github.com/saltstack/salt/pull/26020 +.. _`#26021`: https://github.com/saltstack/salt/pull/26021 +.. _`#26024`: https://github.com/saltstack/salt/issues/26024 +.. _`#26030`: https://github.com/saltstack/salt/pull/26030 +.. _`#26031`: https://github.com/saltstack/salt/pull/26031 +.. _`#26032`: https://github.com/saltstack/salt/pull/26032 +.. _`#26036`: https://github.com/saltstack/salt/pull/26036 +.. _`#26039`: https://github.com/saltstack/salt/issues/26039 +.. _`#26042`: https://github.com/saltstack/salt/pull/26042 +.. _`#26044`: https://github.com/saltstack/salt/pull/26044 +.. _`#26047`: https://github.com/saltstack/salt/pull/26047 +.. _`#26048`: https://github.com/saltstack/salt/pull/26048 +.. _`#26058`: https://github.com/saltstack/salt/pull/26058 +.. _`#26061`: https://github.com/saltstack/salt/pull/26061 +.. _`#26063`: https://github.com/saltstack/salt/issues/26063 +.. _`#26064`: https://github.com/saltstack/salt/pull/26064 +.. _`#26065`: https://github.com/saltstack/salt/pull/26065 +.. _`#26068`: https://github.com/saltstack/salt/pull/26068 +.. _`#26079`: https://github.com/saltstack/salt/pull/26079 +.. _`#26080`: https://github.com/saltstack/salt/pull/26080 +.. _`#26084`: https://github.com/saltstack/salt/pull/26084 +.. _`#26088`: https://github.com/saltstack/salt/pull/26088 +.. _`#26093`: https://github.com/saltstack/salt/issues/26093 +.. _`#26098`: https://github.com/saltstack/salt/issues/26098 +.. _`#26101`: https://github.com/saltstack/salt/pull/26101 +.. _`#26106`: https://github.com/saltstack/salt/pull/26106 +.. _`#26110`: https://github.com/saltstack/salt/pull/26110 +.. _`#26111`: https://github.com/saltstack/salt/pull/26111 +.. _`#26112`: https://github.com/saltstack/salt/issues/26112 +.. _`#26116`: https://github.com/saltstack/salt/pull/26116 +.. _`#26119`: https://github.com/saltstack/salt/pull/26119 +.. _`#26127`: https://github.com/saltstack/salt/pull/26127 +.. _`#26132`: https://github.com/saltstack/salt/pull/26132 +.. _`#26133`: https://github.com/saltstack/salt/pull/26133 +.. _`#26135`: https://github.com/saltstack/salt/pull/26135 +.. _`#26137`: https://github.com/saltstack/salt/pull/26137 +.. _`#26140`: https://github.com/saltstack/salt/pull/26140 +.. _`#26141`: https://github.com/saltstack/salt/issues/26141 +.. _`#26147`: https://github.com/saltstack/salt/pull/26147 +.. _`#26153`: https://github.com/saltstack/salt/pull/26153 +.. _`#26162`: https://github.com/saltstack/salt/issues/26162 +.. _`#26163`: https://github.com/saltstack/salt/pull/26163 +.. _`#26168`: https://github.com/saltstack/salt/pull/26168 +.. _`#26172`: https://github.com/saltstack/salt/pull/26172 +.. _`#26175`: https://github.com/saltstack/salt/pull/26175 +.. _`#26177`: https://github.com/saltstack/salt/pull/26177 +.. _`#26179`: https://github.com/saltstack/salt/pull/26179 +.. _`#26180`: https://github.com/saltstack/salt/pull/26180 +.. _`#26182`: https://github.com/saltstack/salt/pull/26182 +.. _`#26183`: https://github.com/saltstack/salt/pull/26183 +.. _`#26186`: https://github.com/saltstack/salt/pull/26186 +.. _`#26207`: https://github.com/saltstack/salt/issues/26207 +.. _`#26219`: https://github.com/saltstack/salt/pull/26219 +.. _`#26232`: https://github.com/saltstack/salt/pull/26232 +.. _`#26237`: https://github.com/saltstack/salt/pull/26237 +.. _`#26239`: https://github.com/saltstack/salt/pull/26239 +.. _`#26246`: https://github.com/saltstack/salt/pull/26246 +.. _`#26247`: https://github.com/saltstack/salt/pull/26247 +.. _`#26257`: https://github.com/saltstack/salt/pull/26257 +.. _`#26258`: https://github.com/saltstack/salt/pull/26258 +.. _`#26261`: https://github.com/saltstack/salt/pull/26261 +.. _`#26263`: https://github.com/saltstack/salt/pull/26263 +.. _`#26265`: https://github.com/saltstack/salt/pull/26265 +.. _`#26268`: https://github.com/saltstack/salt/pull/26268 +.. _`#26271`: https://github.com/saltstack/salt/pull/26271 +.. _`#26273`: https://github.com/saltstack/salt/pull/26273 +.. _`#26275`: https://github.com/saltstack/salt/pull/26275 +.. _`#26285`: https://github.com/saltstack/salt/pull/26285 +.. _`#26288`: https://github.com/saltstack/salt/pull/26288 +.. _`#26290`: https://github.com/saltstack/salt/pull/26290 +.. _`#26292`: https://github.com/saltstack/salt/pull/26292 +.. _`#26293`: https://github.com/saltstack/salt/pull/26293 +.. _`#26296`: https://github.com/saltstack/salt/pull/26296 +.. _`#3`: https://github.com/saltstack/salt/issues/3 +.. _`#455`: https://github.com/saltstack/salt/issues/455 +.. _`#598`: https://github.com/saltstack/salt/issues/598 +.. _`#602`: https://github.com/saltstack/salt/pull/602 +.. _`#606`: https://github.com/saltstack/salt/pull/606 +.. _`#607`: https://github.com/saltstack/salt/issues/607 +.. _`#611`: https://github.com/saltstack/salt/issues/611 +.. _`#621`: https://github.com/saltstack/salt/pull/621 +.. _`#624`: https://github.com/saltstack/salt/pull/624 +.. _`#625`: https://github.com/saltstack/salt/issues/625 +.. _`#627`: https://github.com/saltstack/salt/pull/627 +.. _`#630`: https://github.com/saltstack/salt/issues/630 +.. _`#631`: https://github.com/saltstack/salt/issues/631 +.. _`#632`: https://github.com/saltstack/salt/pull/632 +.. _`#633`: https://github.com/saltstack/salt/pull/633 +.. _`#634`: https://github.com/saltstack/salt/issues/634 +.. _`#638`: https://github.com/saltstack/salt/pull/638 +.. _`#640`: https://github.com/saltstack/salt/pull/640 +.. _`bp-20972`: https://github.com/saltstack/salt/pull/20972 +.. _`bp-24054`: https://github.com/saltstack/salt/pull/24054 +.. _`bp-24982`: https://github.com/saltstack/salt/pull/24982 +.. _`bp-25001`: https://github.com/saltstack/salt/pull/25001 +.. _`bp-25019`: https://github.com/saltstack/salt/pull/25019 +.. _`bp-25020`: https://github.com/saltstack/salt/pull/25020 +.. _`bp-25059`: https://github.com/saltstack/salt/pull/25059 +.. _`bp-25088`: https://github.com/saltstack/salt/pull/25088 +.. _`bp-25102`: https://github.com/saltstack/salt/pull/25102 +.. _`bp-25128`: https://github.com/saltstack/salt/pull/25128 +.. _`bp-25256`: https://github.com/saltstack/salt/pull/25256 +.. _`bp-25290`: https://github.com/saltstack/salt/pull/25290 +.. _`bp-25309`: https://github.com/saltstack/salt/pull/25309 +.. _`bp-25389`: https://github.com/saltstack/salt/pull/25389 +.. _`bp-25399`: https://github.com/saltstack/salt/pull/25399 +.. _`bp-25404`: https://github.com/saltstack/salt/pull/25404 +.. _`bp-25464`: https://github.com/saltstack/salt/pull/25464 +.. _`bp-25483`: https://github.com/saltstack/salt/pull/25483 +.. _`bp-25485`: https://github.com/saltstack/salt/pull/25485 +.. _`bp-25529`: https://github.com/saltstack/salt/pull/25529 +.. _`bp-25530`: https://github.com/saltstack/salt/pull/25530 +.. _`bp-25608`: https://github.com/saltstack/salt/pull/25608 +.. _`bp-25624`: https://github.com/saltstack/salt/pull/25624 +.. _`bp-25638`: https://github.com/saltstack/salt/pull/25638 +.. _`bp-25660`: https://github.com/saltstack/salt/pull/25660 +.. _`bp-25671`: https://github.com/saltstack/salt/pull/25671 +.. _`bp-25688`: https://github.com/saltstack/salt/pull/25688 +.. _`bp-25696`: https://github.com/saltstack/salt/pull/25696 +.. _`bp-25709`: https://github.com/saltstack/salt/pull/25709 +.. _`bp-25722`: https://github.com/saltstack/salt/pull/25722 +.. _`bp-25730`: https://github.com/saltstack/salt/pull/25730 +.. _`bp-25788`: https://github.com/saltstack/salt/pull/25788 +.. _`bp-25824`: https://github.com/saltstack/salt/pull/25824 +.. _`bp-25829`: https://github.com/saltstack/salt/pull/25829 +.. _`bp-25855`: https://github.com/saltstack/salt/pull/25855 +.. _`bp-25862`: https://github.com/saltstack/salt/pull/25862 +.. _`bp-25864`: https://github.com/saltstack/salt/pull/25864 +.. _`bp-25892`: https://github.com/saltstack/salt/pull/25892 +.. _`bp-25917`: https://github.com/saltstack/salt/pull/25917 +.. _`bp-25976`: https://github.com/saltstack/salt/pull/25976 +.. _`bp-25984`: https://github.com/saltstack/salt/pull/25984 +.. _`bp-26147`: https://github.com/saltstack/salt/pull/26147 +.. _`bp-26153`: https://github.com/saltstack/salt/pull/26153 +.. _`bp-26237`: https://github.com/saltstack/salt/pull/26237 +.. _`fix-11474`: https://github.com/saltstack/salt/issues/11474 +.. _`fix-2015`: https://github.com/saltstack/salt/pull/2015 +.. _`fix-22699`: https://github.com/saltstack/salt/issues/22699 +.. _`fix-24036`: https://github.com/saltstack/salt/issues/24036 +.. _`fix-24272`: https://github.com/saltstack/salt/issues/24272 +.. _`fix-24483`: https://github.com/saltstack/salt/issues/24483 +.. _`fix-24484`: https://github.com/saltstack/salt/issues/24484 +.. _`fix-24882`: https://github.com/saltstack/salt/issues/24882 +.. _`fix-25192`: https://github.com/saltstack/salt/issues/25192 +.. _`fix-25616`: https://github.com/saltstack/salt/issues/25616 +.. _`fix-26163`: https://github.com/saltstack/salt/pull/26163 From 670464258f789dad5e14863670da2df6ace59410 Mon Sep 17 00:00:00 2001 From: rallytime Date: Thu, 13 Aug 2015 16:44:10 -0600 Subject: [PATCH 41/70] Move VM creation details dict to log.trace Fixes #16179 --- salt/cloud/clouds/gce.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/cloud/clouds/gce.py b/salt/cloud/clouds/gce.py index dde7c3b4d73..279b06dead5 100644 --- a/salt/cloud/clouds/gce.py +++ b/salt/cloud/clouds/gce.py @@ -2191,7 +2191,7 @@ def create(vm_=None, call=None): ) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) - log.debug( + log.trace( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(node_dict) ) From c5395db851f9c56fa20fe0a2a56701a551ea5432 Mon Sep 17 00:00:00 2001 From: rallytime Date: Fri, 14 Aug 2015 09:57:53 -0600 Subject: [PATCH 42/70] Make ec2.create_snapshot return less unweildly and more relevant --- salt/cloud/clouds/ec2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/cloud/clouds/ec2.py b/salt/cloud/clouds/ec2.py index 2a388281450..63433768282 100644 --- a/salt/cloud/clouds/ec2.py +++ b/salt/cloud/clouds/ec2.py @@ -3763,7 +3763,7 @@ def create_snapshot(kwargs=None, call=None, wait_to_finish=False): argument_being_watched='status', required_argument_response='completed') - return data + return r_data def delete_snapshot(kwargs=None, call=None): From d4ca1dccbf2dc602964b97f763ead9c4adc7ef0a Mon Sep 17 00:00:00 2001 From: twangboy Date: Fri, 14 Aug 2015 10:52:45 -0600 Subject: [PATCH 43/70] Removed salt-master role requirement --- salt/states/winrepo.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/salt/states/winrepo.py b/salt/states/winrepo.py index 2c3a9665a4c..ee5a1b6ff8b 100644 --- a/salt/states/winrepo.py +++ b/salt/states/winrepo.py @@ -20,15 +20,7 @@ import salt.config def __virtual__(): - ''' - Load this state if this is the salt-master - ''' - try: - return ('winrepo' - if 'salt-master' in __grains__.get('roles', []) - else False) - except TypeError: - return False + return 'winrepo' def genrepo(name, force=False, allow_empty=False): From d8ad023e883a940f83ba7c53ebcd8000370437f4 Mon Sep 17 00:00:00 2001 From: rallytime Date: Fri, 14 Aug 2015 15:47:53 -0600 Subject: [PATCH 44/70] Don't call boto_elb._attributes_present if no attributes were provided Refs #16049 --- salt/states/boto_elb.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/salt/states/boto_elb.py b/salt/states/boto_elb.py index 6326db9ff59..ff7bbdf9b73 100644 --- a/salt/states/boto_elb.py +++ b/salt/states/boto_elb.py @@ -193,7 +193,11 @@ Overriding the alarm values on the resource: attributes: threshold: 2.0 ''' + +# Import Python Libs from __future__ import absolute_import + +# Import Salt Libs import salt.utils.dictupdate as dictupdate from salt.exceptions import SaltInvocationError import salt.ext.six as six @@ -302,13 +306,17 @@ def present( ret['result'] = _ret['result'] if ret['result'] is False: return ret - _ret = _attributes_present(name, attributes, region, key, keyid, profile) - ret['changes'] = dictupdate.update(ret['changes'], _ret['changes']) - ret['comment'] = ' '.join([ret['comment'], _ret['comment']]) - if not _ret['result']: - ret['result'] = _ret['result'] - if ret['result'] is False: - return ret + + if attributes: + _ret = _attributes_present(name, attributes, region, key, keyid, profile) + ret['changes'] = dictupdate.update(ret['changes'], _ret['changes']) + ret['comment'] = ' '.join([ret['comment'], _ret['comment']]) + + if not _ret['result']: + ret['result'] = _ret['result'] + if ret['result'] is False: + return ret + _ret = _health_check_present(name, health_check, region, key, keyid, profile) ret['changes'] = dictupdate.update(ret['changes'], _ret['changes']) From cf532d46ddc77f020a5c2d3fe664465364c4d01c Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Sun, 16 Aug 2015 08:15:05 -0700 Subject: [PATCH 45/70] Some mount options are translated to different options once a share has been mounted, eg. when specifying a protocol for NFS as either tcp or udp this option is translated into either proto=tcp or proto=udp. Change adds a lookup dictionary for these options so that a re-mount isn't forced each time. --- salt/states/mount.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/salt/states/mount.py b/salt/states/mount.py index 256d5dcf6e6..de2c1bf0b8b 100644 --- a/salt/states/mount.py +++ b/salt/states/mount.py @@ -235,9 +235,18 @@ def mounted(name, # Some filesystems have options which should not force a remount. mount_ignore_fs_keys = { 'ramfs': ['size'] - } + } + + # Some options are translated once mounted + mount_translate_options = { + 'tcp': 'proto=tcp', + 'udp': 'proto=udp', + } for opt in opts: + if opt in mount_translate_options: + opt = mount_translate_options[opt] + keyval_option = opt.split('=')[0] if keyval_option in mount_invisible_keys: opt = keyval_option From a83a5de41e660063b4cc5373dba0ad77ff748b16 Mon Sep 17 00:00:00 2001 From: Bastiaan Bakker Date: Mon, 17 Aug 2015 11:11:12 +0200 Subject: [PATCH 46/70] fix issue #26161: on RedHat family systems touch /var/lock/subsys/$SERVICE to ensure the daemon will be stopped on shutdown. --- pkg/rpm/salt-api | 9 ++++++++- pkg/rpm/salt-master | 8 ++++++++ pkg/rpm/salt-minion | 7 ++++++- pkg/rpm/salt-syndic | 8 ++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pkg/rpm/salt-api b/pkg/rpm/salt-api index e4dfc3e49b4..1deeaf2f0df 100755 --- a/pkg/rpm/salt-api +++ b/pkg/rpm/salt-api @@ -73,7 +73,10 @@ start() { RETVAL=1 else daemon --pidfile=$PID_FILE --check $SERVICE $SALTAPI $CONFIG_ARGS - RETVAL=0 + RETVAL=$? + [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + echo + return $RETVAL fi fi RETVAL=$? @@ -97,6 +100,10 @@ stop() { fi else killproc $PROCESS + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + return $RETVAL fi RETVAL=$? echo diff --git a/pkg/rpm/salt-master b/pkg/rpm/salt-master index a05ef357fb2..449f2686c78 100755 --- a/pkg/rpm/salt-master +++ b/pkg/rpm/salt-master @@ -64,6 +64,10 @@ start() { fi else daemon --check $SERVICE $SALTMASTER -d $MASTER_ARGS + RETVAL=$? + [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + echo + return $RETVAL fi RETVAL=$? echo @@ -86,6 +90,10 @@ stop() { fi else killproc $PROCESS + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + return $RETVAL fi RETVAL=$? echo diff --git a/pkg/rpm/salt-minion b/pkg/rpm/salt-minion index 214f895a9d7..32564be5db3 100755 --- a/pkg/rpm/salt-minion +++ b/pkg/rpm/salt-minion @@ -68,7 +68,11 @@ start() { RETVAL=$? echo -n "already running" else - daemon --check $SERVICE $SALTMINION -d $MINION_ARGS + daemon --check $SERVICE $SALTMINION -d $MINION_ARGS + RETVAL=$? + [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + echo + return $RETVAL fi fi RETVAL=$? @@ -94,6 +98,7 @@ stop() { else killproc $PROCESS RETVAL=$? + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE # tidy up any rogue processes: PROCS=`ps -ef | grep "$SALTMINION" | grep -v grep | awk '{print $2}'` if [ -n "$PROCS" ]; then diff --git a/pkg/rpm/salt-syndic b/pkg/rpm/salt-syndic index a687e3dcded..3f958b1de6f 100755 --- a/pkg/rpm/salt-syndic +++ b/pkg/rpm/salt-syndic @@ -65,6 +65,10 @@ start() { fi else daemon --check $SERVICE $SALTSYNDIC -d $SYNDIC_ARGS + RETVAL=$? + [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + echo + return $RETVAL fi RETVAL=$? echo @@ -87,6 +91,10 @@ stop() { fi else killproc $PROCESS + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + return $RETVAL fi RETVAL=$? echo From 33ed315c856e2e505a56ebd933f29438d97fefb2 Mon Sep 17 00:00:00 2001 From: Loren Carvalho Date: Sat, 15 Aug 2015 21:04:51 -0700 Subject: [PATCH 47/70] fixed Packaing -> Packaging typo and added a couple comments on the setuptools/distutils abstract methods --- setup.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 8bc68a4e007..cb6047a153c 100755 --- a/setup.py +++ b/setup.py @@ -138,10 +138,14 @@ class WriteSaltVersion(Command): description = 'Write salt\'s hardcoded version file' def initialize_options(self): - pass + ''' + Abstract method that is required to be overwritten + ''' def finalize_options(self): - pass + ''' + Abstract method that is required to be overwritten + ''' def run(self): if not os.path.exists(SALT_VERSION_HARDCODED): @@ -160,15 +164,19 @@ class WriteSaltVersion(Command): # pylint: enable=E0602 -class WriteSaltSshPackaingFile(Command): +class WriteSaltSshPackagingFile(Command): description = 'Write salt\'s ssh packaging file' def initialize_options(self): - pass + ''' + Abstract method that is required to be overwritten + ''' def finalize_options(self): - pass + ''' + Abstract method that is required to be overwritten + ''' def run(self): if not os.path.exists(PACKAGED_FOR_SALT_SSH_FILE): @@ -316,7 +324,9 @@ class TestCommand(Command): self.runtests_opts = None def finalize_options(self): - pass + ''' + Abstract method that is required to be overwritten + ''' def run(self): from subprocess import Popen From ec8d4b04705c2120a86121a67b03720d787e671a Mon Sep 17 00:00:00 2001 From: Bastiaan Bakker Date: Mon, 17 Aug 2015 17:20:33 +0200 Subject: [PATCH 48/70] test wether RETVAL is 0 with -eq rather than =. --- pkg/rpm/salt-api | 4 ++-- pkg/rpm/salt-master | 4 ++-- pkg/rpm/salt-minion | 4 ++-- pkg/rpm/salt-syndic | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/rpm/salt-api b/pkg/rpm/salt-api index 1deeaf2f0df..0d172bb3b14 100755 --- a/pkg/rpm/salt-api +++ b/pkg/rpm/salt-api @@ -74,7 +74,7 @@ start() { else daemon --pidfile=$PID_FILE --check $SERVICE $SALTAPI $CONFIG_ARGS RETVAL=$? - [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE echo return $RETVAL fi @@ -102,7 +102,7 @@ stop() { killproc $PROCESS RETVAL=$? echo - [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE return $RETVAL fi RETVAL=$? diff --git a/pkg/rpm/salt-master b/pkg/rpm/salt-master index 449f2686c78..dd1a1afc702 100755 --- a/pkg/rpm/salt-master +++ b/pkg/rpm/salt-master @@ -65,7 +65,7 @@ start() { else daemon --check $SERVICE $SALTMASTER -d $MASTER_ARGS RETVAL=$? - [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE echo return $RETVAL fi @@ -92,7 +92,7 @@ stop() { killproc $PROCESS RETVAL=$? echo - [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE return $RETVAL fi RETVAL=$? diff --git a/pkg/rpm/salt-minion b/pkg/rpm/salt-minion index 32564be5db3..9a4796f2582 100755 --- a/pkg/rpm/salt-minion +++ b/pkg/rpm/salt-minion @@ -70,7 +70,7 @@ start() { else daemon --check $SERVICE $SALTMINION -d $MINION_ARGS RETVAL=$? - [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE echo return $RETVAL fi @@ -98,7 +98,7 @@ stop() { else killproc $PROCESS RETVAL=$? - [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE # tidy up any rogue processes: PROCS=`ps -ef | grep "$SALTMINION" | grep -v grep | awk '{print $2}'` if [ -n "$PROCS" ]; then diff --git a/pkg/rpm/salt-syndic b/pkg/rpm/salt-syndic index 3f958b1de6f..fa0493401eb 100755 --- a/pkg/rpm/salt-syndic +++ b/pkg/rpm/salt-syndic @@ -66,7 +66,7 @@ start() { else daemon --check $SERVICE $SALTSYNDIC -d $SYNDIC_ARGS RETVAL=$? - [ $RETVAL = 0 ] && touch /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE echo return $RETVAL fi @@ -93,7 +93,7 @@ stop() { killproc $PROCESS RETVAL=$? echo - [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$SERVICE + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE return $RETVAL fi RETVAL=$? From 211f6feaf5ea0c730d2ec2334693c7e3b28ead96 Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 17 Aug 2015 10:58:44 -0600 Subject: [PATCH 49/70] Fix test failures - get_attributes shouldn't be called if none are provided --- tests/unit/states/boto_elb_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/states/boto_elb_test.py b/tests/unit/states/boto_elb_test.py index e64e1ad35b4..a6e2a1d1e53 100644 --- a/tests/unit/states/boto_elb_test.py +++ b/tests/unit/states/boto_elb_test.py @@ -98,7 +98,7 @@ class BotoElbTestCase(TestCase): self.assertTrue(boto_elb.__salt__['boto_elb.exists'].called) self.assertTrue(boto_elb.__salt__['boto_elb.create'].called) self.assertTrue(boto_elb.__salt__['state.single'].called) - self.assertTrue( + self.assertFalse( boto_elb.__salt__['boto_elb.get_attributes'].called ) self.assertTrue( From b2fa2ac9d3bb785b62b2c4ac0acf8095bd5200ab Mon Sep 17 00:00:00 2001 From: Jason Hamner Date: Mon, 17 Aug 2015 11:00:25 -0600 Subject: [PATCH 50/70] Fixes autosign_timeout usage in check_autosign_dir Fixes #24334 --- salt/daemons/masterapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/daemons/masterapi.py b/salt/daemons/masterapi.py index ea2f7a7e434..9da9c61c05d 100644 --- a/salt/daemons/masterapi.py +++ b/salt/daemons/masterapi.py @@ -328,7 +328,7 @@ class AutoKey(object): autosign_dir = os.path.join(self.opts['pki_dir'], 'minions_autosign') # cleanup expired files - expire_minutes = self.opts.get('autosign_expire_minutes', 10) + expire_minutes = self.opts.get('autosign_timeout', 120) if expire_minutes > 0: min_time = time.time() - (60 * int(expire_minutes)) for root, dirs, filenames in os.walk(autosign_dir): From ca406eaf3cc98a082c6fd99106654ee3de91f95c Mon Sep 17 00:00:00 2001 From: Julien Cigar Date: Mon, 10 Aug 2015 15:00:07 +0200 Subject: [PATCH 51/70] proposed fix for #26155 --- salt/states/pip_state.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index 8daf55ad427..cb65c80ec83 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -57,7 +57,11 @@ def __virtual__(): ''' Only load if the pip module is available in __salt__ ''' - if HAS_PIP and 'pip.list' in __salt__: + if not HAS_PIP: + logger.warning( + 'An importable pip module could not be found on your system' + ) + if 'pip.list' in __salt__: return __virtualname__ return False @@ -98,6 +102,16 @@ def _check_pkg_version_format(pkg): ret = {'result': False, 'comment': None, 'prefix': None, 'version_spec': None} + + if not HAS_PIP: + ret['comment'] = ( + 'An importable pip module is required but could not be found on ' + 'your system. This usually means that the system''s pip package ' + 'is not installed properly.' + ) + + return ret + from_vcs = False try: # Get the requirement object from the pip library From f0bc3765d9990440f61f97ec3a11e3874063942f Mon Sep 17 00:00:00 2001 From: Julien Cigar Date: Mon, 10 Aug 2015 16:10:46 +0200 Subject: [PATCH 52/70] No logging should happen on __virtual__ --- salt/states/pip_state.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index cb65c80ec83..d10b754389d 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -57,10 +57,6 @@ def __virtual__(): ''' Only load if the pip module is available in __salt__ ''' - if not HAS_PIP: - logger.warning( - 'An importable pip module could not be found on your system' - ) if 'pip.list' in __salt__: return __virtualname__ return False From a013bb5b3d06b5ed641eea31d42de7f430521d12 Mon Sep 17 00:00:00 2001 From: TheBigBear Date: Mon, 17 Aug 2015 13:23:46 +0100 Subject: [PATCH 53/70] minor edit --- salt/utils/jinja.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/utils/jinja.py b/salt/utils/jinja.py index d4ab2f6f101..7dd38e950c8 100644 --- a/salt/utils/jinja.py +++ b/salt/utils/jinja.py @@ -272,7 +272,7 @@ class SerializerExtension(Extension, object): {%- set json_src = "{'bar': 'for real'}"|load_json %} Dude, {{ yaml_src.foo }} {{ json_src.bar }}! - will be rendered has:: + will be rendered as:: Dude, it works for real! @@ -298,7 +298,7 @@ class SerializerExtension(Extension, object): {% endload %} Dude, {{ yaml_src.foo }} {{ json_src.bar }}! - will be rendered has:: + will be rendered as:: Dude, it works for real! From 4d6841c7610618398783f562cfee690021140adf Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 14:51:32 +0100 Subject: [PATCH 54/70] Install M2CryptoWin{32,64} while installing Salt --- setup.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index cb6047a153c..a530eda3411 100755 --- a/setup.py +++ b/setup.py @@ -190,6 +190,30 @@ class WriteSaltSshPackagingFile(Command): # pylint: enable=E0602 +class InstallM2CryptoWindows(Command): + + description = 'Install M2CryptoWindows' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if getattr(self.distribution, 'salt_installing_m2crypto_windows', None) is None: + print('This command is not meant to be called on it\'s own') + exit(1) + import platform + from pip.utils import call_subprocess + from pip.utils.logging import indent_log + platform_bits, _ = platform.architecture() + with indent_log(): + call_subprocess( + ['pip', 'install', '--egg', 'M2CryptoWin{0}'.format(platform_bits[:2])] + ) + + class Sdist(sdist): def make_release_tree(self, base_dir, files): @@ -507,6 +531,11 @@ class Install(install): self.distribution.salt_version_hardcoded_path = os.path.join( self.build_lib, 'salt', '_version.py' ) + if IS_WINDOWS_PLATFORM: + # Install M2Crypto first + self.distribution.salt_installing_m2crypto_windows = True + self.run_command('install-m2crypto-windows') + self.distribution.salt_installing_m2crypto_windows = None # Run install.run install.run(self) @@ -605,7 +634,6 @@ class SaltDistribution(distutils.dist.Distribution): self.salt_logs_dir = None self.salt_pidfile_dir = None - self.name = 'salt-ssh' if PACKAGED_FOR_SALT_SSH else 'salt' self.salt_version = __version__ # pylint: disable=undefined-variable self.description = 'Portable, distributed, remote execution and configuration management system' @@ -621,7 +649,8 @@ class SaltDistribution(distutils.dist.Distribution): 'write-salt-ssh-packaging-file': WriteSaltSshPackaingFile}) if not IS_WINDOWS_PLATFORM: self.cmdclass.update({'sdist': CloudSdist, - 'install_lib': InstallLib}) + 'install_lib': InstallLib + 'install-m2crypto-windows': InstallM2CryptoWindows}) self.license = 'Apache Software License 2.0' self.packages = self.discover_packages() From a5aa752a857bfaa53e97dc39182bb354509450be Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 15:27:03 +0100 Subject: [PATCH 55/70] Override the develop command when WITH_SETUPTOOLS is set --- setup.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a530eda3411..653fef01d9e 100755 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ WITH_SETUPTOOLS = False if 'USE_SETUPTOOLS' in os.environ or 'setuptools' in sys.modules: try: from setuptools import setup + from setuptools.command.develop import develop from setuptools.command.install import install from setuptools.command.sdist import sdist from setuptools.command.egg_info import egg_info @@ -190,6 +191,17 @@ class WriteSaltSshPackagingFile(Command): # pylint: enable=E0602 +if WITH_SETUPTOOLS: + class Develop(develop): + def run(self): + if IS_WINDOWS_PLATFORM: + # Install M2Crypto first + self.distribution.salt_installing_m2crypto_windows = True + self.run_command('install-m2crypto-windows') + self.distribution.salt_installing_m2crypto_windows = None + develop.run(self) + + class InstallM2CryptoWindows(Command): description = 'Install M2CryptoWindows' @@ -649,8 +661,9 @@ class SaltDistribution(distutils.dist.Distribution): 'write-salt-ssh-packaging-file': WriteSaltSshPackaingFile}) if not IS_WINDOWS_PLATFORM: self.cmdclass.update({'sdist': CloudSdist, - 'install_lib': InstallLib - 'install-m2crypto-windows': InstallM2CryptoWindows}) + 'install_lib': InstallLib}) + if IS_WINDOWS_PLATFORM: + self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) self.license = 'Apache Software License 2.0' self.packages = self.discover_packages() From 0ff2f19aee5f538a2be78743da8e97fd7912e231 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 15:32:33 +0100 Subject: [PATCH 56/70] Override the develop command in cmdclass --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index 653fef01d9e..f753bbaa65c 100755 --- a/setup.py +++ b/setup.py @@ -665,6 +665,9 @@ class SaltDistribution(distutils.dist.Distribution): if IS_WINDOWS_PLATFORM: self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) + if WITH_SETUPTOOLS: + self.cmdclass.update({'develop': Develop}) + self.license = 'Apache Software License 2.0' self.packages = self.discover_packages() self.zip_safe = False From 8fda8c0db3854595404566a60e5449f1bec5eb7a Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 15:39:58 +0100 Subject: [PATCH 57/70] M2CryptoWin{32,64} should only be installed on Salt < 2015.8.0 --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index f753bbaa65c..43c1415dde5 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ The setup script for salt ''' from __future__ import absolute_import - +# pylint: disable=file-perms # pylint: disable=C0111,E1101,E1103,F0401,W0611,W0201,W0232,R0201,R0902,R0903 # For Python 2.5. A no-op on 2.6 and above. @@ -18,7 +18,7 @@ import time try: from urllib2 import urlopen except ImportError: - from urllib.request import urlopen + from urllib.request import urlopen # pylint: disable=no-name-in-module from datetime import datetime # pylint: disable=E0611 import distutils.dist @@ -194,7 +194,7 @@ class WriteSaltSshPackagingFile(Command): if WITH_SETUPTOOLS: class Develop(develop): def run(self): - if IS_WINDOWS_PLATFORM: + if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable # Install M2Crypto first self.distribution.salt_installing_m2crypto_windows = True self.run_command('install-m2crypto-windows') @@ -543,7 +543,7 @@ class Install(install): self.distribution.salt_version_hardcoded_path = os.path.join( self.build_lib, 'salt', '_version.py' ) - if IS_WINDOWS_PLATFORM: + if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable # Install M2Crypto first self.distribution.salt_installing_m2crypto_windows = True self.run_command('install-m2crypto-windows') @@ -662,7 +662,7 @@ class SaltDistribution(distutils.dist.Distribution): if not IS_WINDOWS_PLATFORM: self.cmdclass.update({'sdist': CloudSdist, 'install_lib': InstallLib}) - if IS_WINDOWS_PLATFORM: + if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) if WITH_SETUPTOOLS: From 1ea426e2992632e4a603482525640918485c5df0 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 14:02:26 +0100 Subject: [PATCH 58/70] Move code to properly handle default requirements. Refs #26305 --- setup.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 43c1415dde5..fd6f15f052d 100755 --- a/setup.py +++ b/setup.py @@ -961,14 +961,6 @@ class SaltDistribution(distutils.dist.Distribution): def parse_command_line(self): args = distutils.dist.Distribution.parse_command_line(self) - # Setup our property functions after class initialization and - # after parsing the command line since most are set to None - for funcname in dir(self): - if not funcname.startswith('_property_'): - continue - property_name = funcname.split('_property_', 1)[-1] - setattr(self, property_name, getattr(self, funcname)) - if not self.ssh_packaging and PACKAGED_FOR_SALT_SSH: self.ssh_packaging = 1 @@ -986,6 +978,16 @@ class SaltDistribution(distutils.dist.Distribution): ) ) + # Setup our property functions after class initialization and + # after parsing the command line since most are set to None + # ATTENTION: This should be the last step before returning the args or + # some of the requirements won't be correctly set + for funcname in dir(self): + if not funcname.startswith('_property_'): + continue + property_name = funcname.split('_property_', 1)[-1] + setattr(self, property_name, getattr(self, funcname)) + return args # <---- Overridden Methods --------------------------------------------------------------------------------------- From 915da594c2f17bd0ac6a61e586905d21bb8b0f8f Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 15:55:20 +0100 Subject: [PATCH 59/70] Skip M2Crypto in Windows. Wwe're installing M2CryptoWin{32,64} which comes compiled --- setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.py b/setup.py index fd6f15f052d..1f10116282a 100755 --- a/setup.py +++ b/setup.py @@ -128,6 +128,10 @@ def _parse_requirements_file(requirements_file): continue if IS_WINDOWS_PLATFORM and 'libcloud' in line: continue + if IS_WINDOWS_PLATFORM and 'M2Crypto' in line and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable + # In Windows, we're installing M2CryptoWin{32,64} which comes + # compiled + continue parsed_requirements.append(line) return parsed_requirements # <---- Helper Functions --------------------------------------------------------------------------------------------- From 86692a92cd213576343176129b1fce6316f8db67 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 16:27:31 +0100 Subject: [PATCH 60/70] Install PyCrypto from a wheel in repo.saltstack.com under Windows --- setup.py | 82 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index 1f10116282a..17a572e8bee 100755 --- a/setup.py +++ b/setup.py @@ -126,12 +126,16 @@ def _parse_requirements_file(requirements_file): line = line.strip() if not line or line.startswith(('#', '-r')): continue - if IS_WINDOWS_PLATFORM and 'libcloud' in line: - continue - if IS_WINDOWS_PLATFORM and 'M2Crypto' in line and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable - # In Windows, we're installing M2CryptoWin{32,64} which comes - # compiled - continue + if IS_WINDOWS_PLATFORM: + if 'libcloud' in line: + continue + if 'pycrypto' in line.lower(): + # On windows we install PyCrypto using python wheels + continue + if 'm2crypto' in line.lower() and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable + # In Windows, we're installing M2CryptoWin{32,64} which comes + # compiled + continue parsed_requirements.append(line) return parsed_requirements # <---- Helper Functions --------------------------------------------------------------------------------------------- @@ -198,11 +202,16 @@ class WriteSaltSshPackagingFile(Command): if WITH_SETUPTOOLS: class Develop(develop): def run(self): - if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable - # Install M2Crypto first - self.distribution.salt_installing_m2crypto_windows = True - self.run_command('install-m2crypto-windows') - self.distribution.salt_installing_m2crypto_windows = None + if IS_WINDOWS_PLATFORM: + if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable + # Install M2Crypto first + self.distribution.salt_installing_m2crypto_windows = True + self.run_command('install-m2crypto-windows') + self.distribution.salt_installing_m2crypto_windows = None + self.distribution.salt_installing_pycrypto_windows = True + self.run_command('install-pycrypto-windows') + self.distribution.salt_installing_pycrypto_windows = None + develop.run(self) @@ -230,6 +239,37 @@ class InstallM2CryptoWindows(Command): ) +class InstallPyCryptoWindowsWheel(Command): + + description = 'Install PyCrypto on Windows' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if getattr(self.distribution, 'salt_installing_pycrypto_windows', None) is None: + print('This command is not meant to be called on it\'s own') + exit(1) + import platform + from pip.utils import call_subprocess + from pip.utils.logging import indent_log + platform_bits, _ = platform.architecture() + call_arguments = ['pip', 'install', 'wheel'] + if platform_bits == '64bit': + call_arguments.append( + 'http://repo.saltstack.com/windows/dependencies/64/pycrypto-2.6.1-cp27-none-win_amd64.whl' + ) + else: + call_arguments.append( + 'http://repo.saltstack.com/windows/dependencies/32/pycrypto-2.6.1-cp27-none-win32.whl' + ) + with indent_log(): + call_subprocess(call_arguments) + + class Sdist(sdist): def make_release_tree(self, base_dir, files): @@ -547,11 +587,15 @@ class Install(install): self.distribution.salt_version_hardcoded_path = os.path.join( self.build_lib, 'salt', '_version.py' ) - if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable - # Install M2Crypto first - self.distribution.salt_installing_m2crypto_windows = True - self.run_command('install-m2crypto-windows') - self.distribution.salt_installing_m2crypto_windows = None + if IS_WINDOWS_PLATFORM: + if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable + # Install M2Crypto first + self.distribution.salt_installing_m2crypto_windows = True + self.run_command('install-m2crypto-windows') + self.distribution.salt_installing_m2crypto_windows = None + self.distribution.salt_installing_pycrypto_windows = True + self.run_command('install-pycrypto-windows') + self.distribution.salt_installing_pycrypto_windows = None # Run install.run install.run(self) @@ -666,8 +710,10 @@ class SaltDistribution(distutils.dist.Distribution): if not IS_WINDOWS_PLATFORM: self.cmdclass.update({'sdist': CloudSdist, 'install_lib': InstallLib}) - if IS_WINDOWS_PLATFORM and __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable - self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) + if IS_WINDOWS_PLATFORM: + self.cmdclass.update({'install-pycrypto-windows': InstallPyCryptoWindowsWheel}) + if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable + self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) if WITH_SETUPTOOLS: self.cmdclass.update({'develop': Develop}) From 7b25430cc71531670b410f0a75d782735013c5bc Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 17:20:12 +0100 Subject: [PATCH 61/70] Download the necessary DLLs for windows --- setup.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 17a572e8bee..b35eafdaf59 100755 --- a/setup.py +++ b/setup.py @@ -208,10 +208,16 @@ if WITH_SETUPTOOLS: self.distribution.salt_installing_m2crypto_windows = True self.run_command('install-m2crypto-windows') self.distribution.salt_installing_m2crypto_windows = None + + # Install PyCrypto self.distribution.salt_installing_pycrypto_windows = True self.run_command('install-pycrypto-windows') self.distribution.salt_installing_pycrypto_windows = None + # Download the required DLLs + self.distribution.salt_download_windows_dlls = True + self.run_command('download-windows-dlls') + self.distribution.salt_download_windows_dlls = None develop.run(self) @@ -270,6 +276,66 @@ class InstallPyCryptoWindowsWheel(Command): call_subprocess(call_arguments) +class DownloadWindowsDlls(Command): + + description = 'Download required DLL\'s for windows' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + if getattr(self.distribution, 'salt_download_windows_dlls', None) is None: + print('This command is not meant to be called on it\'s own') + exit(1) + import platform + from pip.utils.logging import indent_log + platform_bits, _ = platform.architecture() + url= 'http://repo.saltstack.com/windows/dependencies/{bits}/{fname}32.dll' + dest = os.path.join(os.path.dirname(sys.executable), '{fname}32.dll') + with indent_log(): + for fname in ('libeay', 'ssleay'): + furl = url.format(bits=platform_bits[:2], fname=fname) + fdest = dest.format(fname=fname) + if not os.path.exists(fdest): + log.info('Downloading {0}32.dll to {1} from {2}'.format(fname, fdest, furl)) + try: + import requests + from contextlib import closing + with closing(requests.get(url, stream=True)) as req: + if req.status_code == 200: + with open(fdest, 'w') as wfh: + for chunk in req.iter_content(chunk_size=4096): + if chunk: # filter out keep-alive new chunks + wfh.write(chunk) + wfh.flush() + else: + log.error( + 'Failed to download {0}32.dll to {1} from {2}'.format( + fname, fdest, furl + ) + ) + except ImportError: + req = urlopen(url) + + if req.getcode() == 200: + with open(fdest, 'w') as wfh: + while True: + for chunk in req.read(4096): + if not chunk: + break + wfh.write(chunk) + wfh.flush() + else: + log.error( + 'Failed to download {0}32.dll to {1} from {2}'.format( + fname, fdest, furl + ) + ) + + class Sdist(sdist): def make_release_tree(self, base_dir, files): @@ -593,9 +659,14 @@ class Install(install): self.distribution.salt_installing_m2crypto_windows = True self.run_command('install-m2crypto-windows') self.distribution.salt_installing_m2crypto_windows = None + # Install PyCrypto self.distribution.salt_installing_pycrypto_windows = True self.run_command('install-pycrypto-windows') self.distribution.salt_installing_pycrypto_windows = None + # Download the required DLLs + self.distribution.salt_download_windows_dlls = True + self.run_command('download-windows-dlls') + self.distribution.salt_download_windows_dlls = None # Run install.run install.run(self) @@ -711,7 +782,8 @@ class SaltDistribution(distutils.dist.Distribution): self.cmdclass.update({'sdist': CloudSdist, 'install_lib': InstallLib}) if IS_WINDOWS_PLATFORM: - self.cmdclass.update({'install-pycrypto-windows': InstallPyCryptoWindowsWheel}) + self.cmdclass.update({'install-pycrypto-windows': InstallPyCryptoWindowsWheel, + 'download-windows-dlls': DownloadWindowsDlls}) if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable self.cmdclass.update({'install-m2crypto-windows': InstallM2CryptoWindows}) From 71928f2194c48e92fc183edf70eb401928c53cf1 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 17:35:38 +0100 Subject: [PATCH 62/70] Prefer HTTPS, fix url argument --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index b35eafdaf59..af0f98de394 100755 --- a/setup.py +++ b/setup.py @@ -293,7 +293,7 @@ class DownloadWindowsDlls(Command): import platform from pip.utils.logging import indent_log platform_bits, _ = platform.architecture() - url= 'http://repo.saltstack.com/windows/dependencies/{bits}/{fname}32.dll' + url = 'https://repo.saltstack.com/windows/dependencies/{bits}/{fname}32.dll' dest = os.path.join(os.path.dirname(sys.executable), '{fname}32.dll') with indent_log(): for fname in ('libeay', 'ssleay'): @@ -304,7 +304,7 @@ class DownloadWindowsDlls(Command): try: import requests from contextlib import closing - with closing(requests.get(url, stream=True)) as req: + with closing(requests.get(furl, stream=True)) as req: if req.status_code == 200: with open(fdest, 'w') as wfh: for chunk in req.iter_content(chunk_size=4096): @@ -318,7 +318,7 @@ class DownloadWindowsDlls(Command): ) ) except ImportError: - req = urlopen(url) + req = urlopen(furl) if req.getcode() == 200: with open(fdest, 'w') as wfh: From 26246a72eebc9d6f835fcae52da463529c8ad06d Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 17:59:40 +0100 Subject: [PATCH 63/70] Allow writing Salt's _version.py when installing in develop mode. Pass `--write-salt-version` or set the `WRITE_SALT_VERSION` environment variable to trigger the generation of `_version.py`. Closes #25094 --- setup.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/setup.py b/setup.py index af0f98de394..7eea37c4145 100755 --- a/setup.py +++ b/setup.py @@ -201,6 +201,24 @@ class WriteSaltSshPackagingFile(Command): if WITH_SETUPTOOLS: class Develop(develop): + user_options = develop.user_options + [ + ('write-salt-version', None, + 'Generate Salt\'s _version.py file which allows proper version ' + 'reporting. This defaults to False on develop/editable setups.') + ] + boolean_options = develop.boolean_options + [ + 'write-salt-version' + ] + + def initialize_options(self): + develop.initialize_options(self) + self.write_salt_version = False + + def finalize_options(self): + develop.finalize_options(self) + if 'WRITE_SALT_VERSION' in os.environ: + self.write_salt_version = True + def run(self): if IS_WINDOWS_PLATFORM: if __saltstack_version__.info < (2015, 8): # pylint: disable=undefined-variable @@ -218,6 +236,10 @@ if WITH_SETUPTOOLS: self.distribution.salt_download_windows_dlls = True self.run_command('download-windows-dlls') self.distribution.salt_download_windows_dlls = None + + if self.write_salt_version is True: + self.distribution.salt_version_hardcoded_path = SALT_VERSION_HARDCODED + self.run_command('write-salt-version') develop.run(self) From b1105fc7068dc0de6d5eb6aca04bf74bce209349 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 18:32:30 +0100 Subject: [PATCH 64/70] Allow mimicking the install setup command for develop/editable installations. To generate Salt's _syspaths.py file, pass `--generate-salt-syspaths` to the develop command or set the `GENERATE_SALT_SYSPATHS` environment variable. Passing `--mimic-salt-install` to the develop command or setting the `MIMIC_SALT_INSTALL` environment variable will generate `_version.py` and `_syspaths.py` Fixes #11046 Fixes #25094 --- setup.py | 91 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index 7eea37c4145..5980be2866e 100755 --- a/setup.py +++ b/setup.py @@ -104,6 +104,7 @@ except ImportError: SALT_VERSION = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', 'version.py') SALT_VERSION_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_version.py') +SALT_SYSPATHS_HARDCODED = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', '_syspaths.py') SALT_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), '_requirements.txt') SALT_ZEROMQ_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'zeromq-requirements.txt') SALT_RAET_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'raet-requirements.txt') @@ -173,6 +174,40 @@ class WriteSaltVersion(Command): # pylint: enable=E0602 +class GenerateSaltSyspaths(Command): + + description = 'Generate salt\'s hardcoded syspaths file' + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + # Write the syspaths file + if getattr(self.distribution, 'salt_syspaths_hardcoded_path', None) is None: + print('This command is not meant to be called on it\'s own') + exit(1) + + # Write the system paths file + open(self.distribution.salt_syspaths_hardcoded_path, 'w').write( + INSTALL_SYSPATHS_TEMPLATE.format( + date=datetime.utcnow(), + root_dir=self.distribution.salt_root_dir, + config_dir=self.distribution.salt_config_dir, + cache_dir=self.distribution.salt_cache_dir, + sock_dir=self.distribution.salt_sock_dir, + srv_root_dir=self.distribution.salt_srv_root_dir, + base_file_roots_dir=self.distribution.salt_base_file_roots_dir, + base_pillar_roots_dir=self.distribution.salt_base_pillar_roots_dir, + base_master_roots_dir=self.distribution.salt_base_master_roots_dir, + logs_dir=self.distribution.salt_logs_dir, + pidfile_dir=self.distribution.salt_pidfile_dir, + ) + ) + + class WriteSaltSshPackagingFile(Command): description = 'Write salt\'s ssh packaging file' @@ -204,20 +239,46 @@ if WITH_SETUPTOOLS: user_options = develop.user_options + [ ('write-salt-version', None, 'Generate Salt\'s _version.py file which allows proper version ' - 'reporting. This defaults to False on develop/editable setups.') + 'reporting. This defaults to False on develop/editable setups. ' + 'If WRITE_SALT_VERSION is found in the environment this flag is ' + 'switched to True.'), + ('generate-salt-syspaths', None, + 'Generate Salt\'s _syspaths.py file which allows tweaking some ' + 'common paths that salt uses. This defaults to False on ' + 'develop/editable setups. If GENERATE_SALT_SYSPATHS is found in ' + 'the environment this flag is switched to True.'), + ('mimic-install', None, + 'Mimmic the install command when running the develop command. ' + 'This will generate salt\'s _version.py and _syspaths.py files. ' + 'Generate Salt\'s _syspaths.py file which allows tweaking some ' + 'This defaults to False on develop/editable setups. ' + 'If MIMIC_INSTALL is found in the environment this flag is ' + 'switched to True.') ] boolean_options = develop.boolean_options + [ - 'write-salt-version' + 'write-salt-version', + 'generate-salt-syspaths', + 'mimic-salt-install' ] def initialize_options(self): develop.initialize_options(self) self.write_salt_version = False + self.generate_salt_syspaths = False + self.mimic_salt_install = False def finalize_options(self): develop.finalize_options(self) if 'WRITE_SALT_VERSION' in os.environ: self.write_salt_version = True + if 'GENERATE_SALT_SYSPATHS' in os.environ: + self.generate_salt_syspaths = True + if 'MIMIC_SALT_INSTALL' in os.environ: + self.mimic_salt_install = True + + if self.mimic_salt_install: + self.write_salt_version = True + self.generate_salt_syspaths = True def run(self): if IS_WINDOWS_PLATFORM: @@ -238,8 +299,15 @@ if WITH_SETUPTOOLS: self.distribution.salt_download_windows_dlls = None if self.write_salt_version is True: + self.distribution.running_salt_install = True self.distribution.salt_version_hardcoded_path = SALT_VERSION_HARDCODED self.run_command('write-salt-version') + + if self.generate_salt_syspaths: + self.distribution.salt_syspaths_hardcoded_path = SALT_SYSPATHS_HARDCODED + self.run_command('generate-salt-syspaths') + + # Resume normal execution develop.run(self) @@ -565,24 +633,10 @@ class Build(build): self.run_command('write-salt-version') # Write the system paths file - system_paths_file_path = os.path.join( + self.distribution.salt_syspaths_hardcoded_path = os.path.join( self.build_lib, 'salt', '_syspaths.py' ) - open(system_paths_file_path, 'w').write( - INSTALL_SYSPATHS_TEMPLATE.format( - date=datetime.utcnow(), - root_dir=self.distribution.salt_root_dir, - config_dir=self.distribution.salt_config_dir, - cache_dir=self.distribution.salt_cache_dir, - sock_dir=self.distribution.salt_sock_dir, - srv_root_dir=self.distribution.salt_srv_root_dir, - base_file_roots_dir=self.distribution.salt_base_file_roots_dir, - base_pillar_roots_dir=self.distribution.salt_base_pillar_roots_dir, - base_master_roots_dir=self.distribution.salt_base_master_roots_dir, - logs_dir=self.distribution.salt_logs_dir, - pidfile_dir=self.distribution.salt_pidfile_dir, - ) - ) + self.run_command('generate-salt-syspaths') class Install(install): @@ -799,6 +853,7 @@ class SaltDistribution(distutils.dist.Distribution): 'sdist': Sdist, 'install': Install, 'write-salt-version': WriteSaltVersion, + 'generate-salt-syspaths': GenerateSaltSyspaths, 'write-salt-ssh-packaging-file': WriteSaltSshPackaingFile}) if not IS_WINDOWS_PLATFORM: self.cmdclass.update({'sdist': CloudSdist, From 72d2fdb51253c012fdbea6d5ab5f3faa546004ca Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 14:04:14 +0100 Subject: [PATCH 65/70] Add `pypiwin32 >= 219` as a windows install requires. Refs #26305 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 5980be2866e..6b447e28ca1 100755 --- a/setup.py +++ b/setup.py @@ -983,6 +983,7 @@ class SaltDistribution(distutils.dist.Distribution): if IS_WINDOWS_PLATFORM: install_requires.append('WMI') + install_requires.append('pypiwin32 >= 219') if self.salt_transport == 'zeromq': install_requires += _parse_requirements_file(SALT_ZEROMQ_REQS) From 92af1c9572a747101e2f710494784a494f7d47ed Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 18:44:16 +0100 Subject: [PATCH 66/70] Fix argument name --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6b447e28ca1..a0311764f8f 100755 --- a/setup.py +++ b/setup.py @@ -247,7 +247,7 @@ if WITH_SETUPTOOLS: 'common paths that salt uses. This defaults to False on ' 'develop/editable setups. If GENERATE_SALT_SYSPATHS is found in ' 'the environment this flag is switched to True.'), - ('mimic-install', None, + ('mimic-salt-install', None, 'Mimmic the install command when running the develop command. ' 'This will generate salt\'s _version.py and _syspaths.py files. ' 'Generate Salt\'s _syspaths.py file which allows tweaking some ' From e7cb3be2a0fdbf2b36f5737de804cf80084eddb0 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Fri, 14 Aug 2015 22:05:29 +0100 Subject: [PATCH 67/70] Document the added options --- doc/topics/development/hacking.rst | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/doc/topics/development/hacking.rst b/doc/topics/development/hacking.rst index 5402417bbff..3336bbd7b0e 100644 --- a/doc/topics/development/hacking.rst +++ b/doc/topics/development/hacking.rst @@ -212,6 +212,48 @@ and 103 characters on BSD-based systems. ` instructions. +Changing Default Paths +~~~~~~~~~~~~~~~~~~~~~~ + +Instead of updating your configuration files to point to the new root directory +and having to pass the new configuration directory path to all of Salt's CLI +tools, you can explicitly tweak the default system paths that Salt expects: + +.. code-block:: bash + + GENERATE_SALT_SYSPATHS=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \ + install -e ./salt # the path to the salt git clone from above + + +You can now call all of Salt's CLI tools without explicitly passing the configuration directory. + +Additional Options +.................. + +In case you want to distribute your virtualenv, you probably don't want to +include Salt's clone ``.git/`` directory, and, without it, Salt won't report +the accurate version. You can tell ``setup.py`` to generate the hardcoded +version information which is distributable: + +.. code-block:: bash + + GENERATE_SALT_SYSPATHS=1 WRITE_SALT_VERSION=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \ + install -e ./salt # the path to the salt git clone from above + + +Instead of passing those two environmental variables, you can just pass a +single one which will trigger the other two: + +.. code-block:: bash + + MIMIC_SALT_INSTALL=1 pip --global-option='--salt-root-dir=/path/to/your/virtualenv/' \ + install -e ./salt # the path to the salt git clone from above + + +This last one will grant you an edditable salt installation with hardcoded +system paths and version information. + + Installing Salt from the Python Package Index --------------------------------------------- From ad5fa03b768ebd0478dd313420200d1505ba5335 Mon Sep 17 00:00:00 2001 From: twangboy Date: Mon, 17 Aug 2015 14:18:31 -0600 Subject: [PATCH 68/70] Removed documentation no longer required --- salt/states/winrepo.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/salt/states/winrepo.py b/salt/states/winrepo.py index ee5a1b6ff8b..27f11881b5f 100644 --- a/salt/states/winrepo.py +++ b/salt/states/winrepo.py @@ -1,11 +1,6 @@ # -*- coding: utf-8 -*- ''' Manage Windows Package Repository - -.. note:: - - This state only loads on minions that have the ``roles: salt-master`` grain - set. ''' from __future__ import absolute_import From 8898d64918ef0ec7c0f178990acaaca64778789b Mon Sep 17 00:00:00 2001 From: TheBigBear Date: Mon, 17 Aug 2015 22:01:50 +0100 Subject: [PATCH 69/70] dependency zip files moved to new site --- doc/topics/installation/windows.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/topics/installation/windows.rst b/doc/topics/installation/windows.rst index 2473fdbb5f7..76ad766fefc 100644 --- a/doc/topics/installation/windows.rst +++ b/doc/topics/installation/windows.rst @@ -139,8 +139,8 @@ Install the following software: Download the Prerequisite zip file for your CPU architecture from the SaltStack download site: -* `Salt32.zip `_ -* `Salt64.zip `_ +* `Salt32.zip `_ +* `Salt64.zip `_ These files contain all sofware required to build and develop salt. Unzip the contents of the file to ``C:\Salt-Dev\temp``. From 81d351ff8fff8bc0de397b482382942fe3ceb600 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Mon, 17 Aug 2015 15:16:18 -0600 Subject: [PATCH 70/70] fix syntax error in lvm exec module Fixes #26404. --- salt/modules/linux_lvm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py index 97d8765b661..4a56f409457 100644 --- a/salt/modules/linux_lvm.py +++ b/salt/modules/linux_lvm.py @@ -353,7 +353,7 @@ def vgremove(vgname): salt mymachine lvm.vgremove vgname salt mymachine lvm.vgremove vgname force=True ''' - cmd = ['vgremove' '-f', vgname] + cmd = ['vgremove', '-f', vgname] out = __salt__['cmd.run'](cmd, python_shell=False) return out.strip()