Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with non-ASCII strings from dynamic inventory #10007

Closed
etanol opened this issue Jan 15, 2015 · 10 comments
Closed

Problems with non-ASCII strings from dynamic inventory #10007

etanol opened this issue Jan 15, 2015 · 10 comments
Labels
bug This issue/PR relates to a bug.

Comments

@etanol
Copy link

etanol commented Jan 15, 2015

Issue Type:

Bug Report

Ansible Version:

1.8, 1.9, devel

Environment:

Ubuntu 14.04.1 LTS x86_64

Summary:

When using a dynamic inventory, if a variable definition contains non-ASCII characters (but correct UTF-8 sequences or even correct Unicode escapes \u00e1 it will later fail at whatever template expansion attepted: wheter it's from the playbook itself or through the template module.

The problem seems to be related to the fact that Jinja2 can only handle either Python unicode objects or plain ASCII strings, but not strings encoded in UTF-8 as it is receiving right now.

Steps To Reproduce:

Configure Ansible to use the following inventory script:

#!/usr/bin/env python
# coding: utf-8
import sys
import json

json.dump(
    {
        'all': {
            'vars': { 'name': u"Cáñamo" },
            'hosts': ['foo']
        },
        '_meta': { 'hostvars': {} },
    }, sys.stdout)

And then try to execute the following example playbook:

---
- name: Testing dynamic inventory Unicode
  hosts: all
  connection: local

  tasks:
    - name: Unicode test
      debug: msg="Hey {{ name }}"
...
Expected Results:
PLAY [Testing dynamic inventory Unicode] ************************************** 

TASK: [Unicode test] ********************************************************** 
ok: [foo] => {
    "msg": "Hey Cáñamo"
}

PLAY RECAP ******************************************************************** 
foo                        : ok=1    changed=0    unreachable=0    failed=0   
Actual Results:
PLAY [Testing dynamic inventory Unicode] ************************************** 

TASK: [Unicode test] ********************************************************** 
fatal: [foo] => Traceback (most recent call last):
  File "/home/isaac/work/sistemas/.virtualenv/local/lib/python2.7/site-packages/ansible/runner/__init__.py", line 590, in _executor
    exec_rc = self._executor_internal(host, new_stdin)
  File "/home/isaac/work/sistemas/.virtualenv/local/lib/python2.7/site-packages/ansible/runner/__init__.py", line 792, in _executor_internal
    return self._executor_internal_inner(host, self.module_name, self.module_args, inject, port, complex_args=complex_args)
  File "/home/isaac/work/sistemas/.virtualenv/local/lib/python2.7/site-packages/ansible/runner/__init__.py", line 993, in _executor_internal_inner
    module_args = template.template(self.basedir, module_args, inject, fail_on_undefined=self.error_on_undefined_vars)
  File "/home/isaac/work/sistemas/.virtualenv/local/lib/python2.7/site-packages/ansible/utils/template.py", line 118, in template
    varname = template_from_string(basedir, varname, templatevars, fail_on_undefined)
  File "/home/isaac/work/sistemas/.virtualenv/local/lib/python2.7/site-packages/ansible/utils/template.py", line 364, in template_from_string
    res = jinja2.utils.concat(rf)
  File "<template>", line 9, in root
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)


FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/home/isaac/playbook.yaml.retry

foo                        : ok=0    changed=0    unreachable=1    failed=0   
Notes:

As a temporary fix, we applied the following patch to our installation:

diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py
index cee6510..7a3805b 100644
--- a/lib/ansible/module_utils/basic.py
+++ b/lib/ansible/module_utils/basic.py
@@ -240,8 +240,8 @@ def json_dict_unicode_to_bytes(d):
         and dict container types (the containers that the json module returns)
     '''

-    if isinstance(d, unicode):
-        return d.encode('utf-8')
+    if isinstance(d, str):
+        return d.decode('utf-8')
     elif isinstance(d, dict):
         return dict(map(json_dict_unicode_to_bytes, d.iteritems()))
     elif isinstance(d, list):
diff --git a/v2/ansible/module_utils/basic.py b/v2/ansible/module_utils/basic.py
index acaa370..f5d126c 100644
--- a/v2/ansible/module_utils/basic.py
+++ b/v2/ansible/module_utils/basic.py
@@ -240,8 +240,8 @@ def json_dict_unicode_to_bytes(d):
         and dict container types (the containers that the json module returns)
     '''

-    if isinstance(d, unicode):
-        return d.encode('utf-8')
+    if isinstance(d, str):
+        return d.decode('utf-8')
     elif isinstance(d, dict):
         return dict(map(json_dict_unicode_to_bytes, d.iteritems()))
     elif isinstance(d, list):

However, this simple change is semantically significant, even though it seems to pass the test suite (see below), we are not sure it is the proper place to fix it.

Test run:
PYTHONPATH=./lib nosetests -d -w test/units -v # Could do: --with-coverage --cover-package=ansible
test_configfile_and_env_both_set (TestConstants.TestConstants) ... ok
test_configfile_not_set_env_not_set (TestConstants.TestConstants) ... ok
test_configfile_not_set_env_set (TestConstants.TestConstants) ... ok
test_configfile_set_env_not_set (TestConstants.TestConstants) ... ok
test_bool_no (TestFilters.TestFilters) ... ok
test_bool_none (TestFilters.TestFilters) ... ok
test_bool_true (TestFilters.TestFilters) ... ok
test_bool_yes (TestFilters.TestFilters) ... ok
test_fileglob (TestFilters.TestFilters) ... ok
test_match_case_insensitive (TestFilters.TestFilters) ... ok
test_match_case_sensitive (TestFilters.TestFilters) ... ok
test_match_no_match (TestFilters.TestFilters) ... ok
test_max (TestFilters.TestFilters) ... ok
test_min (TestFilters.TestFilters) ... ok
test_quotes (TestFilters.TestFilters) ... ok
test_regex (TestFilters.TestFilters) ... ok
test_regex_replace_case_insensitive (TestFilters.TestFilters) ... ok
test_regex_replace_case_sensitive (TestFilters.TestFilters) ... ok
test_regex_replace_no_match (TestFilters.TestFilters) ... ok
test_search_case_insensitive (TestFilters.TestFilters) ... ok
test_search_case_sensitive (TestFilters.TestFilters) ... ok
test_version_compare (TestFilters.TestFilters) ... ok
test_allows_equals_sign_in_var (TestInventory.TestInventory) ... ok
test_alpha_end_before_beg (TestInventory.TestInventory) ... ok
test_combined_range (TestInventory.TestInventory) ... ok
test_complex_enumeration (TestInventory.TestInventory) ... ok
test_complex_exclude (TestInventory.TestInventory) ... ok
test_complex_group_names (TestInventory.TestInventory) ... ok
test_complex_intersect (TestInventory.TestInventory) ... ok
test_complex_vars (TestInventory.TestInventory) ... ok
test_dir_inventory (TestInventory.TestInventory) ... ok
test_dir_inventory_group_hosts (TestInventory.TestInventory) ... ok
test_dir_inventory_groups_for_host (TestInventory.TestInventory) ... ok
test_dir_inventory_groups_list (TestInventory.TestInventory) ... ok
test_dir_inventory_multiple_groups (TestInventory.TestInventory) ... ok
test_dir_inventory_skip_extension (TestInventory.TestInventory) ... ok
test_empty (TestInventory.TestInventory) ... ok
test_get_hosts (TestInventory.TestInventory) ... ok
test_hosts_list (TestInventory.TestInventory) ... ok
test_incorrect_format (TestInventory.TestInventory) ... ok
test_invalid_range (TestInventory.TestInventory) ... ok
test_large_range (TestInventory.TestInventory) ... ok
test_leading_range (TestInventory.TestInventory) ... ok
test_missing_end (TestInventory.TestInventory) ... ok
test_no_src (TestInventory.TestInventory) ... ok
test_regex_exclude (TestInventory.TestInventory) ... ok
test_regex_grouping (TestInventory.TestInventory) ... ok
test_script (TestInventory.TestInventory) ... ok
test_script_all (TestInventory.TestInventory) ... ok
test_script_combined (TestInventory.TestInventory) ... ok
test_script_multiple_groups (TestInventory.TestInventory) ... ok
test_script_norse (TestInventory.TestInventory) ... ok
test_script_restrict (TestInventory.TestInventory) ... ok
test_script_vars (TestInventory.TestInventory) ... ok
test_simple (TestInventory.TestInventory) ... ok
test_simple_all (TestInventory.TestInventory) ... ok
test_simple_combined (TestInventory.TestInventory) ... ok
test_simple_norse (TestInventory.TestInventory) ... ok
test_simple_port (TestInventory.TestInventory) ... ok
test_simple_restrict (TestInventory.TestInventory) ... ok
test_simple_string_fqdn (TestInventory.TestInventory) ... ok
test_simple_string_fqdn_port (TestInventory.TestInventory) ... ok
test_simple_string_fqdn_vars (TestInventory.TestInventory) ... ok
test_simple_string_ipv4 (TestInventory.TestInventory) ... ok
test_simple_string_ipv4_port (TestInventory.TestInventory) ... ok
test_simple_string_ipv4_vars (TestInventory.TestInventory) ... ok
test_simple_string_ipv6 (TestInventory.TestInventory) ... ok
test_simple_string_ipv6_port (TestInventory.TestInventory) ... ok
test_simple_string_ipv6_vars (TestInventory.TestInventory) ... ok
test_simple_ungrouped (TestInventory.TestInventory) ... ok
test_simple_vars (TestInventory.TestInventory) ... ok
test_subet_range_empty_group (TestInventory.TestInventory) ... ok
test_subset (TestInventory.TestInventory) ... ok
test_subset_filename (TestInventory.TestInventory) ... ok
test_subset_range (TestInventory.TestInventory) ... ok
testinvalid_entry (TestInventory.TestInventory) ... ok
test_run_command_args (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_args_with_env_variables (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_unsafe_with_double_redirect_out (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_unsafe_with_env_variables (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_unsafe_with_pipe (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_unsafe_with_redirect_in (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_unsafe_with_redirect_out (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_with_binary_data (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_with_cwd (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_with_data (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_run_command_string_with_env_variables (TestModuleUtilsBasic.TestModuleUtilsBasic) ... ok
test_log_sanitize_correctness (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
test_log_sanitize_speed_many_ssh (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
test_log_sanitize_speed_many_url (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
test_log_sanitize_speed_one_ssh (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
test_log_sanitize_speed_one_url (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
test_log_sanitize_speed_zero_secrets (TestModuleUtilsBasic.TestModuleUtilsBasicHelpers) ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_how_many_dots ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"table "invalid" double quote"', 'table', 'User escaped identifiers must escape extra quotes') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"test"."too"."many"."dots"', 'schema', 'PostgreSQL does not support schema with more than 2 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('test.too."many.dots"', 'database', 'PostgreSQL does not support database with more than 1 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"test"."too"."many"."dots"', 'database', 'PostgreSQL does not support database with more than 1 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('test.too.many.dots', 'table', 'PostgreSQL does not support table with more than 3 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"schema "invalid"""."table "invalid"', 'table', 'User escaped identifiers must escape extra quotes') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"schema".', 'table', 'Identifier name unspecified or unquoted trailing dot') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"test"."too"."many"."dots"."for"."column"', 'column', 'PostgreSQL does not support column with more than 4 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"schema."table"', 'table', 'User escaped identifiers must escape extra quotes') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"test.too".many.dots', 'database', 'PostgreSQL does not support database with more than 1 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_invalid_quotes('"test"."too"."many"."dots"', 'table', 'PostgreSQL does not support table with more than 3 dots') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('."table"', '".""table"""') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema.".".table"', '"schema.".".table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('public.table', '"public"."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema.test"."table.test"', '"schema.test"."table.test"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema."."table"', '"schema."."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema.".table', '"schema."."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('public."table ""test"""', '"public"."table ""test"""') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema.".table"', '"schema".".table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"no end quote', '"""no end quote"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema test".table test', '"schema test"."table test"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('public.table "test"', '"public"."table ""test"""') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema test"."table test"', '"schema test"."table test"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema.table', '"""schema"."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema".".table"', '"schema".".table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('public."table"', '"public"."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema test.table test', '"schema test"."table test"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('table "test"', '"table ""test"""') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema "test".table', '"schema ""test"""."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"public.table"', '"public.table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"""wat"""."""test"""', '"""wat"""."""test"""') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"schema ""test""".table', '"schema ""test"""."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"public".table', '"public"."table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema."table', '"schema"."""table"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema test."table test"', '"schema test"."table test"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('table.', '"table."') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('schema."table.something', '"schema"."""table"."something"') ... ok
TestModuleUtilsDatabase.TestQuotePgIdentifier.test_valid_quotes('"public"."table"', '"public"."table"') ... ok
test_ast_parse (TestModules.TestModules) ... ok
test_multiple_vars_files (TestPlayVarsFiles.TestMe) ... ok
test_play_constructor (TestPlayVarsFiles.TestMe) ... ok
test_vars_file (TestPlayVarsFiles.TestMe) ... ok
test_vars_file_nonlist_error (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_assert_all_found (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_first_found (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_for_host (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_multiple_found (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_two_vars_different_scope (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_two_vars_different_scope_first_found (TestPlayVarsFiles.TestMe) ... ok
test_vars_files_two_vars_in_name (TestPlayVarsFiles.TestMe) ... ok
verify the synchronize action plugin sets ... ok
verify the synchronize action plugin sets ... ok
verify the synchronize action plugin unsets and then sets sudo ... ok
Verify the action plugin accommodates the common ... ok
Failure: ImportError (No module named passlib.hash) ... ERROR
Failure: ImportError (No module named passlib.hash) ... ERROR
test_add_header (TestVault.TestVaultLib) ... ok
test_cipher_not_set (TestVault.TestVaultLib) ... SKIP
test_decrypt_decrypted (TestVault.TestVaultLib) ... SKIP
test_encrypt_decrypt_aes (TestVault.TestVaultLib) ... SKIP
test_encrypt_decrypt_aes256 (TestVault.TestVaultLib) ... SKIP
test_encrypt_encrypted (TestVault.TestVaultLib) ... SKIP
test_is_encrypted (TestVault.TestVaultLib) ... ok
test_methods_exist (TestVault.TestVaultLib) ... ok
test_split_header (TestVault.TestVaultLib) ... ok
test_decrypt_1_0 (TestVaultEditor.TestVaultEditor) ... SKIP
test_decrypt_1_1 (TestVaultEditor.TestVaultEditor) ... SKIP
test_decrypt_1_1_newline (TestVaultEditor.TestVaultEditor) ... SKIP
test_methods_exist (TestVaultEditor.TestVaultEditor) ... ok
test_rekey_migration (TestVaultEditor.TestVaultEditor) ... SKIP
Failure: ImportError (No module named core.packaging.os.apt) ... ERROR
Failure: ImportError (No module named core.cloud.docker.docker) ... ERROR

======================================================================
ERROR: Failure: ImportError (No module named passlib.hash)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/loader.py", line 414, in loadTestsFromName
    addr.filename, addr.module)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/isaac/sources/ansible/test/units/TestUtils.py", line 10, in <module>
    import passlib.hash
ImportError: No module named passlib.hash

======================================================================
ERROR: Failure: ImportError (No module named passlib.hash)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/loader.py", line 414, in loadTestsFromName
    addr.filename, addr.module)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/isaac/sources/ansible/test/units/TestUtilsStringFunctions.py", line 8, in <module>
    import passlib.hash
ImportError: No module named passlib.hash

======================================================================
ERROR: Failure: ImportError (No module named core.packaging.os.apt)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/loader.py", line 414, in loadTestsFromName
    addr.filename, addr.module)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/isaac/sources/ansible/test/units/module_tests/TestApt.py", line 6, in <module>
    from ansible.modules.core.packaging.os.apt import (
ImportError: No module named core.packaging.os.apt

======================================================================
ERROR: Failure: ImportError (No module named core.cloud.docker.docker)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/loader.py", line 414, in loadTestsFromName
    addr.filename, addr.module)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/home/isaac/virtualenvs/adevel/local/lib/python2.7/site-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/home/isaac/sources/ansible/test/units/module_tests/TestDocker.py", line 5, in <module>
    from ansible.modules.core.cloud.docker.docker import get_split_image_tag
ImportError: No module named core.cloud.docker.docker

----------------------------------------------------------------------
Ran 167 tests in 4.178s

FAILED (SKIP=9, errors=4)
make: *** [tests] Error 1
@abadger
Copy link
Contributor

abadger commented Jan 19, 2015

I'll have to look through the git log around json_dict_to_bytes() to refresh my memory on this... I think if there is a testcase it would be an integrarion test rather than a unittest. The change is definitely going to cause problems... at the least, a regression of the problem that json_dict_to_bytes() was written for. But I haven't found a jinja2 method of processing non-ascii byte strings either. So I suspect some portion of the code is calling jinja templating and json_dict_to_bytes() in the opposite order of what they need to be. (the jinja templating needs to be finished before we call json_dict_to_bytes()). We'll have to look through the git log and code to see if that's easy to fix or extremely hard...

@etanol
Copy link
Author

etanol commented Jan 20, 2015

Thanks for taking a look. I tried to follow your commits (a10d10f and cef2a87) but I can't find any cross reference that leads me to an issue or the original motivation.

Tomorrow we'll try another approach: converting UTF-8 back to unicode when adding a value to a host or a group.

@abadger
Copy link
Contributor

abadger commented Jan 21, 2015

Just an update here - Looks like the problem I wrote this for can be fixed at a specific point instead of all throughout the code. This will also make the code closer to the v2 tree (where we decided to use unicode type internally). To do that I'll add the transformation to a byte str in the callbacks.py function on_unreachable() and then remove the calls to json_dict_to_bytes() from the dynamic inventory handling.

@etanol
Copy link
Author

etanol commented Jan 21, 2015

Thanks for the feedback. We're really looking forward to have this fixed. Or, either, v2 being published, as we always run with the latest Ansible release.

@mscherer
Copy link
Contributor

So I just had someone who reported me the exact same bug during a workshop I gave, and I found a minimal test case:

ansible-playbook toto.yml -e "foo=ééé"

With:

---
- hosts: 127.0.0.1
  connection: local
  tasks:
  - debug: msg="plop {{ foo }}"

(use case was using vars_prompt and deploy people name in the git configuration, and the person had Unicode in his name). So at least, having instruction on how to use the v2 tree would help (in fact, I wonder why this is not a git branch, as this would ease test from community for small issue like this)

Should it be treated as a different bug ?

@abadger
Copy link
Contributor

abadger commented Jan 26, 2015

I think I have a partial fix -- it removes one of the two places where json_dict_to_bytes() is called (when getting the input from the dynamic inventory script) and adds an explicit encoding step to the callbacks.on_unreachable() callback. I'm just trying to determine:

  • That there isn't any regressions when I do this.
  • Whether or not we need to do the opposite of the current code and transform any output of dynamic inventory to a unicode type if it's a byte type to begin with.

@abadger
Copy link
Contributor

abadger commented Jan 26, 2015

@mscherer I believe that may be a different problem. I think this fix is just changing the interface between dynamic inventory scripts and the main part of ansible.

to test this on v2, you should be able to source v2/hacking/env-setup just like you could source the toplevel hacking/env-setup. That will setup all of the paths to run the v2 version of ansible and ansible-playbook. It's not complete by any stretch but many of the integration tests are now passing.

@abadger
Copy link
Contributor

abadger commented Jan 26, 2015

Okay, answer to my questions:

  • I've also patched callbacks.on_unreachable() to prevent regression (in v2, we're going to try to solve this at a different level.
  • We do need to do the opposite (transform any output of dynamic inventory into a unicode type) in order to prevent the same sort of traceback from occurring with byte strings specified in dynamic inventory (at least, I think that's where the problem is originating although I don't fully understand yet why v1 would be doing that)

@abadger
Copy link
Contributor

abadger commented Jan 27, 2015

Okay, I think that patch should fix the problems with dynamic inventory. I do believe that the same sort of thing could happen with extra-vars as @mscherer is experiencing but we should probably track it separately -- it will be a different portion of the code that handles parsing of vars given via the command line that we'll need to modify.

@abadger
Copy link
Contributor

abadger commented Jan 27, 2015

And of course, if the problem isn't fixed, feel free to open a new bug report or otherwise let me know! Thanks.

Closing This Ticket

Hi!

We believe recent commits (likely detailed above) should resolve this question or problem for you.

This will also be included in the next major release.

If you continue seeing any problems related to this issue, or if you have any further questions, please let us know by stopping by one of the two mailing lists, as appropriate:

Because this project is very active, we're unlikely to see comments made on closed tickets, but the mailing list is a great way to ask questions, or post if you don't think this particular
issue is resolved.

Thank you!

abadger added a commit that referenced this issue Feb 17, 2015
…m potential byte str into unicode type. This fix is for dynamic inventory.

Fixes #10007

Conflicts:
	v2/ansible/inventory/script.py
	v2/ansible/module_utils/basic.py
@ansibot ansibot added bug This issue/PR relates to a bug. and removed bug_report labels Mar 6, 2018
@ansible ansible locked and limited conversation to collaborators Apr 25, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug This issue/PR relates to a bug.
Projects
None yet
Development

No branches or pull requests

5 participants