mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #46148 from rallytime/merge-2017.7
[2017.7] Merge forward from 2017.7.3 to 2017.7
This commit is contained in:
commit
705caa8cca
5 changed files with 175 additions and 52 deletions
|
@ -9,17 +9,45 @@ Changes for v2017.7.3..v2017.7.4
|
|||
|
||||
Extended changelog courtesy of Todd Stansell (https://github.com/tjstansell/salt-changelogs):
|
||||
|
||||
*Generated at: 2018-02-13T16:29:07Z*
|
||||
*Generated at: 2018-02-16T16:44:38Z*
|
||||
|
||||
Statistics:
|
||||
|
||||
- Total Merges: **4**
|
||||
- Total Issue references: **3**
|
||||
- Total PR references: **7**
|
||||
- Total Merges: **7**
|
||||
- Total Issue references: **4**
|
||||
- Total PR references: **11**
|
||||
|
||||
Changes:
|
||||
|
||||
|
||||
- **PR** `#46066`_: (*rallytime*) Pin tornado version in requirements file
|
||||
@ *2018-02-16T16:40:05Z*
|
||||
|
||||
- **ISSUE** `#45790`_: (*bdarnell*) Test with Tornado 5.0b1
|
||||
| refs: `#46066`_
|
||||
* 32f3d00e44 Merge pull request `#46066`_ from rallytime/pin-tornado
|
||||
* 6dc1a3b9dc Pin tornado version in requirements file
|
||||
|
||||
- **PR** `#46036`_: (*terminalmage*) git.latest: Fix regression with identity file usage
|
||||
@ *2018-02-16T13:57:23Z*
|
||||
|
||||
* 85761ee650 Merge pull request `#46036`_ from terminalmage/issue43769
|
||||
* e2140d9a84 Mock the ssh.key_is_encrypted utils func
|
||||
|
||||
* 169924b3fe Move ssh.key_is_encrypted to a utils module temporarily
|
||||
|
||||
* 54f4d78f7a Only keep ssh.py in the Windows installer
|
||||
|
||||
* 5f04531e1b Keep ssh state and execution modules in the installer
|
||||
|
||||
* f2b69f703d git.latest: Fix regression with identity file usage
|
||||
|
||||
- **PR** `#46009`_: (*Ch3LL*) Add 2017.7.4 Release Notes with PRs
|
||||
@ *2018-02-13T16:40:30Z*
|
||||
|
||||
* 6d534c6e7e Merge pull request `#46009`_ from Ch3LL/rn_7.4
|
||||
* ac0baf4b34 Add 2017.7.4 Release Notes with PRs
|
||||
|
||||
- **PR** `#45981`_: (*gtmanfred*) use local config for vault when masterless
|
||||
@ *2018-02-13T15:22:01Z*
|
||||
|
||||
|
@ -66,6 +94,7 @@ Changes:
|
|||
|
||||
|
||||
.. _`#45742`: https://github.com/saltstack/salt/pull/45742
|
||||
.. _`#45790`: https://github.com/saltstack/salt/issues/45790
|
||||
.. _`#45893`: https://github.com/saltstack/salt/issues/45893
|
||||
.. _`#45902`: https://github.com/saltstack/salt/pull/45902
|
||||
.. _`#45915`: https://github.com/saltstack/salt/issues/45915
|
||||
|
@ -75,6 +104,9 @@ Changes:
|
|||
.. _`#45953`: https://github.com/saltstack/salt/pull/45953
|
||||
.. _`#45976`: https://github.com/saltstack/salt/issues/45976
|
||||
.. _`#45981`: https://github.com/saltstack/salt/pull/45981
|
||||
.. _`#46009`: https://github.com/saltstack/salt/pull/46009
|
||||
.. _`#46036`: https://github.com/saltstack/salt/pull/46036
|
||||
.. _`#46066`: https://github.com/saltstack/salt/pull/46066
|
||||
.. _`bp-45742`: https://github.com/saltstack/salt/pull/45742
|
||||
.. _`bp-45902`: https://github.com/saltstack/salt/pull/45902
|
||||
.. _`bp-45928`: https://github.com/saltstack/salt/pull/45928
|
||||
|
|
|
@ -179,6 +179,28 @@ def _format_git_opts(opts):
|
|||
return _format_opts(opts)
|
||||
|
||||
|
||||
def _find_ssh_exe():
|
||||
'''
|
||||
Windows only: search for Git's bundled ssh.exe in known locations
|
||||
'''
|
||||
# Known locations for Git's ssh.exe in Windows
|
||||
globmasks = [os.path.join(os.getenv('SystemDrive'), os.sep,
|
||||
'Program Files*', 'Git', 'usr', 'bin',
|
||||
'ssh.exe'),
|
||||
os.path.join(os.getenv('SystemDrive'), os.sep,
|
||||
'Program Files*', 'Git', 'bin',
|
||||
'ssh.exe')]
|
||||
for globmask in globmasks:
|
||||
ssh_exe = glob.glob(globmask)
|
||||
if ssh_exe and os.path.isfile(ssh_exe[0]):
|
||||
ret = ssh_exe[0]
|
||||
break
|
||||
else:
|
||||
ret = None
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _git_run(command, cwd=None, user=None, password=None, identity=None,
|
||||
ignore_retcode=False, failhard=True, redirect_stderr=False,
|
||||
saltenv='base', **kwargs):
|
||||
|
@ -239,22 +261,12 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
|
|||
)
|
||||
tmp_ssh_wrapper = None
|
||||
if salt.utils.is_windows():
|
||||
# Known locations for Git's ssh.exe in Windows
|
||||
globmasks = [os.path.join(os.getenv('SystemDrive'), os.sep,
|
||||
'Program Files*', 'Git', 'usr', 'bin',
|
||||
'ssh.exe'),
|
||||
os.path.join(os.getenv('SystemDrive'), os.sep,
|
||||
'Program Files*', 'Git', 'bin',
|
||||
'ssh.exe')]
|
||||
for globmask in globmasks:
|
||||
ssh_exe = glob.glob(globmask)
|
||||
if ssh_exe and os.path.isfile(ssh_exe[0]):
|
||||
env['GIT_SSH_EXE'] = ssh_exe[0]
|
||||
break
|
||||
else:
|
||||
ssh_exe = _find_ssh_exe()
|
||||
if ssh_exe is None:
|
||||
raise CommandExecutionError(
|
||||
'Failed to find ssh.exe, unable to use identity file'
|
||||
)
|
||||
env['GIT_SSH_EXE'] = ssh_exe
|
||||
# Use the windows batch file instead of the bourne shell script
|
||||
ssh_id_wrapper += '.bat'
|
||||
env['GIT_SSH'] = ssh_id_wrapper
|
||||
|
@ -268,7 +280,7 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
|
|||
env['GIT_SSH'] = tmp_ssh_wrapper
|
||||
|
||||
if 'salt-call' not in _salt_cli \
|
||||
and __salt__['ssh.key_is_encrypted'](id_file):
|
||||
and __utils__['ssh.key_is_encrypted'](id_file):
|
||||
errors.append(
|
||||
'Identity file {0} is passphrase-protected and cannot be '
|
||||
'used in a non-interactive command. Using salt-call from '
|
||||
|
@ -295,25 +307,33 @@ def _git_run(command, cwd=None, user=None, password=None, identity=None,
|
|||
redirect_stderr=redirect_stderr,
|
||||
**kwargs)
|
||||
finally:
|
||||
# Cleanup the temporary ssh wrapper file
|
||||
try:
|
||||
__salt__['file.remove'](tmp_ssh_wrapper)
|
||||
log.debug('Removed ssh wrapper file %s', tmp_ssh_wrapper)
|
||||
except AttributeError:
|
||||
# No wrapper was used
|
||||
pass
|
||||
except (SaltInvocationError, CommandExecutionError) as exc:
|
||||
log.warning('Failed to remove ssh wrapper file %s: %s', tmp_ssh_wrapper, exc)
|
||||
if tmp_ssh_wrapper:
|
||||
# Cleanup the temporary ssh wrapper file
|
||||
try:
|
||||
__salt__['file.remove'](tmp_ssh_wrapper)
|
||||
log.debug('Removed ssh wrapper file %s', tmp_ssh_wrapper)
|
||||
except AttributeError:
|
||||
# No wrapper was used
|
||||
pass
|
||||
except (SaltInvocationError, CommandExecutionError) as exc:
|
||||
log.warning(
|
||||
'Failed to remove ssh wrapper file %s: %s',
|
||||
tmp_ssh_wrapper, exc
|
||||
)
|
||||
|
||||
# Cleanup the temporary identity file
|
||||
try:
|
||||
__salt__['file.remove'](tmp_identity_file)
|
||||
log.debug('Removed identity file %s', tmp_identity_file)
|
||||
except AttributeError:
|
||||
# No identify file was used
|
||||
pass
|
||||
except (SaltInvocationError, CommandExecutionError) as exc:
|
||||
log.warning('Failed to remove identity file %s: %s', tmp_identity_file, exc)
|
||||
if tmp_identity_file:
|
||||
# Cleanup the temporary identity file
|
||||
try:
|
||||
__salt__['file.remove'](tmp_identity_file)
|
||||
log.debug('Removed identity file %s', tmp_identity_file)
|
||||
except AttributeError:
|
||||
# No identify file was used
|
||||
pass
|
||||
except (SaltInvocationError, CommandExecutionError) as exc:
|
||||
log.warning(
|
||||
'Failed to remove identity file %s: %s',
|
||||
tmp_identity_file, exc
|
||||
)
|
||||
|
||||
# If the command was successful, no need to try additional IDs
|
||||
if result['retcode'] == 0:
|
||||
|
|
|
@ -1286,18 +1286,4 @@ def key_is_encrypted(key):
|
|||
|
||||
salt '*' ssh.key_is_encrypted /root/id_rsa
|
||||
'''
|
||||
try:
|
||||
with salt.utils.fopen(key, 'r') as fp_:
|
||||
key_data = fp_.read()
|
||||
except (IOError, OSError) as exc:
|
||||
# Raise a CommandExecutionError
|
||||
salt.utils.files.process_read_exception(exc, key)
|
||||
|
||||
is_private_key = re.search(r'BEGIN (?:\w+\s)*PRIVATE KEY', key_data)
|
||||
is_encrypted = 'ENCRYPTED' in key_data
|
||||
del key_data
|
||||
|
||||
if not is_private_key:
|
||||
raise CommandExecutionError('{0} is not a private key'.format(key))
|
||||
|
||||
return is_encrypted
|
||||
return __utils__['ssh.key_is_encrypted'](key)
|
||||
|
|
31
salt/utils/ssh.py
Normal file
31
salt/utils/ssh.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import Python libs
|
||||
import re
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.files
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
|
||||
def key_is_encrypted(key):
|
||||
# NOTE: this is a temporary workaround until we can get salt/modules/ssh.py
|
||||
# working on Windows.
|
||||
try:
|
||||
with salt.utils.fopen(key, 'r') as fp_:
|
||||
key_data = fp_.read()
|
||||
except (IOError, OSError) as exc:
|
||||
# Raise a CommandExecutionError
|
||||
salt.utils.files.process_read_exception(exc, key)
|
||||
|
||||
is_private_key = re.search(r'BEGIN (?:\w+\s)*PRIVATE KEY', key_data)
|
||||
is_encrypted = 'ENCRYPTED' in key_data
|
||||
del key_data
|
||||
|
||||
if not is_private_key:
|
||||
raise CommandExecutionError('{0} is not a private key'.format(key))
|
||||
|
||||
return is_encrypted
|
|
@ -14,6 +14,7 @@ import subprocess
|
|||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import (
|
||||
Mock,
|
||||
MagicMock,
|
||||
patch,
|
||||
NO_MOCK,
|
||||
|
@ -77,7 +78,13 @@ class GitTestCase(TestCase, LoaderModuleMockMixin):
|
|||
Test cases for salt.modules.git
|
||||
'''
|
||||
def setup_loader_modules(self):
|
||||
return {git_mod: {}}
|
||||
return {
|
||||
git_mod: {
|
||||
'__utils__': {
|
||||
'ssh.key_is_encrypted': Mock(return_value=False)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def test_list_worktrees(self):
|
||||
'''
|
||||
|
@ -164,3 +171,50 @@ class GitTestCase(TestCase, LoaderModuleMockMixin):
|
|||
dict([(x, worktree_ret[x]) for x in WORKTREE_INFO
|
||||
if WORKTREE_INFO[x].get('stale', False)])
|
||||
)
|
||||
|
||||
def test__git_run_tmp_wrapper(self):
|
||||
'''
|
||||
When an identity file is specified, make sure we don't attempt to
|
||||
remove a temp wrapper that wasn't created. Windows doesn't use temp
|
||||
wrappers, and *NIX won't unless no username was specified and the path
|
||||
is not executable.
|
||||
'''
|
||||
file_remove_mock = Mock()
|
||||
mock_true = Mock(return_value=True)
|
||||
mock_false = Mock(return_value=False)
|
||||
cmd_mock = MagicMock(return_value={
|
||||
'retcode': 0,
|
||||
'stdout': '',
|
||||
'stderr': '',
|
||||
})
|
||||
with patch.dict(git_mod.__salt__, {'file.file_exists': mock_true,
|
||||
'file.remove': file_remove_mock,
|
||||
'cmd.run_all': cmd_mock,
|
||||
'ssh.key_is_encrypted': mock_false}):
|
||||
|
||||
# Non-windows
|
||||
with patch('salt.utils.is_windows', mock_false), \
|
||||
patch.object(git_mod, '_path_is_executable_others',
|
||||
mock_true):
|
||||
|
||||
# Command doesn't really matter here since we're mocking
|
||||
git_mod._git_run(
|
||||
['git', 'rev-parse', 'HEAD'],
|
||||
cwd='/some/path',
|
||||
user=None,
|
||||
identity='/root/.ssh/id_rsa')
|
||||
|
||||
file_remove_mock.assert_not_called()
|
||||
|
||||
file_remove_mock.reset_mock()
|
||||
with patch('salt.utils.is_windows', mock_true), \
|
||||
patch.object(git_mod, '_find_ssh_exe',
|
||||
MagicMock(return_value=r'C:\Git\ssh.exe')):
|
||||
# Command doesn't really matter here since we're mocking
|
||||
git_mod._git_run(
|
||||
['git', 'rev-parse', 'HEAD'],
|
||||
cwd=r'C:\some\path',
|
||||
user=None,
|
||||
identity=r'C:\ssh\id_rsa')
|
||||
|
||||
file_remove_mock.assert_not_called()
|
||||
|
|
Loading…
Add table
Reference in a new issue