Repository: ansible/ansible

Issue:
'prompt' doesn't accept non-ASCII characters
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
vars_prompt

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
$ ansible --version
ansible 2.3.2.0
  config file = /work/ansible/configuration/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
N/A

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
CentOS 7

##### SUMMARY
<!--- Explain the problem briefly -->
Non-ASCII characters in the prompt of a vars_prompt section cause errors. This looks very much like #10319, however, it was closed a long time ago, and this is happening on a recent release.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
  vars_prompt:
    - name: "test"
      prompt: "é"

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
It should prompt for tha variable:
```
é:
```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
ERROR! Unexpected Exception: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
the full traceback was:

Traceback (most recent call last):
  File "/usr/bin/ansible-playbook", line 109, in <module>
    exit_code = cli.run()
  File "/usr/lib/python2.7/site-packages/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/usr/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 119, in run
    play.vars[vname] = display.do_var_prompt(vname, private, prompt, encrypt, confirm, salt_size, salt, default)
  File "/usr/lib/python2.7/site-packages/ansible/utils/display.py", line 304, in do_var_prompt
    result = do_prompt(msg, private)
  File "/usr/lib/python2.7/site-packages/ansible/utils/display.py", line 278, in prompt
    return getpass.getpass(msg)
  File "/usr/lib64/python2.7/getpass.py", line 71, in unix_getpass
    passwd = _raw_input(prompt, stream, input=input)
  File "/usr/lib64/python2.7/getpass.py", line 128, in _raw_input
    prompt = str(prompt)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
```



Discussion:
Looks like we can use ```to_native()``` of the prompt.

Python3:
```
>>> getpass.getpass(u'\xe9')
é
'w'
>>> getpass.getpass(b'\xe9')
b'\xe9'
'e'
```

Python2:
```
>>> getpass.getpass(b'é')
é
'd'
>>> getpass.getpass(u'é')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/getpass.py", line 71, in unix_getpass
    passwd = _raw_input(prompt, stream, input=input)
  File "/usr/lib64/python2.7/getpass.py", line 128, in _raw_input
    prompt = str(prompt)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
```

So we need a text string on python3 and a byte string on python2... just what ```to_native()``` was designed for.

Resolving patch:
diff --git a/lib/ansible/utils/display.py b/lib/ansible/utils/display.py
--- a/lib/ansible/utils/display.py
+++ b/lib/ansible/utils/display.py
@@ -279,7 +279,7 @@ def prompt(msg, private=False):
             prompt_string = to_text(prompt_string)
 
         if private:
-            return getpass.getpass(msg)
+            return getpass.getpass(prompt_string)
         else:
             return input(prompt_string)
 


Test patch: