From d1be5519e60e0d111715ba4cceb9b0f6d428c171 Mon Sep 17 00:00:00 2001 From: Mike Wallis Date: Fri, 8 Oct 2021 12:29:55 +0100 Subject: [PATCH] Whitespaces in paths or current working directory path of playbook causes rsync to incorrectly chdir to current source dir, Example : cd "/home/a/ansible plays" task: - synchronize: src: a dest: b Results in the following error being thrown fatal: [remote-host]: FAILED! => {"changed": false, "cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh='/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' --rsync-path='sudo -u root rsync' --out-format='<>%i %n%L' /home/a/ansible plays/deployments// remote-user@remote-host:/data/", "msg": "rsync: [sender] link_stat \"/home/a/ansible\" failed: No such file or directory (2)\nrsync: [sender] change_dir \"/home/a/ansible plays/plays/a/\" failed: No such file or directory (2)\nrsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1330) [sender=3.2.3]\n", "rc": 23} --- .../shell_escape_full_path_for_rsync.yml | 3 ++ plugins/modules/synchronize.py | 4 +- .../targets/synchronize/tasks/main.yml | 43 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/shell_escape_full_path_for_rsync.yml diff --git a/changelogs/fragments/shell_escape_full_path_for_rsync.yml b/changelogs/fragments/shell_escape_full_path_for_rsync.yml new file mode 100644 index 0000000000..d37bee7fa8 --- /dev/null +++ b/changelogs/fragments/shell_escape_full_path_for_rsync.yml @@ -0,0 +1,3 @@ +--- +bugfixes: + - Fix for whitespace in source full path causing error ```code 23) at main.c(1330) [sender=3.2.3]``` (https://github.com/ansible-collections/ansible.posix/pull/278) diff --git a/plugins/modules/synchronize.py b/plugins/modules/synchronize.py index 5f63dd4860..86cf360d43 100644 --- a/plugins/modules/synchronize.py +++ b/plugins/modules/synchronize.py @@ -587,8 +587,8 @@ def main(): if '@' not in dest: dest = os.path.expanduser(dest) - cmd.append(source) - cmd.append(dest) + cmd.append(shlex_quote(source)) + cmd.append(shlex_quote(dest)) cmdstr = ' '.join(cmd) # If we are using password authentication, write the password into the pipe diff --git a/tests/integration/targets/synchronize/tasks/main.yml b/tests/integration/targets/synchronize/tasks/main.yml index 8df2c75d6c..125a406f3b 100644 --- a/tests/integration/targets/synchronize/tasks/main.yml +++ b/tests/integration/targets/synchronize/tasks/main.yml @@ -265,3 +265,46 @@ - directory_a/foo.txt - directory_a - directory_b + +- name: setup - test for source with working dir with spaces in path + file: + state: directory + path: '{{output_dir}}/{{item}}' + delegate_to: '{{ inventory_hostname }}' + with_items: + - 'directory a' + - 'directory b' +- name: setup - create test new files + copy: + dest: '{{output_dir}}/directory a/{{item}}' + mode: '0644' + content: 'hello world' + with_items: + - foo.txt + delegate_to: '{{ inventory_hostname }}' +- name: copy source with spaces in dir path + synchronize: + src: '{{output_dir}}/directory a/foo.txt' + dest: '{{output_dir}}/directory b/' + delegate_to: '{{ inventory_hostname }}' + register: sync_result + ignore_errors: true +- name: get stat information for directory_b + stat: + path: '{{ output_dir }}/directory b/foo.txt' + register: stat_result_b +- assert: + that: + - '''changed'' in sync_result' + - sync_result.changed == true + - stat_result_b.stat.exists == True + - stat_result_b.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' +- name: Cleanup + file: + state: absent + path: '{{output_dir}}/{{item}}' + with_items: + - 'directory b/foo.txt' + - 'directory a/foo.txt' + - 'directory a' + - 'directory b'