Repository: ansible/ansible

Issue:
ERROR! 'ascii' codec can't decode byte 0xc3 in position when using callback plugin with vault
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
Callback plugin

##### ANSIBLE VERSION
```
ansible 2.4.2.0
  config file = /home/contint/Check Num de Conexiones con SCP_SMS España - Pto 5010/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.13 (default, Apr 20 2017, 12:13:37) [GCC 6.3.0]
```

##### CONFIGURATION

[defaults]
stdout_callback = debug


##### OS / ENVIRONMENT

N/A


##### SUMMARY
<!--- Explain the problem briefly -->
When I use the callback plugin in conjunction with special characters and vault I get a 
ERROR! 'ascii' codec can't decode byte 0xc3 in position 54: ordinal not in range(128)

##### STEPS TO REPRODUCE

```
mkdir "prueba con una Ñ"
vi "prueba con una Ñ"/test.yml
```
test.yml:
<!--- Paste example playbooks or commands between quotes below -->
```yaml
- hosts: localhost
  gather_facts: False
  tasks:
    - debug:
      msg: "works"
```
add your inventory
create a vault file
```ansible-vault create group_vars/all.yml```

execute the test

```ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook -i inventory -u user -k test.yml   -v --ask-vault-pass
<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
TASK [debug] *************************************************************************************************************************************************************************************
ok: [ESJC-DSMM-AS02S] => {}

MSG:

Works
```
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
PLAY [ESJC-DSMM-AS02S] ***************************************************************************************************************************************************************************
ERROR! 'ascii' codec can't decode byte 0xc3 in position 54: ordinal not in range(128)
```
delete the vault file and try again, works


Discussion:
Files identified in the description:
None

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Files identified in the description:
* [lib/ansible/plugins/callback](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/callback)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
More complete traceback:

```
Traceback (most recent call last):
  File "/Users/matt/projects/ansibledev/ansible/bin/ansible-playbook", line 109, in <module>
    exit_code = cli.run()
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/cli/playbook.py", line 130, in run
    results = pbex.run()
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/executor/playbook_executor.py", line 154, in run
    result = self._tqm.run(play=play)
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/executor/task_queue_manager.py", line 290, in run
    play_return = strategy.run(iterator, play_context)
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/plugins/strategy/linear.py", line 248, in run
    task_vars = self._variable_manager.get_vars(play=iterator._play, host=host, task=task)
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/vars/manager.py", line 313, in get_vars
    all_vars = combine_vars(all_vars, locals()[entry]())
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/vars/manager.py", line 283, in all_plugins_play
    return _plugins_play([all_group])
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/vars/manager.py", line 272, in _plugins_play
    data = combine_vars(data, _get_plugin_vars(plugin, path, entities))
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/vars/manager.py", line 238, in _get_plugin_vars
    data = plugin.get_vars(self._loader, path, entities)
  File "/Users/matt/projects/ansibledev/ansible/lib/ansible/plugins/vars/host_group_vars.py", line 103, in get_vars
    raise AnsibleParserError(to_native(e))
ansible.errors.AnsibleParserError: 'ascii' codec can't decode byte 0xc3 in position 63: ordinal not in range(128)
```

Resolving patch:
diff --git a/lib/ansible/parsing/vault/__init__.py b/lib/ansible/parsing/vault/__init__.py
--- a/lib/ansible/parsing/vault/__init__.py
+++ b/lib/ansible/parsing/vault/__init__.py
@@ -77,7 +77,7 @@
 from ansible.module_utils.six import PY3, binary_type
 # Note: on py2, this zip is izip not the list based zip() builtin
 from ansible.module_utils.six.moves import zip
-from ansible.module_utils._text import to_bytes, to_text
+from ansible.module_utils._text import to_bytes, to_text, to_native
 
 try:
     from __main__ import display
@@ -663,7 +663,7 @@ def decrypt_and_get_vault_id(self, vaulttext, filename=None):
         if not is_encrypted(b_vaulttext):
             msg = "input is not vault encrypted data"
             if filename:
-                msg += "%s is not a vault encrypted file" % filename
+                msg += "%s is not a vault encrypted file" % to_native(filename)
             raise AnsibleError(msg)
 
         b_vaulttext, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext,
@@ -699,7 +699,7 @@ def decrypt_and_get_vault_id(self, vaulttext, filename=None):
             vault_id_matchers.append(vault_id)
             _matches = match_secrets(self.secrets, vault_id_matchers)
             if _matches:
-                display.vvvvv('We have a secret associated with vault id (%s), will try to use to decrypt %s' % (vault_id, filename))
+                display.vvvvv('We have a secret associated with vault id (%s), will try to use to decrypt %s' % (vault_id, to_text(filename)))
             else:
                 display.vvvvv('Found a vault_id (%s) in the vault text, but we do not have a associated secret (--vault-id)' % (vault_id))
 
@@ -713,7 +713,7 @@ def decrypt_and_get_vault_id(self, vaulttext, filename=None):
 
         # for vault_secret_id in vault_secret_ids:
         for vault_secret_id, vault_secret in matched_secrets:
-            display.vvvvv('Trying to use vault secret=(%s) id=%s to decrypt %s' % (vault_secret, vault_secret_id, filename))
+            display.vvvvv('Trying to use vault secret=(%s) id=%s to decrypt %s' % (vault_secret, vault_secret_id, to_text(filename)))
 
             try:
                 # secret = self.secrets[vault_secret_id]
@@ -726,24 +726,24 @@ def decrypt_and_get_vault_id(self, vaulttext, filename=None):
             except AnsibleVaultFormatError as exc:
                 msg = "There was a vault format error"
                 if filename:
-                    msg += ' in %s' % (filename)
+                    msg += ' in %s' % (to_text(filename))
                 msg += ': %s' % exc
                 display.warning(msg)
                 raise
             except AnsibleError as e:
                 display.vvvv('Tried to use the vault secret (%s) to decrypt (%s) but it failed. Error: %s' %
-                             (vault_secret_id, filename, e))
+                             (vault_secret_id, to_text(filename), e))
                 continue
         else:
             msg = "Decryption failed (no vault secrets were found that could decrypt)"
             if filename:
-                msg += " on %s" % filename
+                msg += " on %s" % to_native(filename)
             raise AnsibleVaultError(msg)
 
         if b_plaintext is None:
             msg = "Decryption failed"
             if filename:
-                msg += " on %s" % filename
+                msg += " on %s" % to_native(filename)
             raise AnsibleError(msg)
 
         return b_plaintext, vault_id_used


Test patch: