From ffe8f45ddd7bfc83402bd07ed737c536c117a5fb Mon Sep 17 00:00:00 2001 From: Nathaniel Case Date: Mon, 14 Oct 2019 11:34:37 -0400 Subject: [PATCH] Pickle non-str objects to survive connection return (#63110) * Fail more helpfully when data is not str * Pickle arbitrary objects to return from connection --- lib/ansible/module_utils/connection.py | 4 +++- lib/ansible/utils/jsonrpc.py | 13 +++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/ansible/module_utils/connection.py b/lib/ansible/module_utils/connection.py index d1ea86f843d..0ef9e631be9 100644 --- a/lib/ansible/module_utils/connection.py +++ b/lib/ansible/module_utils/connection.py @@ -155,7 +155,7 @@ class Connection(object): try: response = json.loads(out) except ValueError: - params = list(args) + ['{0}={1}'.format(k, v) for k, v in iteritems(kwargs)] + params = [repr(arg) for arg in args] + ['{0}={1!r}'.format(k, v) for k, v in iteritems(kwargs)] params = ', '.join(params) raise ConnectionError( "Unable to decode JSON from response to {0}({1}). Received '{2}'.".format(name, params, out) @@ -163,6 +163,8 @@ class Connection(object): if response['id'] != reqid: raise ConnectionError('invalid json-rpc id received') + if "result_type" in response: + response["result"] = cPickle.loads(to_bytes(response["result"])) return response diff --git a/lib/ansible/utils/jsonrpc.py b/lib/ansible/utils/jsonrpc.py index 530e28c1eeb..e48c979d4c5 100644 --- a/lib/ansible/utils/jsonrpc.py +++ b/lib/ansible/utils/jsonrpc.py @@ -9,7 +9,8 @@ import traceback from ansible.module_utils._text import to_text from ansible.module_utils.connection import ConnectionError -from ansible.module_utils.six import binary_type +from ansible.module_utils.six import binary_type, text_type +from ansible.module_utils.six.moves import cPickle from ansible.utils.display import Display display = Display() @@ -60,7 +61,12 @@ class JsonRpcServer(object): else: response = self.response(result) - response = json.dumps(response) + try: + response = json.dumps(response) + except Exception as exc: + display.vvv(traceback.format_exc()) + error = self.internal_error(data=to_text(exc, errors='surrogate_then_replace')) + response = json.dumps(error) delattr(self, '_identifier') @@ -76,6 +82,9 @@ class JsonRpcServer(object): response = self.header() if isinstance(result, binary_type): result = to_text(result) + if not isinstance(result, text_type): + response["result_type"] = "pickle" + result = to_text(cPickle.dumps(result, protocol=0)) response['result'] = result return response