From c1d90e3f2d8d866946ed48f2fca676ef0fa41fc4 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Thu, 25 Feb 2016 16:37:48 +0100 Subject: [PATCH] Added a section wrt. hybrid plugins and provide an example for lookup plugins --- docsite/rst/porting_guide_2.0.rst | 124 ++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/docsite/rst/porting_guide_2.0.rst b/docsite/rst/porting_guide_2.0.rst index b2b6b15dd1c..6f08bd01c45 100644 --- a/docsite/rst/porting_guide_2.0.rst +++ b/docsite/rst/porting_guide_2.0.rst @@ -254,6 +254,130 @@ Connection plugins * connection plugins +Hybrid plugins +============== +In specific cases you may want a plugin that supports both ansible-1.9.x *and* +ansible-2.0. Much like porting plugins from v1 to v2, you need to understand +how plugins work in each version and support both requirements. It may mean +playing tricks on Ansible. + +Since the ansible-2.0 plugin system is more advanced, it is easier to adapt +your plugin to provide similar pieces (subclasses, methods) for ansible-1.9.x +as ansible-2.0 expects. This way your code will look a lot cleaner. + +You may find the following tips useful: + +* Check whether the ansible-2.0 class(es) are available and if they are missing + (ansible-1.9.x) mimic them with the needed methods (e.g. `__init__`) + +* When ansible-2.0 python modules are imported, and they fail (ansible-1.9.x), + catch the `ImportError` exception and perform the equivalent imports for + ansible-1.9.x. With possible translations (e.g. importing specific methods). + +* Use the existence of these methods as a qualifier to what version of Ansible + you are running. So rather than using version checks, you can do capability + checks instead. (See examples below) + +* Document for each if-then-else case for which specific version each block is + needed. This will help others to understand how they have to adapt their + plugins, but it will also help you to remove the older ansible-1.9.x support + when it is deprecated. + +* When doing plugin development, it is very useful to have the `warning()` + method during development, but it is also important to emit warnings for + deadends (cases that you expect should never be triggered) or corner cases + (e.g. cases where you expect misconfigurations). + + +Lookup plugins +-------------- +As a simple example we are going to make a hybrid `fileglob` lookup plugin. +The `fileglob` lookup plugin is pretty simple to understand:: + + from __future__ import (absolute_import, division, print_function) + __metaclass__ = type + + import os + import glob + + try: + # ansible-2.0 + from ansible.plugins.lookup import LookupBase + except ImportError: + # ansible-1.9.x + + class LookupBase(object): + def __init__(self, basedir=None, runner=None, **kwargs): + self.runner = runner + self.basedir = self.runner.basedir + + def get_basedir(self, variables): + return self.basedir + + try: + # ansible-1.9.x + from ansible.utils import (listify_lookup_plugin_terms, path_dwim, warning) + except ImportError: + # ansible-2.0 + from __main__ import display + warning = display.warning + + class LookupModule(LookupBase): + + # For ansible-1.9.x, we added inject=None as valid arguments + def run(self, terms, inject=None, variables=None, **kwargs): + + # ansible-2.0, but we made this work for ansible-1.9.x too ! + basedir = self.get_basedir(variables) + + # ansible-1.9.x + if 'listify_lookup_plugin_terms' in globals(): + terms = listify_lookup_plugin_terms(terms, basedir, inject) + + ret = [] + for term in terms: + term_file = os.path.basename(term) + + # For ansible-1.9.x, we imported path_dwim() from ansible.utils + if 'path_dwim' in globals(): + # ansible-1.9.x + dwimmed_path = path_dwim(basedir, os.path.dirname(term)) + else: + # ansible-2.0 + dwimmed_path = self._loader.path_dwim_relative(basedir, 'files', os.path.dirname(term)) + + globbed = glob.glob(os.path.join(dwimmed_path, term_file)) + ret.extend(g for g in globbed if os.path.isfile(g)) + + return ret + +Note that in the above example we did not use the `warning()` method as we +had no direct use for it in the final version. However we left this code in +so people can use this part during development/porting/use. + + + +Connection plugins +------------------ + +* connection plugins + +Action plugins +-------------- + +* action plugins + +Callback plugins +---------------- + +* callback plugins + +Connection plugins +------------------ + +* connection plugins + + Porting custom scripts ======================