Allow Salt Cloud to use either SCP or SFTP, as configured

This commit is contained in:
Joseph Hall 2015-05-12 02:05:27 -06:00 committed by rallytime
parent 13facbf077
commit bbec34abd3
2 changed files with 57 additions and 34 deletions

View File

@ -28,14 +28,16 @@ This has also been tested to work with pipes, if needed:
script_args: | head
Use SFTP to transfer files
==========================
Some distributions do not have scp distributed with the ssh package. The
solution is to use sftp with the `use_sftp` flag
Selecting the File Transport
============================
By default, Salt Cloud uses SFTP to transfer files to Linux hosts. However, if
SFTP is not available, or specific SCP functionality is needed, Salt Cloud can
be configured to use SCP instead.
.. code-block:: yaml
use_sftp: True
file_transport: sftp
file_transport: scp
Sync After Install

View File

@ -324,6 +324,11 @@ def bootstrap(vm_, opts):
'ssh_username', vm_, opts, default='root'
)
if 'file_transport' not in opts:
opts['file_transport'] = vm_.get('file_transport', 'sftp')
# NOTE: deploy_kwargs is also used to pass inline_script variable content
# to run_inline_script function
deploy_kwargs = {
'opts': opts,
'host': vm_['ssh_host'],
@ -1085,24 +1090,24 @@ def deploy_script(host,
if remote_dir not in remote_dirs:
root_cmd('mkdir -p \'{0}\''.format(remote_dir), tty, sudo, **ssh_kwargs)
remote_dirs.append(remote_dir)
sftp_file(
remote_file, kwargs=ssh_kwargs, local_file=local_file
ssh_file(
opts, remote_file, kwargs=ssh_kwargs, local_file=local_file
)
file_map_success.append({local_file: remote_file})
# Minion configuration
if minion_pem:
sftp_file('{0}/minion.pem'.format(tmp_dir), minion_pem, ssh_kwargs)
ssh_file(opts, '{0}/minion.pem'.format(tmp_dir), minion_pem, ssh_kwargs)
ret = root_cmd('chmod 600 \'{0}/minion.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
raise SaltCloudSystemExit(
'Cant set perms on {0}/minion.pem'.format(tmp_dir))
if minion_pub:
sftp_file('{0}/minion.pub'.format(tmp_dir), minion_pub, ssh_kwargs)
ssh_file(opts, '{0}/minion.pub'.format(tmp_dir), minion_pub, ssh_kwargs)
if master_sign_pub_file:
sftp_file('{0}/master_sign.pub'.format(tmp_dir), kwargs=ssh_kwargs, local_file=master_sign_pub_file)
ssh_file(opts, '{0}/master_sign.pub'.format(tmp_dir), kwargs=ssh_kwargs, local_file=master_sign_pub_file)
if minion_conf:
if not isinstance(minion_conf, dict):
@ -1115,12 +1120,14 @@ def deploy_script(host,
)
minion_grains = minion_conf.pop('grains', {})
if minion_grains:
sftp_file(
ssh_file(
opts,
'{0}/grains'.format(tmp_dir),
salt_config_to_yaml(minion_grains),
ssh_kwargs
)
sftp_file(
ssh_file(
opts,
'{0}/minion'.format(tmp_dir),
salt_config_to_yaml(minion_conf),
ssh_kwargs
@ -1128,7 +1135,7 @@ def deploy_script(host,
# Master configuration
if master_pem:
sftp_file('{0}/master.pem'.format(tmp_dir), master_pem, ssh_kwargs)
ssh_file(opts, '{0}/master.pem'.format(tmp_dir), master_pem, ssh_kwargs)
ret = root_cmd('chmod 600 \'{0}/master.pem\''.format(tmp_dir),
tty, sudo, **ssh_kwargs)
if ret:
@ -1136,7 +1143,7 @@ def deploy_script(host,
'Cant set perms on {0}/master.pem'.format(tmp_dir))
if master_pub:
sftp_file('{0}/master.pub'.format(tmp_dir), master_pub, ssh_kwargs)
ssh_file(opts, '{0}/master.pub'.format(tmp_dir), master_pub, ssh_kwargs)
if master_conf:
if not isinstance(master_conf, dict):
@ -1148,7 +1155,8 @@ def deploy_script(host,
'Loading from YAML ...'
)
sftp_file(
ssh_file(
opts,
'{0}/master'.format(tmp_dir),
salt_config_to_yaml(master_conf),
ssh_kwargs
@ -1187,7 +1195,7 @@ def deploy_script(host,
rpath = os.path.join(
preseed_minion_keys_tempdir, minion_id
)
sftp_file(rpath, minion_key, ssh_kwargs)
ssh_file(opts, rpath, minion_key, ssh_kwargs)
if ssh_kwargs['username'] != 'root':
root_cmd(
@ -1205,7 +1213,7 @@ def deploy_script(host,
if script:
# got strange escaping issues with sudoer, going onto a
# subshell fixes that
sftp_file('{0}/deploy.sh'.format(tmp_dir), script, ssh_kwargs)
ssh_file(opts, '{0}/deploy.sh'.format(tmp_dir), script, ssh_kwargs)
ret = root_cmd(
('sh -c "( chmod +x \'{0}/deploy.sh\' )";'
'exit $?').format(tmp_dir),
@ -1267,7 +1275,8 @@ def deploy_script(host,
environ_script_contents.append(deploy_command)
# Upload our environ setter wrapper
sftp_file(
ssh_file(
opts,
'{0}/environ-deploy-wrapper.sh'.format(tmp_dir),
'\n'.join(environ_script_contents),
ssh_kwargs
@ -1470,13 +1479,14 @@ def _exec_ssh_cmd(cmd, error_msg=None, allow_failure=False, **kwargs):
return 1
def scp_file(dest_path, contents, kwargs):
def scp_file(dest_path, contents=None, kwargs=None, local_file=None):
'''
Use scp or sftp to copy a file to a server
'''
tmpfh, tmppath = tempfile.mkstemp()
with salt.utils.fopen(tmppath, 'w') as tmpfile:
tmpfile.write(contents)
if contents is not None:
tmpfh, tmppath = tempfile.mkstemp()
with salt.utils.fopen(tmppath, 'w') as tmpfile:
tmpfile.write(contents)
log.debug('Uploading {0} to {1}'.format(dest_path, kwargs['hostname']))
@ -1488,6 +1498,12 @@ def scp_file(dest_path, contents, kwargs):
# Don't re-use the SSH connection. Less failures.
'-oControlPath=none'
]
if local_file is not None:
tmppath = local_file
if os.path.isdir(local_file):
ssh_args.append('-r')
if 'key_filename' in kwargs:
# There should never be both a password and an ssh key passed in, so
ssh_args.extend([
@ -1534,20 +1550,15 @@ def scp_file(dest_path, contents, kwargs):
ssh_gateway_port
)
)
if kwargs.get('use_sftp', False) is True:
cmd = 'sftp {0} {2[username]}@{2[hostname]} <<< "put {1} {3}"'.format(
cmd = (
'scp {0} {1} {2[username]}@{2[hostname]}:{3} || '
'echo "put {1} {3}" | sftp {0} {2[username]}@{2[hostname]} || '
'rsync -avz -e "ssh {0}" {1} {2[username]}@{2[hostname]}:{3}'.format(
' '.join(ssh_args), tmppath, kwargs, dest_path
)
log.debug('SFTP command: {0!r}'.format(cmd))
else:
cmd = (
'scp {0} {1} {2[username]}@{2[hostname]}:{3} || '
'echo "put {1} {3}" | sftp {0} {2[username]}@{2[hostname]} || '
'rsync -avz -e "ssh {0}" {1} {2[username]}@{2[hostname]}:{3}'.format(
' '.join(ssh_args), tmppath, kwargs, dest_path
)
)
log.debug('SCP command: {0!r}'.format(cmd))
)
log.debug('SCP command: {0!r}'.format(cmd))
retcode = _exec_ssh_cmd(cmd,
error_msg='Failed to upload file {0!r}: {1}\n{2}',
password_retries=3,
@ -1555,6 +1566,16 @@ def scp_file(dest_path, contents, kwargs):
return retcode
def ssh_file(opts, dest_path, contents=None, kwargs=None, local_file=None):
'''
Copies a file to the remote SSH target using either sftp or scp, as
configured.
'''
if opts.get('file_transport', 'sftp') == 'sftp':
return sftp_file(dest_path, contents, kwargs, local_file)
return scp_file(dest_path, contents, kwargs, local_file)
def sftp_file(dest_path, contents=None, kwargs=None, local_file=None):
'''
Use sftp to upload a file to a server