diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py index 46024a3404c..0b60e88dcb6 100644 --- a/lib/ansible/config/manager.py +++ b/lib/ansible/config/manager.py @@ -27,7 +27,7 @@ Setting = namedtuple('Setting', 'name value origin type') # FIXME: see if we can unify in module_utils with similar function used by argspec -def ensure_type(value, value_type): +def ensure_type(value, value_type, origin=None): ''' return a configuration variable with casting :arg value: The value to ensure correct typing of :kwarg value_type: The type of the value. This can be any of the following strings: @@ -44,6 +44,11 @@ def ensure_type(value, value_type): means colon separated strings.) Split the value and then expand each part for environment variables and tildes. ''' + + basedir = None + if origin and os.path.isabs(origin) and os.path.exists(origin): + basedir = origin + if value_type: value_type = value_type.lower() @@ -66,10 +71,10 @@ def ensure_type(value, value_type): value = None elif value_type == 'path': - value = resolve_path(value) + value = resolve_path(value, basedir=basedir) elif value_type in ('tmp', 'temppath', 'tmppath'): - value = resolve_path(value) + value = resolve_path(value, basedir=basedir) if not os.path.exists(value): makedirs_safe(value, 0o700) prefix = 'ansible-local-%s' % os.getpid() @@ -78,12 +83,12 @@ def ensure_type(value, value_type): elif value_type == 'pathspec': if isinstance(value, string_types): value = value.split(os.pathsep) - value = [resolve_path(x) for x in value] + value = [resolve_path(x, basedir=basedir) for x in value] elif value_type == 'pathlist': if isinstance(value, string_types): value = value.split(',') - value = [resolve_path(x) for x in value] + value = [resolve_path(x, basedir=basedir) for x in value] # defaults to string types elif isinstance(value, string_types): @@ -93,12 +98,12 @@ def ensure_type(value, value_type): # FIXME: see if this can live in utils/path -def resolve_path(path): +def resolve_path(path, basedir=None): ''' resolve relative or 'varaible' paths ''' if '{{CWD}}' in path: # allow users to force CWD using 'magic' {{CWD}} path = path.replace('{{CWD}}', os.getcwd()) - return unfrackpath(path, follow=False) + return unfrackpath(path, follow=False, basedir=basedir) # FIXME: generic file type? @@ -323,7 +328,7 @@ class ConfigManager(object): # ensure correct type try: - value = ensure_type(value, defs[config].get('type')) + value = ensure_type(value, defs[config].get('type'), origin=origin) except Exception as e: self.UNABLE.append(config) diff --git a/lib/ansible/utils/path.py b/lib/ansible/utils/path.py index 771aab30cb4..717cef6cf01 100644 --- a/lib/ansible/utils/path.py +++ b/lib/ansible/utils/path.py @@ -27,7 +27,7 @@ from ansible.module_utils._text import to_bytes, to_native, to_text __all__ = ['unfrackpath', 'makedirs_safe'] -def unfrackpath(path, follow=True): +def unfrackpath(path, follow=True, basedir=None): ''' Returns a path that is free of symlinks (if follow=True), environment variables, relative path traversals and symbols (~) @@ -43,12 +43,20 @@ def unfrackpath(path, follow=True): '$HOME/../../var/mail' becomes '/var/spool/mail' ''' + if basedir is None: + basedir = os.getcwd() + elif os.path.isfile(basedir): + basedir = os.path.dirname(basedir) + + final_path = os.path.expanduser(os.path.expandvars(to_bytes(path, errors='surrogate_or_strict'))) + + if not os.path.isabs(final_path): + final_path = os.path.join(to_bytes(basedir, errors='surrogate_or_strict'), final_path) + if follow: - final_path = os.path.normpath(os.path.realpath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='surrogate_or_strict'))))) - else: - final_path = os.path.normpath(os.path.abspath(os.path.expanduser(os.path.expandvars(to_bytes(path, errors='surrogate_or_strict'))))) + final_path = os.path.realpath(final_path) - return to_text(final_path, errors='surrogate_or_strict') + return to_text(os.path.normpath(final_path), errors='surrogate_or_strict') def makedirs_safe(path, mode=None):