|
|
|
|
@ -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
|
|
|
|
|
======================
|
|
|
|
|
|
|
|
|
|
|