Skip to content

Commit

Permalink
Misc SSH fixes/improvemnts
Browse files Browse the repository at this point in the history
- Reformatted the SSH SHIM script to be readable
- added more pythons to SHIM
   - RHEL python altinstalls are ...2.x not 2x
- added tty params around to allow tty specification in roster
- TTY=True is not working, see TODO
- Replaced "sudo -i" with individual "sudo" invocations in the SHIM
  - supports systems where exec'ing a shell with sudo is forbidden
  - Also precludes tainting environment with users login shell
- Added some more SSH options per salt.cloud (@s0undt3ch)
  • Loading branch information
ajithhub authored and basepi committed Oct 7, 2013
1 parent c72ce30 commit 2a1c4fc
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 50 deletions.
106 changes: 56 additions & 50 deletions salt/client/ssh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,46 +24,55 @@
import salt.minion
import salt.exceptions

# This is just a delimiter to distinguish the beginning of salt STDOUT. There
# is no special meaning
RSTR = '_edbc7885e4f9aac9b83b35999b68d015148caf467b78fa39c05f669c0ff89878'

HEREDOC = (' << "EOF"\n'
'{{0}}\n'
'set -x\n'
' for py_candidate in \\\n'
' python27 \\\n'
' python2.7 \\\n'
' python26 \\\n'
' python2.6 \\\n'
' python2 \\\n'
' python ;\n'
' do \n'

' if [ `type -p $py_candidate` ] \n'
' then \n'
' PYTHON=$py_candidate \n'
' break \n'
' fi \n'
' done \n'
'if [ -f /tmp/.salt/salt-call ] \n'
'then\n'
' if [[ $(cat /tmp/.salt/version) != {0} ]]\n'
' then\n'
' rm -rf /tmp/.salt\n'
' install -m 1777 -d /tmp/.salt\n'
' echo "{1}"\n'
' echo "deploy"\n'
' exit 1\n'
' fi\n'
' SALT=/tmp/.salt/salt-call\n'
'else\n'
' echo "{1}"\n'
' install -m 1777 -d /tmp/.salt\n'
' echo "deploy"\n'
' exit 1\n'
'fi\n'
'echo "{1}"\n'
'$PYTHON $SALT --local --out json -l quiet {{1}}\n'
'EOF').format(salt.__version__, RSTR)

# This shim facilitaites remote salt-call operations
# 1. Identify a suitable python
# 2. Test for remote salt-call and version if present
# 3. Signal to (re)deploy if missing or out of date
# 4. Perform salt-call

# Note there are two levels of formatting.
# - First format pass inserts salt version and delimiter
# - Second pass at run-time and inserts optional "sudo" and command
SSH_SHIM = ''' << 'EOF'
for py_candidate in \\
python27 \\
python2.7 \\
python26 \\
python2.6 \\
python2 \\
python ;
do
if [ `type -p $py_candidate` ]
then
PYTHON=$(type -p $py_candidate)
break
fi
done
if [ -f /tmp/.salt/salt-call ]
then
if [[ $(cat /tmp/.salt/version) != {0} ]]
then
{{0}} rm -rf /tmp/.salt
{{0}} install -m 1777 -d /tmp/.salt
echo "{1}"
echo "deploy"
exit 1
fi
SALT=/tmp/.salt/salt-call
else
echo "{1}"
{{0}} install -m 1777 -d /tmp/.salt
echo "deploy"
exit 1
fi
echo "{1}"
{{0}} $PYTHON $SALT --local --out json -l quiet {{1}}
EOF\n'''.format(salt.__version__, RSTR)

class SSH(object):
'''
Expand All @@ -72,7 +81,8 @@ class SSH(object):
def __init__(self, opts):
self.verify_env()
self.opts = opts
tgt_type = self.opts['selected_target_option'] if self.opts['selected_target_option'] else 'glob'
tgt_type = self.opts['selected_target_option'] \
if self.opts['selected_target_option'] else 'glob'
self.roster = salt.roster.Roster(opts)
self.targets = self.roster.targets(
self.opts['tgt'],
Expand Down Expand Up @@ -360,6 +370,7 @@ def __init__(
priv=None,
timeout=None,
sudo=False,
tty=False,
**kwargs):
self.opts = opts
self.arg_str = arg_str
Expand All @@ -372,7 +383,8 @@ def __init__(
'passwd': passwd,
'priv': priv,
'timeout': timeout,
'sudo': sudo}
'sudo': sudo,
'tty': tty}
self.shell = salt.client.ssh.shell.Shell(**args)

self.target = kwargs
Expand Down Expand Up @@ -482,11 +494,9 @@ def cmd(self):
args, kwargs = salt.minion.parse_args_and_kwargs(
self.sls_seed, self.arg)
self.sls_seed(*args, **kwargs)
sudo = 'sudo -i\n' if self.target['sudo'] else ''
cmd = HEREDOC.format(sudo, self.arg_str)
sudo = 'sudo' if self.target['sudo'] else ''
cmd = SSH_SHIM.format(sudo, self.arg_str)
for stdout, stderr in self.shell.exec_nb_cmd(cmd):
print stdout
print stderr
yield stdout, stderr

def cmd_block(self):
Expand All @@ -497,13 +507,9 @@ def cmd_block(self):
# 2. check is salt-call is on the target
# 3. deploy salt-thin
# 4. execute command
sudo = 'sudo -i\n' if self.target['sudo'] else ''
cmd = HEREDOC.format(sudo, self.arg_str)
sudo = 'sudo' if self.target['sudo'] else ''
cmd = SSH_SHIM.format(sudo, self.arg_str)
stdout, stderr = self.shell.exec_cmd(cmd)
print "THIS IS STDOUT"
print stdout
print "THIS IS STDERR"
print stderr
if RSTR in stdout:
stdout = stdout.split(RSTR)[1].strip()
if stdout.startswith('deploy'):
Expand Down
17 changes: 17 additions & 0 deletions salt/client/ssh/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,24 @@ def _passwd_opts(self):
'''
Return options to pass to sshpass
'''
# TODO ControlMaster does not work without ControlPath
# user could take advange of it if they set ControlPath in thier
# ssh config. Also, ControlPersist not widely available.
options = ['ControlMaster=auto',
'StrictHostKeyChecking=no',
'GSSAPIAuthentication=no',
]
options.append('ConnectTimeout={0}'.format(self.timeout))

if self.passwd:
options.extend(['PasswordAuthentication=yes',
'PubkeyAuthentication=no'])
else:
options.extend(['PasswordAuthentication=no',
'PubkeyAuthentication=yes',
'KbdInteractiveAuthentication=no',
'ChallengeResponseAuthentication=no',
'BatchMode=yes'])
if self.port:
options.append('Port={0}'.format(self.port))
if self.user:
Expand Down Expand Up @@ -127,6 +140,10 @@ def _cmd_str(self, cmd, ssh='ssh'):
'''
Return the cmd string to execute
'''

# TODO: if tty, then our SSH_SHIM cannot be supplied from STDIN Will
# need to deliver the SHIM to the remote host and execute it there

if self.passwd and salt.utils.which('sshpass'):
opts = self._passwd_opts()
return 'sshpass -p "{0}" {1} {2} {3} {4} {5}'.format(
Expand Down

0 comments on commit 2a1c4fc

Please sign in to comment.