From d2abfb9ff820ac0eb0331aa1c10523a68efd2490 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 18 Nov 2012 18:36:37 +0100 Subject: [PATCH 1/3] Ensure runner adds its basedir, so ansible can benefit from plugins --- lib/ansible/runner/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 3a151a868c9..257ad3346c2 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -151,6 +151,8 @@ class Runner(object): if self.transport == 'local': self.remote_user = pwd.getpwuid(os.geteuid())[0] + utils.plugins.push_basedir(self.basedir) + # ensure we are using unique tmp paths random.seed() From 5dd2ec2cae9c929b647ebe48171e07e3dd8fcbff Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 18 Nov 2012 18:40:56 +0100 Subject: [PATCH 2/3] Add a way to add directories to just one type of loader --- lib/ansible/inventory/__init__.py | 2 +- lib/ansible/utils/plugins.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 3c679ba67ea..12bf0ffac3b 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/utils/plugins.py b/lib/ansible/utils/plugins.py index 5bc91407eb7..1337ade846c 100644 --- a/lib/ansible/utils/plugins.py +++ b/lib/ansible/utils/plugins.py @@ -42,6 +42,7 @@ 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""" @@ -55,7 +56,14 @@ class PluginLoader(object): """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 find_plugin(self, name): """Find a plugin named name""" From f95fefd8c5d4fe300d7c2fffa21b3c8e80dd2834 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 18 Nov 2012 18:37:30 +0100 Subject: [PATCH 3/3] Use plugin system to find modules --- lib/ansible/playbook/__init__.py | 9 ++------- lib/ansible/playbook/task.py | 2 +- lib/ansible/runner/__init__.py | 16 ++++++++-------- lib/ansible/utils/__init__.py | 14 -------------- lib/ansible/utils/plugins.py | 27 +++++++++++++++++++++------ 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index 52c77d72ddd..00cf2d6dd49 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 e6e997b82a5..fb74d6032d4 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 257ad3346c2..f6c71b3150e 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,10 @@ 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 @@ -513,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 b1c06390c2c..753fb99ddb2 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 1337ade846c..50815e6668e 100644 --- a/lib/ansible/utils/plugins.py +++ b/lib/ansible/utils/plugins.py @@ -46,29 +46,43 @@ class PluginLoader(object): 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 self._extra_dirs + - [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 @@ -101,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')