From b32131c867b9feb5449d3ef71f60eb523e05980e Mon Sep 17 00:00:00 2001 From: Dale Sedivec Date: Thu, 20 Jun 2013 18:34:47 -0500 Subject: [PATCH] expanduser on each component of plug-in paths ansible.constants was calling expanduser (by way of shell_expand_path) on the entire configured value for the library and *_plugins configuration values, but these values have always been interpreted as multiple directories separated by os.pathsep. Thus, if you supplied multiple directories for one of these values, typically only the first (at least on *nix) would have e.g. "~" expanded to HOME. Now PluginLoader does expansion on each individual path in each of these variables. --- lib/ansible/constants.py | 14 +++++------ lib/ansible/utils/plugins.py | 2 ++ test/TestUtils.py | 47 ++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 6632bdc51d2..5f1182eb780 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -71,7 +71,7 @@ DEFAULTS='defaults' # configurable things DEFAULT_HOST_LIST = shell_expand_path(get_config(p, DEFAULTS, 'hostfile', 'ANSIBLE_HOSTS', '/etc/ansible/hosts')) -DEFAULT_MODULE_PATH = shell_expand_path(get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', DIST_MODULE_PATH)) +DEFAULT_MODULE_PATH = get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', DIST_MODULE_PATH) DEFAULT_REMOTE_TMP = shell_expand_path(get_config(p, DEFAULTS, 'remote_tmp', 'ANSIBLE_REMOTE_TEMP', '$HOME/.ansible/tmp')) DEFAULT_MODULE_NAME = get_config(p, DEFAULTS, 'module_name', None, 'command') DEFAULT_PATTERN = get_config(p, DEFAULTS, 'pattern', None, '*') @@ -98,12 +98,12 @@ DEFAULT_LEGACY_PLAYBOOK_VARIABLES = get_config(p, DEFAULTS, 'legacy_playbook_var DEFAULT_JINJA2_EXTENSIONS = get_config(p, DEFAULTS, 'jinja2_extensions', 'ANSIBLE_JINJA2_EXTENSIONS', None) DEFAULT_EXECUTABLE = get_config(p, DEFAULTS, 'executable', 'ANSIBLE_EXECUTABLE', '/bin/sh') -DEFAULT_ACTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'action_plugins', 'ANSIBLE_ACTION_PLUGINS', '/usr/share/ansible_plugins/action_plugins')) -DEFAULT_CALLBACK_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'callback_plugins', 'ANSIBLE_CALLBACK_PLUGINS', '/usr/share/ansible_plugins/callback_plugins')) -DEFAULT_CONNECTION_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'connection_plugins', 'ANSIBLE_CONNECTION_PLUGINS', '/usr/share/ansible_plugins/connection_plugins')) -DEFAULT_LOOKUP_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'lookup_plugins', 'ANSIBLE_LOOKUP_PLUGINS', '/usr/share/ansible_plugins/lookup_plugins')) -DEFAULT_VARS_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'vars_plugins', 'ANSIBLE_VARS_PLUGINS', '/usr/share/ansible_plugins/vars_plugins')) -DEFAULT_FILTER_PLUGIN_PATH = shell_expand_path(get_config(p, DEFAULTS, 'filter_plugins', 'ANSIBLE_FILTER_PLUGINS', '/usr/share/ansible_plugins/filter_plugins')) +DEFAULT_ACTION_PLUGIN_PATH = get_config(p, DEFAULTS, 'action_plugins', 'ANSIBLE_ACTION_PLUGINS', '/usr/share/ansible_plugins/action_plugins') +DEFAULT_CALLBACK_PLUGIN_PATH = get_config(p, DEFAULTS, 'callback_plugins', 'ANSIBLE_CALLBACK_PLUGINS', '/usr/share/ansible_plugins/callback_plugins') +DEFAULT_CONNECTION_PLUGIN_PATH = get_config(p, DEFAULTS, 'connection_plugins', 'ANSIBLE_CONNECTION_PLUGINS', '/usr/share/ansible_plugins/connection_plugins') +DEFAULT_LOOKUP_PLUGIN_PATH = get_config(p, DEFAULTS, 'lookup_plugins', 'ANSIBLE_LOOKUP_PLUGINS', '/usr/share/ansible_plugins/lookup_plugins') +DEFAULT_VARS_PLUGIN_PATH = get_config(p, DEFAULTS, 'vars_plugins', 'ANSIBLE_VARS_PLUGINS', '/usr/share/ansible_plugins/vars_plugins') +DEFAULT_FILTER_PLUGIN_PATH = get_config(p, DEFAULTS, 'filter_plugins', 'ANSIBLE_FILTER_PLUGINS', '/usr/share/ansible_plugins/filter_plugins') DEFAULT_LOG_PATH = shell_expand_path(get_config(p, DEFAULTS, 'log_path', 'ANSIBLE_LOG_PATH', '')) ANSIBLE_NOCOWS = get_config(p, DEFAULTS, 'nocows', 'ANSIBLE_NOCOWS', None) diff --git a/lib/ansible/utils/plugins.py b/lib/ansible/utils/plugins.py index 88aaa792b37..6c5b92d1406 100644 --- a/lib/ansible/utils/plugins.py +++ b/lib/ansible/utils/plugins.py @@ -16,6 +16,7 @@ # along with Ansible. If not, see . import os +import os.path import sys import glob import imp @@ -108,6 +109,7 @@ class PluginLoader(object): # look in any configured plugin paths, allow one level deep for subcategories configured_paths = self.config.split(os.pathsep) for path in configured_paths: + path = os.path.expanduser(path) contents = glob.glob("%s/*" % path) for c in contents: if os.path.isdir(c): diff --git a/test/TestUtils.py b/test/TestUtils.py index 1a3d488985e..61fe445c292 100644 --- a/test/TestUtils.py +++ b/test/TestUtils.py @@ -1,6 +1,11 @@ # -*- coding: utf-8 -*- import unittest +import os +import os.path +import tempfile + +from nose.plugins.skip import SkipTest import ansible.utils import ansible.utils.template as template2 @@ -376,3 +381,45 @@ class TestUtils(unittest.TestCase): def test_parse_kv_basic(self): assert (ansible.utils.parse_kv('a=simple b="with space" c="this=that"') == {'a': 'simple', 'b': 'with space', 'c': 'this=that'}) + + ##################################### + ### plugins + + def test_loaders_expanduser_each_dir(self): + # Test that PluginLoader will call expanduser on each path + # when it splits its "config" argument. + home_dir = os.path.expanduser("~") + if home_dir == "~": + raise SkipTest("your platform doesn't expand ~ in paths") + elif not os.path.isdir(home_dir): + raise SkipTest("~ expands to non-directory %r" % (home_dir,)) + elif not os.path.isabs(home_dir): + raise SkipTest("~ expands to non-absolute path %r" % (home_dir,)) + # Unfortunately we have to create temporary directories in + # your home directory; the directories have to exist for + # PluginLoader to accept them. + abs_dirs, tilde_dirs = [], [] + try: + for _ in range(2): + temp_dir = tempfile.mkdtemp(prefix="ansible", dir=home_dir) + abs_dirs.append(temp_dir) + # Convert mkdtemp's absolute path to one starting with "~". + tilde_dir = os.path.join("~", os.path.relpath(temp_dir, + home_dir)) + tilde_dirs.append(tilde_dir) + loader = ansible.utils.plugins.PluginLoader( + "", + "", + os.pathsep.join(tilde_dirs), + "something_under_basedir" + ) + loader_paths = loader.print_paths().split(os.pathsep) + for abs_dir in abs_dirs: + assert abs_dir in loader_paths, \ + "%r not in %r" % (abs_dir, loader_paths) + finally: + for a_dir in abs_dirs: + try: + os.rmdir(a_dir) + except os.error: + pass