diff --git a/changelogs/fragments/ssh_quote_cp.yml b/changelogs/fragments/ssh_quote_cp.yml new file mode 100644 index 00000000000..eef867606ee --- /dev/null +++ b/changelogs/fragments/ssh_quote_cp.yml @@ -0,0 +1,2 @@ +bugfixes: + - ssh connection - properly quote controlpersist path given by user to avoid issues with spaces and other characters diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py index f6c0ba20275..f888a7d9712 100644 --- a/lib/ansible/plugins/connection/ssh.py +++ b/lib/ansible/plugins/connection/ssh.py @@ -363,7 +363,6 @@ import subprocess import time from functools import wraps -from ansible import constants as C from ansible.errors import ( AnsibleAuthenticationFailure, AnsibleConnectionFailure, @@ -777,7 +776,7 @@ class Connection(ConnectionBase): self.port, self.user ) - b_args = (b"-o", b"ControlPath=" + to_bytes(self.control_path % dict(directory=cpdir), errors='surrogate_or_strict')) + b_args = (b"-o", b'ControlPath="%s"' % to_bytes(self.control_path % dict(directory=cpdir), errors='surrogate_or_strict')) self._add_args(b_command, b_args, u"found only ControlPersist; added ControlPath") # Finally, we add any caller-supplied extras. diff --git a/test/integration/targets/connection_ssh/runme.sh b/test/integration/targets/connection_ssh/runme.sh index cbadf1d5d1d..4d4302637de 100755 --- a/test/integration/targets/connection_ssh/runme.sh +++ b/test/integration/targets/connection_ssh/runme.sh @@ -71,3 +71,7 @@ ansible-playbook check_ssh_defaults.yml "$@" -i test_connection.inventory # ensure we can load from ini cfg ANSIBLE_CONFIG=./test_ssh_defaults.cfg ansible-playbook verify_config.yml "$@" + +# ensure we handle cp with spaces correctly, otherwise would fail with +# `"Failed to connect to the host via ssh: command-line line 0: keyword controlpath extra arguments at end of line"` +ANSIBLE_SSH_CONTROL_PATH='/tmp/ssh cp with spaces' ansible -m ping all -e ansible_connection=ssh -i test_connection.inventory "$@"