From 0a441eb2f116e43c78204e94aa7fd8be5ece4513 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Tue, 10 Apr 2018 10:03:30 -0700 Subject: [PATCH] Bkprt py3 consul kv (#37802) * consul_kv: decodes kv values from Consul to utf-8 (#35894) * Decodes kv values from Consul to utf-8. * Switches to using module utils to perform text decoding. * Adds self to authors list to help community maintenance. (cherry picked from commit a4a2b4a38160fc3f80c8a11d12ba0fb7fab77f42) * Add a changelog fragment for consul_kv python3 fix --- changelogs/fragments/py3-consul_kv.yaml | 2 ++ lib/ansible/modules/clustering/consul_kv.py | 34 ++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/py3-consul_kv.yaml diff --git a/changelogs/fragments/py3-consul_kv.yaml b/changelogs/fragments/py3-consul_kv.yaml new file mode 100644 index 00000000000..0aa198a2cc2 --- /dev/null +++ b/changelogs/fragments/py3-consul_kv.yaml @@ -0,0 +1,2 @@ +bugfixes: +- Fix for consul_kv idempotence on Python3 https://github.com/ansible/ansible/issues/35893 diff --git a/lib/ansible/modules/clustering/consul_kv.py b/lib/ansible/modules/clustering/consul_kv.py index 967dadc969b..f284b3d6e97 100644 --- a/lib/ansible/modules/clustering/consul_kv.py +++ b/lib/ansible/modules/clustering/consul_kv.py @@ -1,6 +1,7 @@ #!/usr/bin/python # # (c) 2015, Steve Gargan +# (c) 2017, 2018 Genome Research Ltd. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function @@ -28,7 +29,8 @@ requirements: - requests version_added: "2.0" author: -- Steve Gargan (@sgargan) + - Steve Gargan (@sgargan) + - Colin Nolan (@colin-nolan) options: state: description: @@ -122,6 +124,8 @@ EXAMPLES = ''' state: acquire ''' +from ansible.module_utils._text import to_text + try: import consul from requests.exceptions import ConnectionError @@ -132,6 +136,27 @@ except ImportError: from ansible.module_utils.basic import AnsibleModule +def _has_value_changed(consul_client, key, target_value): + """ + Uses the given Consul client to determine if the value associated to the given key is different to the given target + value. + :param consul_client: Consul connected client + :param key: key in Consul + :param target_value: value to be associated to the key + :return: tuple where the first element is the value of the "X-Consul-Index" header and the second is `True` if the + value has changed (i.e. the stored value is not the target value) + """ + index, existing = consul_client.kv.get(key) + if not existing: + return index, True + try: + changed = to_text(existing['Value'], errors='surrogate_or_strict') != target_value + return index, changed + except UnicodeError: + # Existing value was not decodable but all values we set are valid utf-8 + return index, True + + def execute(module): state = module.params.get('state') @@ -157,9 +182,8 @@ def lock(module, state): msg='%s of lock for %s requested but no session supplied' % (state, key)) - index, existing = consul_api.kv.get(key) + index, changed = _has_value_changed(consul_api, key, value) - changed = not existing or (existing and existing['Value'] != value) if changed and not module.check_mode: if state == 'acquire': changed = consul_api.kv.put(key, value, @@ -184,14 +208,14 @@ def add_value(module): key = module.params.get('key') value = module.params.get('value') - index, existing = consul_api.kv.get(key) + index, changed = _has_value_changed(consul_api, key, value) - changed = not existing or (existing and existing['Value'] != value) if changed and not module.check_mode: changed = consul_api.kv.put(key, value, cas=module.params.get('cas'), flags=module.params.get('flags')) + stored = None if module.params.get('retrieve'): index, stored = consul_api.kv.get(key)