Make all parts of messages and pathnames into unicode so that we don't get UnicodeError tracebacks.

Note that the fix for display normalizing to unicode is correct but the
fix for pathnames is probably not.  Changing pathnames to unicode type
means that we will handle utf8 pathnames fine but pathnames can be any
sequence of bytes that do not contain null.  We do not handle sequences
of bytes that are not valid utf8 here.  To do that we need to revamp the
handling of basedir and paths to transform to bytes instead of unicode.
Didn't want to do that in 2.0.x as it will potentially introduce other
bugs as we find all the places that we combine basedir with other path
elements.  Since no one has raised that as an issue thus far so it's not
something we need to handle yet.  But it's something to keep in mind for
the future.

To test utf8 handling, create a utf8 directory and run a playbook from
within there.

To test non-utf8 handling (currently doesn't work as stated above), create
a directory with non-utf8 chars an run a playbook from there.  In bash,
create that directory like this: mkdir $'\377'

Fixes #13937
pull/14009/head
Toshio Kuratomi 9 years ago
parent 742bd2c554
commit 40373dea4d

@ -32,7 +32,7 @@ import subprocess
from ansible import __version__ from ansible import __version__
from ansible import constants as C from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleOptionsError from ansible.errors import AnsibleError, AnsibleOptionsError
from ansible.utils.unicode import to_bytes from ansible.utils.unicode import to_bytes, to_unicode
try: try:
from __main__ import display from __main__ import display
@ -105,9 +105,9 @@ class CLI(object):
if self.options.verbosity > 0: if self.options.verbosity > 0:
if C.CONFIG_FILE: if C.CONFIG_FILE:
display.display("Using %s as config file" % C.CONFIG_FILE) display.display(u"Using %s as config file" % to_unicode(C.CONFIG_FILE))
else: else:
display.display("No config file found; using defaults") display.display(u"No config file found; using defaults")
@staticmethod @staticmethod
def ask_vault_passwords(ask_new_vault_pass=False, rekey=False): def ask_vault_passwords(ask_new_vault_pass=False, rekey=False):

@ -735,11 +735,11 @@ class Inventory(object):
if group and host is None: if group and host is None:
# load vars in dir/group_vars/name_of_group # load vars in dir/group_vars/name_of_group
base_path = os.path.realpath(os.path.join(basedir, "group_vars/%s" % group.name)) base_path = os.path.realpath(os.path.join(to_unicode(basedir), "group_vars/%s" % group.name))
results = combine_vars(results, self._variable_manager.add_group_vars_file(base_path, self._loader)) results = combine_vars(results, self._variable_manager.add_group_vars_file(base_path, self._loader))
elif host and group is None: elif host and group is None:
# same for hostvars in dir/host_vars/name_of_host # same for hostvars in dir/host_vars/name_of_host
base_path = os.path.realpath(os.path.join(basedir, "host_vars/%s" % host.name)) base_path = os.path.realpath(os.path.join(to_unicode(basedir), "host_vars/%s" % host.name))
results = combine_vars(results, self._variable_manager.add_host_vars_file(base_path, self._loader)) results = combine_vars(results, self._variable_manager.add_host_vars_file(base_path, self._loader))
# all done, results is a dictionary of variables for this particular host. # all done, results is a dictionary of variables for this particular host.

Loading…
Cancel
Save