synchronize: Convert cmd to list and fix handling of the copy_links argument (#22573)

* synchronize: Convert cmd to list and fix handling of the copy_links argument

Converting cmd from str to list stops the pain of argument quoting/escaping.

* synchronize: Update imports according to #pullrequestreview-28758614
This commit is contained in:
Erwin Lang 2017-03-24 17:22:45 +01:00 committed by Toshio Kuratomi
parent 65d9feea4f
commit f7c9f44aab

View file

@ -310,6 +310,20 @@ EXAMPLES = '''
- "--no-motd" - "--no-motd"
- "--exclude=.git" - "--exclude=.git"
''' '''
import os
# Python3 compat. six.moves.shlex_quote will be available once we're free to
# upgrade beyond six-1.4 module-side.
try:
from shlex import quote as shlex_quote
except ImportError:
from pipes import quote as shlex_quote
from ansible.module_utils.basic import AnsibleModule
client_addr = None client_addr = None
@ -351,7 +365,7 @@ def main():
dirs = dict(default='no', type='bool'), dirs = dict(default='no', type='bool'),
recursive = dict(type='bool'), recursive = dict(type='bool'),
links = dict(type='bool'), links = dict(type='bool'),
copy_links = dict(type='bool'), copy_links = dict(default='no', type='bool'),
perms = dict(type='bool'), perms = dict(type='bool'),
times = dict(type='bool'), times = dict(type='bool'),
owner = dict(type='bool'), owner = dict(type='bool'),
@ -369,13 +383,13 @@ def main():
if module.params['_substitute_controller']: if module.params['_substitute_controller']:
try: try:
source = '"' + substitute_controller(module.params['src']) + '"' source = substitute_controller(module.params['src'])
dest = '"' + substitute_controller(module.params['dest']) + '"' dest = substitute_controller(module.params['dest'])
except ValueError: except ValueError:
module.fail_json(msg='Could not determine controller hostname for rsync to send to') module.fail_json(msg='Could not determine controller hostname for rsync to send to')
else: else:
source = '"' + module.params['src'] + '"' source = module.params['src']
dest = '"' + module.params['dest'] + '"' dest = module.params['dest']
dest_port = module.params['dest_port'] dest_port = module.params['dest_port']
delete = module.params['delete'] delete = module.params['delete']
private_key = module.params['private_key'] private_key = module.params['private_key']
@ -403,90 +417,81 @@ def main():
if '/' not in rsync: if '/' not in rsync:
rsync = module.get_bin_path(rsync, required=True) rsync = module.get_bin_path(rsync, required=True)
ssh = module.get_bin_path('ssh', required=True) cmd = [rsync, '--delay-updates', '-F']
cmd = '%s --delay-updates -F' % rsync
if compress: if compress:
cmd = cmd + ' --compress' cmd.append('--compress')
if rsync_timeout: if rsync_timeout:
cmd = cmd + ' --timeout=%s' % rsync_timeout cmd.append('--timeout=%s' % rsync_timeout)
if module.check_mode: if module.check_mode:
cmd = cmd + ' --dry-run' cmd.append('--dry-run')
if delete: if delete:
cmd = cmd + ' --delete-after' cmd.append('--delete-after')
if existing_only: if existing_only:
cmd = cmd + ' --existing' cmd.append('--existing')
if checksum: if checksum:
cmd = cmd + ' --checksum' cmd.append('--checksum')
if copy_links:
cmd.append('--copy-links')
if archive: if archive:
cmd = cmd + ' --archive' cmd.append('--archive')
if recursive is False: if recursive is False:
cmd = cmd + ' --no-recursive' cmd.append('--no-recursive')
if links is False: if links is False:
cmd = cmd + ' --no-links' cmd.append('--no-links')
if copy_links is True:
cmd = cmd + ' --copy-links'
if perms is False: if perms is False:
cmd = cmd + ' --no-perms' cmd.append('--no-perms')
if times is False: if times is False:
cmd = cmd + ' --no-times' cmd.append('--no-times')
if owner is False: if owner is False:
cmd = cmd + ' --no-owner' cmd.append('--no-owner')
if group is False: if group is False:
cmd = cmd + ' --no-group' cmd.append('--no-group')
else: else:
if recursive is True: if recursive is True:
cmd = cmd + ' --recursive' cmd.append('--recursive')
if links is True: if links is True:
cmd = cmd + ' --links' cmd.append('--links')
if copy_links is True:
cmd = cmd + ' --copy-links'
if perms is True: if perms is True:
cmd = cmd + ' --perms' cmd.append('--perms')
if times is True: if times is True:
cmd = cmd + ' --times' cmd.append('--times')
if owner is True: if owner is True:
cmd = cmd + ' --owner' cmd.append('--owner')
if group is True: if group is True:
cmd = cmd + ' --group' cmd.append('--group')
if dirs: if dirs:
cmd = cmd + ' --dirs' cmd.append('--dirs')
if private_key is None:
private_key = ''
else:
private_key = '-i "%s"' % private_key
ssh_opts = '-S none' if source.startswith('rsync://') and dest.startswith('rsync://'):
if not verify_host:
ssh_opts = '%s -o StrictHostKeyChecking=no' % ssh_opts
if ssh_args:
ssh_opts = '%s %s' % (ssh_opts, ssh_args)
if source.startswith('"rsync://') and dest.startswith('"rsync://'):
module.fail_json(msg='either src or dest must be a localhost', rc=1) module.fail_json(msg='either src or dest must be a localhost', rc=1)
if not source.startswith('"rsync://') and not dest.startswith('"rsync://'): if not source.startswith('rsync://') and not dest.startswith('rsync://'):
ssh_cmd = [module.get_bin_path('ssh', required=True), '-S', 'none']
if private_key is not None:
ssh_cmd.extend(['-i', private_key])
# If the user specified a port value # If the user specified a port value
# Note: The action plugin takes care of setting this to a port from # Note: The action plugin takes care of setting this to a port from
# inventory if the user didn't specify an explicit dest_port # inventory if the user didn't specify an explicit dest_port
if dest_port is not None: if dest_port is not None:
cmd += " --rsh 'ssh %s %s -o Port=%s'" % (private_key, ssh_opts, dest_port) ssh_cmd.extend(['-o', 'Port=%s' % dest_port])
else: if not verify_host:
cmd += " --rsh 'ssh %s %s'" % (private_key, ssh_opts) ssh_cmd.extend(['-o', 'StrictHostKeyChecking=no'])
if ssh_args:
ssh_cmd.append(ssh_args)
ssh_cmd_str = ' '.join(shlex_quote(arg) for arg in ssh_cmd)
cmd.append('--rsh=%s' % ssh_cmd_str)
if rsync_path: if rsync_path:
cmd = cmd + " --rsync-path=%s" % (rsync_path) cmd.append('--rsync-path=%s' % rsync_path)
if rsync_opts: if rsync_opts:
cmd = cmd + " " + " ".join(rsync_opts) cmd.extend(rsync_opts)
if partial: if partial:
cmd = cmd + " --partial" cmd.append('--partial')
changed_marker = '<<CHANGED>>' changed_marker = '<<CHANGED>>'
cmd = cmd + " --out-format='" + changed_marker + "%i %n%L'" cmd.append('--out-format=' + changed_marker + '%i %n%L')
# expand the paths # expand the paths
if '@' not in source: if '@' not in source:
@ -494,15 +499,16 @@ def main():
if '@' not in dest: if '@' not in dest:
dest = os.path.expanduser(dest) dest = os.path.expanduser(dest)
cmd = ' '.join([cmd, source, dest]) cmd.append(source)
cmdstr = cmd cmd.append(dest)
cmdstr = ' '.join(cmd)
(rc, out, err) = module.run_command(cmd) (rc, out, err) = module.run_command(cmd)
if rc: if rc:
return module.fail_json(msg=err, rc=rc, cmd=cmdstr) return module.fail_json(msg=err, rc=rc, cmd=cmdstr)
else: else:
changed = changed_marker in out changed = changed_marker in out
out_clean=out.replace(changed_marker,'') out_clean = out.replace(changed_marker, '')
out_lines=out_clean.split('\n') out_lines = out_clean.split('\n')
while '' in out_lines: while '' in out_lines:
out_lines.remove('') out_lines.remove('')
if module._diff: if module._diff:
@ -514,8 +520,6 @@ def main():
return module.exit_json(changed=changed, msg=out_clean, return module.exit_json(changed=changed, msg=out_clean,
rc=rc, cmd=cmdstr, stdout_lines=out_lines) rc=rc, cmd=cmdstr, stdout_lines=out_lines)
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()