diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 3c679ba67e..12bf0ffac3 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -68,7 +68,7 @@ class Inventory(object): host_list = [ h for h in host_list if h and h.strip() ] else: - utils.plugins.push_basedir(self.basedir()) + utils.plugins.vars_loader.add_directory(self.basedir()) if type(host_list) == list: all = Group('all') diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index 52c77d72dd..00cf2d6dd4 100644 --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -44,7 +44,7 @@ class PlayBook(object): def __init__(self, playbook = None, host_list = C.DEFAULT_HOST_LIST, - module_path = C.DEFAULT_MODULE_PATH, + module_path = None, forks = C.DEFAULT_FORKS, timeout = C.DEFAULT_TIMEOUT, remote_user = C.DEFAULT_REMOTE_USER, @@ -110,17 +110,11 @@ class PlayBook(object): self.inventory = ansible.inventory.Inventory(host_list) self.inventory.subset(subset) - self.modules_list = utils.get_available_modules(self.module_path) - if not self.inventory._is_script: self.global_vars.update(self.inventory.get_group_variables('all')) self.basedir = os.path.dirname(playbook) (self.playbook, self.play_basedirs) = self._load_playbook_from_file(playbook) - self.module_path = self.module_path + os.pathsep + os.path.join(self.basedir, "library") - - for i in self.play_basedirs: - utils.plugins.push_basedir(i) # ***************************************************** @@ -137,6 +131,7 @@ class PlayBook(object): raise errors.AnsibleError("parse error: playbooks must be formatted as a YAML list") basedir = os.path.dirname(path) + utils.plugins.push_basedir(basedir) for play in playbook_data: if type(play) != dict: raise errors.AnsibleError("parse error: each play in a playbook must a YAML dictionary (hash), recieved: %s" % play) diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index e6e997b82a..fb74d6032d 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -44,7 +44,7 @@ class Task(object): for x in ds.keys(): # code to allow for saying "modulename: args" versus "action: modulename args" - if x in play.playbook.modules_list: + if x in utils.plugins.module_finder: ds['action'] = x + " " + ds[x] ds.pop(x) diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 3a151a868c..f6c71b3150 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -91,7 +91,7 @@ class Runner(object): def __init__(self, host_list=C.DEFAULT_HOST_LIST, # ex: /etc/ansible/hosts, legacy usage - module_path=C.DEFAULT_MODULE_PATH, # ex: /usr/share/ansible + module_path=None, # ex: /usr/share/ansible module_name=C.DEFAULT_MODULE_NAME, # ex: copy module_args=C.DEFAULT_MODULE_ARGS, # ex: "src=/tmp/a dest=/tmp/b" forks=C.DEFAULT_FORKS, # parallelism level @@ -128,7 +128,6 @@ class Runner(object): self.sudo_user = sudo_user self.connector = connection.Connection(self) self.conditional = conditional - self.module_path = module_path self.module_name = module_name self.forks = int(forks) self.pattern = pattern @@ -151,6 +150,12 @@ class Runner(object): if self.transport == 'local': self.remote_user = pwd.getpwuid(os.geteuid())[0] + if module_path is not None: + for i in module_path.split(os.pathsep): + utils.plugins.module_finder.add_directory(i) + + utils.plugins.push_basedir(self.basedir) + # ensure we are using unique tmp paths random.seed() @@ -511,12 +516,9 @@ class Runner(object): raise errors.AnsibleFileNotFound("%s is not a module" % module_name) # Search module path(s) for named module. - for module_path in self.module_path.split(os.pathsep): - in_path = os.path.expanduser(os.path.join(module_path, module_name)) - if os.path.exists(in_path): - break - else: - raise errors.AnsibleFileNotFound("module %s not found in %s" % (module_name, self.module_path)) + in_path = utils.plugins.module_finder.find_plugin(module_name) + if in_path is None: + raise errors.AnsibleFileNotFound("module %s not found in %s" % (module_name, utils.plugins.module_finder.print_paths())) out_path = os.path.join(tmp, module_name) diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py index b1c06390c2..753fb99ddb 100644 --- a/lib/ansible/utils/__init__.py +++ b/lib/ansible/utils/__init__.py @@ -463,20 +463,6 @@ def filter_leading_non_json_lines(buf): filtered_lines.write(line + '\n') return filtered_lines.getvalue() -def get_available_modules(dirname=None): - """ - returns a list of modules available based on current directory - looks in DEFAULT_MODULE_PATH, all subfolders named library and - -M option""" - modules_list = set() - if dirname is None: - dirname = C.DEFAULT_MODULE_PATH - for path in dirname.split(os.pathsep): - if os.path.exists(path): - modules_list.update(os.listdir(path)) - modules_list = list(modules_list) - return modules_list - def boolean(value): val = str(value) if val.lower() in [ "true", "t", "y", "1", "yes" ]: diff --git a/lib/ansible/utils/plugins.py b/lib/ansible/utils/plugins.py index 5bc91407eb..50815e6668 100644 --- a/lib/ansible/utils/plugins.py +++ b/lib/ansible/utils/plugins.py @@ -42,25 +42,47 @@ class PluginLoader(object): self.subdir = subdir self.aliases = aliases self._module_cache = {} + self._extra_dirs = [] def _get_package_path(self): """Gets the path of a Python package""" + if not self.package: + return [] if not hasattr(self, 'package_path'): m = __import__(self.package) parts = self.package.split('.')[1:] self.package_path = os.path.join(os.path.dirname(m.__file__), *parts) - return self.package_path + return [self.package_path] def _get_paths(self): """Return a list of paths to search for plugins in The list is searched in order.""" - return [os.path.join(basedir, self.subdir) for basedir in _basedirs] + self.config.split(os.pathsep) + [self._get_package_path()] + return self._extra_dirs + \ + [os.path.join(basedir, self.subdir) for basedir in _basedirs] + \ + self.config.split(os.pathsep) + \ + self._get_package_path() + + def add_directory(self, directory): + """Adds an additional directory to the search path""" + self._extra_dirs.append(directory) + + def print_paths(self): + """Returns a string suitable for printing of the search path""" + # Uses a list to get the order right + ret = [] + for i in self._get_paths(): + if i not in ret: + ret.append(i) + return os.pathsep.join(ret) def find_plugin(self, name): """Find a plugin named name""" + suffix = ".py" + if not self.class_name: + suffix = "" for i in self._get_paths(): - path = os.path.join(i, "%s.py" % name) + path = os.path.join(i, "%s%s" % (name, suffix)) if os.path.exists(path): return path return None @@ -93,6 +115,7 @@ class PluginLoader(object): action_loader = PluginLoader('ActionModule', 'ansible.runner.action_plugins', C.DEFAULT_ACTION_PLUGIN_PATH, 'action_plugins') callback_loader = PluginLoader('CallbackModule', 'ansible.callback_plugins', C.DEFAULT_CALLBACK_PLUGIN_PATH, 'callback_plugins') connection_loader = PluginLoader('Connection', 'ansible.runner.connection_plugins', C.DEFAULT_CONNECTION_PLUGIN_PATH, 'connection_plugins', aliases={'paramiko': 'paramiko_ssh'}) +module_finder = PluginLoader('', '', C.DEFAULT_MODULE_PATH, 'library') lookup_loader = PluginLoader('LookupModule', 'ansible.runner.lookup_plugins', C.DEFAULT_LOOKUP_PLUGIN_PATH, 'lookup_plugins') vars_loader = PluginLoader('VarsModule', 'ansible.inventory.vars_plugins', C.DEFAULT_VARS_PLUGIN_PATH, 'vars_plugins') filter_loader = PluginLoader('FilterModule', 'ansible.runner.filter_plugins', C.DEFAULT_FILTER_PLUGIN_PATH, 'filter_plugins')