From f05979932b7a9187a6d60b051d01c94f918dd0da Mon Sep 17 00:00:00 2001 From: Nathaniel Case Date: Fri, 21 Dec 2018 11:15:18 -0500 Subject: [PATCH] Allow AnsibleVaultEncryptedUnicode to pass through exec_jsonrpc (#48306) * Allow AnsibleVaultEncryptedUnicode to pass through exec_jsonrpc * Add changelog --- .../fragments/48306-ansible-connection-json | 4 ++ lib/ansible/module_utils/connection.py | 44 ++++++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 changelogs/fragments/48306-ansible-connection-json diff --git a/changelogs/fragments/48306-ansible-connection-json b/changelogs/fragments/48306-ansible-connection-json new file mode 100644 index 00000000000..130b12bb4fe --- /dev/null +++ b/changelogs/fragments/48306-ansible-connection-json @@ -0,0 +1,4 @@ +--- +bugfixes: +- Use custom JSON encoder in conneciton.py so that ansible objects (AnsibleVaultEncryptedUnicode, for example) + can be sent to the persistent connection process diff --git a/lib/ansible/module_utils/connection.py b/lib/ansible/module_utils/connection.py index 5e5451b5cd9..91a2a9d61bc 100644 --- a/lib/ansible/module_utils/connection.py +++ b/lib/ansible/module_utils/connection.py @@ -33,9 +33,11 @@ import socket import struct import traceback import uuid +from datetime import date, datetime from functools import partial from ansible.module_utils._text import to_bytes, to_text +from ansible.module_utils.common._collections_compat import Mapping from ansible.module_utils.six import iteritems from ansible.module_utils.six.moves import cPickle @@ -138,22 +140,8 @@ class Connection(object): '\nSee the socket_path issue catergory in Network Debug and Troubleshooting Guide') try: - data = json.dumps(req) + data = json.dumps(req, cls=AnsibleJSONEncoder) except TypeError as exc: - data = req.get('params') - - if isinstance(data, dict): - data = data.get('var_options', {}) - - for key, value in iteritems(data): - try: - dummy = json.dumps(value) - except TypeError: - raise ConnectionError( - "Failed to encode some variables as JSON for communication with ansible-connection. " - "Please open an issue and mention that the culprit is most likely '%s'" % key - ) - raise ConnectionError( "Failed to encode some variables as JSON for communication with ansible-connection. " "The original exception was: %s" % to_text(exc) @@ -214,3 +202,29 @@ class Connection(object): sf.close() return to_text(response, errors='surrogate_or_strict') + + +# NOTE: This is a modified copy of the class in parsing.ajson to get around not +# being able to import that directly, nor some of the type classes +class AnsibleJSONEncoder(json.JSONEncoder): + ''' + Simple encoder class to deal with JSON encoding of Ansible internal types + ''' + + def default(self, o): + if type(o).__name__ == 'AnsibleVaultEncryptedUnicode': + # vault object + value = {'__ansible_vault': to_text(o._ciphertext, errors='surrogate_or_strict', nonstring='strict')} + elif type(o).__name__ == 'AnsibleUnsafe': + # unsafe object + value = {'__ansible_unsafe': to_text(o, errors='surrogate_or_strict', nonstring='strict')} + elif isinstance(o, Mapping): + # hostvars and other objects + value = dict(o) + elif isinstance(o, (date, datetime)): + # date object + value = o.isoformat() + else: + # use default encoder + value = super(AnsibleJSONEncoder, self).default(o) + return value