From c264061272241033d1214c36d09c96a6689179ff Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Thu, 15 Mar 2018 13:52:33 -0700 Subject: [PATCH] Bkprt conn err msg no template (#37381) * Connection error messages are unsafe: wrap them (#37329) * Check that connection error msg are not unsafe * Connection error messages are unsafe: wrap them For example, in case of error, docker connection plugin returns exception message containing Go template. These messages weren't tagged as unsafe and were consequently rendered: The conditional check 'result is failed' failed. The error was: { 'msg': u'Docker version check ([\'/usr/bin/docker\', \'version\', \'--format\', "\'{{.Server.Version}}\'"]) failed: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.35/version: dial unix /var/run/docker.sock: connect: permission denied\n', 'failed': True }: template error while templating string: unexpected '.'. String: Docker version check (['/usr/bin/docker', 'version', '--format', "'{{.Server.Version}}'"]) failed: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.35/version: dial unix /var/run/docker.sock: connect: permission denied (cherry picked from commit 4378542ac7ff98fba4fe2c00eec99fbab8e93d1e) * Add a changelog for the no-template error message fix --- .../fragments/no-template-conn-err.yaml | 4 ++ lib/ansible/executor/task_executor.py | 2 +- test/integration/targets/connection/aliases | 1 + test/integration/targets/connection/inventory | 2 + test/integration/targets/connection/play.yml | 19 ++++++++ .../targets/connection/plugin/dummy.py | 46 +++++++++++++++++++ test/integration/targets/connection/runme.sh | 5 ++ 7 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/no-template-conn-err.yaml create mode 100644 test/integration/targets/connection/aliases create mode 100644 test/integration/targets/connection/inventory create mode 100644 test/integration/targets/connection/play.yml create mode 100644 test/integration/targets/connection/plugin/dummy.py create mode 100755 test/integration/targets/connection/runme.sh diff --git a/changelogs/fragments/no-template-conn-err.yaml b/changelogs/fragments/no-template-conn-err.yaml new file mode 100644 index 00000000000..6b8b4e3198e --- /dev/null +++ b/changelogs/fragments/no-template-conn-err.yaml @@ -0,0 +1,4 @@ +bugfixes: + - Connection error messages may contain characters that jinja2 would + interpret as a template. Wrap the error string so this doesn't happen + (https://github.com/ansible/ansible/pull/37329) diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 8754f2cbc32..e3a1201978f 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -170,7 +170,7 @@ class TaskExecutor: display.debug("done dumping result, returning") return res except AnsibleError as e: - return dict(failed=True, msg=to_text(e, nonstring='simplerepr')) + return dict(failed=True, msg=wrap_var(to_text(e, nonstring='simplerepr'))) except Exception as e: return dict(failed=True, msg='Unexpected failure during module execution.', exception=to_text(traceback.format_exc()), stdout='') finally: diff --git a/test/integration/targets/connection/aliases b/test/integration/targets/connection/aliases new file mode 100644 index 00000000000..7af8b7f05bb --- /dev/null +++ b/test/integration/targets/connection/aliases @@ -0,0 +1 @@ +posix/ci/group2 diff --git a/test/integration/targets/connection/inventory b/test/integration/targets/connection/inventory new file mode 100644 index 00000000000..324f0d3af39 --- /dev/null +++ b/test/integration/targets/connection/inventory @@ -0,0 +1,2 @@ +[local] +testhost diff --git a/test/integration/targets/connection/play.yml b/test/integration/targets/connection/play.yml new file mode 100644 index 00000000000..b62239379a3 --- /dev/null +++ b/test/integration/targets/connection/play.yml @@ -0,0 +1,19 @@ +- hosts: testhost + gather_facts: false + tasks: + - name: "use a connection plugin raising an exception, exception message contains Jinja template." + connection: dummy + command: /bin/true # command won't be executed + register: result + ignore_errors: True + + - name: "check that Jinja template embedded in exception message isn't rendered" + debug: + msg: 'ok' + when: result is failed + register: debug_task + + - assert: + that: + - result is failed + - debug_task is success diff --git a/test/integration/targets/connection/plugin/dummy.py b/test/integration/targets/connection/plugin/dummy.py new file mode 100644 index 00000000000..de84bb43419 --- /dev/null +++ b/test/integration/targets/connection/plugin/dummy.py @@ -0,0 +1,46 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = """ + author: + - John Doe + connection: dummy + short_description: defective connection plugin + description: + - defective connection plugin + version_added: "2.0" + options: {} +""" +import ansible.constants as C +from ansible.errors import AnsibleError +from ansible.plugins.connection import ConnectionBase + + +class Connection(ConnectionBase): + + transport = 'dummy' + has_pipelining = True + become_methods = frozenset(C.BECOME_METHODS) + + def __init__(self, play_context, new_stdin, *args, **kwargs): + super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs) + + raise AnsibleError('an error with {{ some Jinja }}') + + def transport(self): + pass + + def _connect(self): + pass + + def exec_command(self, cmd, in_data=None, sudoable=True): + pass + + def put_file(self, in_path, out_path): + pass + + def fetch_file(self, in_path, out_path): + pass + + def close(self): + pass diff --git a/test/integration/targets/connection/runme.sh b/test/integration/targets/connection/runme.sh new file mode 100755 index 00000000000..2ab43e00663 --- /dev/null +++ b/test/integration/targets/connection/runme.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -o nounset -o errexit -o xtrace + +ANSIBLE_CONNECTION_PLUGINS="$(pwd)/plugin" ansible-playbook -i inventory "$(pwd)/play.yml" -v "$@"