From 5ac1b04929aae38e4a4cfd199051f76c7aa187a0 Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Thu, 10 Jun 2021 21:07:55 +0200 Subject: [PATCH] Add support for unicode in ansible-inventory CLI (#74912) * Add support for unicode in ansible-inventory CLI Fixes #57378 * Add tests * First test fix * --output tests * fix --- .../fragments/57378-inventory-cli-unicode.yml | 2 + lib/ansible/cli/inventory.py | 12 +-- .../ansible-inventory/files/unicode.yml | 3 + .../targets/ansible-inventory/tasks/main.yml | 74 +++++++++++++++++++ 4 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/57378-inventory-cli-unicode.yml create mode 100644 test/integration/targets/ansible-inventory/files/unicode.yml diff --git a/changelogs/fragments/57378-inventory-cli-unicode.yml b/changelogs/fragments/57378-inventory-cli-unicode.yml new file mode 100644 index 00000000000..50d1d503459 --- /dev/null +++ b/changelogs/fragments/57378-inventory-cli-unicode.yml @@ -0,0 +1,2 @@ +bugfixes: + - Add unicode support to ``ansible-inventory`` CLI (https://github.com/ansible/ansible/issues/57378) diff --git a/lib/ansible/cli/inventory.py b/lib/ansible/cli/inventory.py index 135fe1fa974..3fbea734e69 100644 --- a/lib/ansible/cli/inventory.py +++ b/lib/ansible/cli/inventory.py @@ -15,7 +15,7 @@ from ansible import context from ansible.cli import CLI from ansible.cli.arguments import option_helpers as opt_help from ansible.errors import AnsibleError, AnsibleOptionsError -from ansible.module_utils._text import to_bytes, to_native +from ansible.module_utils._text import to_bytes, to_native, to_text from ansible.utils.vars import combine_vars from ansible.utils.display import Display from ansible.vars.plugins import get_vars_from_inventory_sources, get_vars_from_path @@ -158,8 +158,8 @@ class InventoryCLI(CLI): display.display(results) else: try: - with open(to_bytes(outfile), 'wt') as f: - f.write(results) + with open(to_bytes(outfile), 'wb') as f: + f.write(to_bytes(results)) except (OSError, IOError) as e: raise AnsibleError('Unable to write to destination file (%s): %s' % (to_native(outfile), to_native(e))) sys.exit(0) @@ -172,7 +172,7 @@ class InventoryCLI(CLI): if context.CLIARGS['yaml']: import yaml from ansible.parsing.yaml.dumper import AnsibleDumper - results = yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False) + results = to_text(yaml.dump(stuff, Dumper=AnsibleDumper, default_flow_style=False, allow_unicode=True)) elif context.CLIARGS['toml']: from ansible.plugins.inventory.toml import toml_dumps, HAS_TOML if not HAS_TOML: @@ -192,9 +192,9 @@ class InventoryCLI(CLI): import json from ansible.parsing.ajson import AnsibleJSONEncoder try: - results = json.dumps(stuff, cls=AnsibleJSONEncoder, sort_keys=True, indent=4, preprocess_unsafe=True) + results = json.dumps(stuff, cls=AnsibleJSONEncoder, sort_keys=True, indent=4, preprocess_unsafe=True, ensure_ascii=False) except TypeError as e: - results = json.dumps(stuff, cls=AnsibleJSONEncoder, sort_keys=False, indent=4, preprocess_unsafe=True) + results = json.dumps(stuff, cls=AnsibleJSONEncoder, sort_keys=False, indent=4, preprocess_unsafe=True, ensure_ascii=False) display.warning("Could not sort JSON output due to issues while sorting keys: %s" % to_native(e)) return results diff --git a/test/integration/targets/ansible-inventory/files/unicode.yml b/test/integration/targets/ansible-inventory/files/unicode.yml new file mode 100644 index 00000000000..ff95db0d4cf --- /dev/null +++ b/test/integration/targets/ansible-inventory/files/unicode.yml @@ -0,0 +1,3 @@ +all: + hosts: + příbor: diff --git a/test/integration/targets/ansible-inventory/tasks/main.yml b/test/integration/targets/ansible-inventory/tasks/main.yml index 7ec924f21fe..685cad885df 100644 --- a/test/integration/targets/ansible-inventory/tasks/main.yml +++ b/test/integration/targets/ansible-inventory/tasks/main.yml @@ -105,3 +105,77 @@ that: - result is failed - '"ERROR! The source inventory contains a non-string key" in result.stderr' + +- name: "test json output with unicode characters" + command: ansible-inventory --list -i {{ role_path }}/files/unicode.yml + register: result + +- assert: + that: + - result is succeeded + - result.stdout is contains('příbor') + +- block: + - name: "test json output file with unicode characters" + command: ansible-inventory --list --output unicode_inventory.json -i {{ role_path }}/files/unicode.yml + + - set_fact: + json_inventory_file: "{{ lookup('file', 'unicode_inventory.json') | string }}" + + - assert: + that: + - json_inventory_file is contains('příbor') + always: + - file: + name: unicode_inventory.json + state: absent + +- name: "test yaml output with unicode characters" + command: ansible-inventory --list --yaml -i {{ role_path }}/files/unicode.yml + register: result + +- assert: + that: + - result is succeeded + - result.stdout is contains('příbor') + +- block: + - name: "test yaml output file with unicode characters" + command: ansible-inventory --list --yaml --output unicode_inventory.yaml -i {{ role_path }}/files/unicode.yml + + - set_fact: + yaml_inventory_file: "{{ lookup('file', 'unicode_inventory.yaml') | string }}" + + - assert: + that: + - yaml_inventory_file is contains('příbor') + always: + - file: + name: unicode_inventory.yaml + state: absent + +- block: + - name: "test toml output with unicode characters" + command: ansible-inventory --list --toml -i {{ role_path }}/files/unicode.yml + register: result + + - assert: + that: + - result is succeeded + - result.stdout is contains('příbor') + + - block: + - name: "test toml output file with unicode characters" + command: ansible-inventory --list --toml --output unicode_inventory.toml -i {{ role_path }}/files/unicode.yml + + - set_fact: + toml_inventory_file: "{{ lookup('file', 'unicode_inventory.toml') | string }}" + + - assert: + that: + - toml_inventory_file is contains('příbor') + always: + - file: + name: unicode_inventory.toml + state: absent + when: ansible_python.version.major|int == 3