-
Notifications
You must be signed in to change notification settings - Fork 23.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow dynamic imports in plugins. #28770
Comments
Files identified in the description: If these files are inaccurate, please update the |
👍 - this would be very helpful for making custom lookup code reusable / modular. |
Unlike module_utils, this doesn't seem very useful except as a matter of symmetry. You can just install into a local pythonpath for controller code. To keep everything contained in the role, you can do something like include a python wheel or zipfile of the code you need to install in the roles files and then use the pip module to install that on the local system as one of the role's first tasks. |
I won't speak to @flungo 's original use case / reason for opening this ticket, but for me, it would be useful to keep everything in one git repository without the need for shims or some kind of notification/documentation that PYTHONPATH must be set to a local path. For my use case, we would want users to be able to simply git checkout and use Ansible without any other interventions. Symmetry in my mind makes this less astonishing, too, which is always good (since there is a reasonable expectation, at least in my mind, that plugins would work in a somewhat similar fashion as modules). |
I think that the example I sketched above satisfies all of your needs. |
Here's a sample of the example to make clear what I mean: https://github.com/abadger/sample-28770 |
Your sample is definitely clear, but having to create the scaffolding to create a pip package and then install/maintain it is a lot of paperwork and, more importantly, a lot of added complexity, particularly if you have multiple small libraries. Aside from symmetry, having this as a native Ansible feature would lead to simpler playbooks and cleaner, more self-contained Ansible repos. I see that Ansible is pretty much just doing some vanilla The feature is so close to already existing it can almost be achieved with just some "hackery": |
I've took sometime to check loader implementation and got some ideas here. I believe that after #37748 we are unable to import filter plugins via imp.load_source(..) because they are imported with package_names consisting of full path to the file.
So, we are obviously can't reference this module it from other filter/module. And this is true for filters,tests,callbacks:
I have a suggestion to revert module package name to old behaviour, so that package_name will be correct(e.g. ansible.plugins.filter.ipaddr), but if we are still hitting duplicate package names, just load it with a new naming(e.g. ansible.plugins.filter./opt/awx/awx-app/venv/lib/python2.7/site-packages/ansible/plugins/filter/ipaddr) and display warning to user. @abadger, what do you think? |
I would also like a way to share code between my inventory, action, and lookup plugins. @abadger Your example is interesting, I don't want my playbooks to do local pip installs because ansible is running in one of various virtualenvs on the controller, so assuming you can access --user is not always true. I'm currently installing a python module in those virtualenvs with some shared code, but I don't want to maintain the machinery to keep those virtualenvs up to date with the playbooks repo as I update it. In several cases, the virtualenv belongs to some other program, and that program doesn't provide any hooks to allow for installing additional packages beyond its own requirements.txt, so I don't like modifying the virtualenv in case that program modifies or replaces the virtualenv (eg during an update). |
I'm on ansible 2.7, but I also considered using content collections with ansible 2.8 / mazer. |
@nitzmahone (responding to your #48844 (comment) ) Is there a way to share code between controller-side plugins with collections? How does the collections namespacing work in Ansible 2.8?
edit: to add this comment: |
Haven't looked into namespaces in 2.8, but an additional work around in 2.7 through 2.8, better than one I posted in an earlier issue, is to use As an example, if your top-level inventory plugins directory is
And then you can import in your filter plugins like this: |
@cognifloyd Because collections-hosted controller plugins are loaded and instantiated by a PEP302 loader (bypassing a lot of the "fun" in |
As problem is still actual, this is my approach. module_utils = module_utils Then I tried to load this module into a custom Action plugin with class ActionModule(ActionBase):
def run(self, tmp=None, task_vars=None):
module = self._shared_loader_obj.module_utils_loader.get('custom', class_only=True) But it was unsuccessful:
So I had to add a little hack into my module: def __getattr__(name):
import sys
if name == '':
return sys.modules[__name__] Thus you could use your module_utils in modules and in plugins as well. |
Not sure what you're trying to accomplish here, but this is almost certainly not the right way to do it. You can do this trivially with a playbook-adjacent collection in 2.8+ with no such hackery required. |
I'm actually going to close this issue, since collections satisfies the original request... |
ISSUE TYPE
COMPONENT NAME
module_utils
ANSIBLE VERSION
CONFIGURATION
No specific configuration
OS / ENVIRONMENT
N/A
SUMMARY
It does not seem that there is at present a way to have common code between plugins provided adjacent to a playbook or in a role. This can result in plugin files having a lot of common code which has to be maintained in multiple places. I think it would be beneficial for there to be a way of sharing code between plugins. This is possible (and common) within the packaged plugins and will help with the development of new plugins.
For modules, a
modules_utils
directory can be included adjacent to the playbook or inside the role which can then be accessed by custom modules to provide common functionality. This is extremely useful but does not work with plugins. Whether it is by makingmodules_utils
inside action plugins or by creating some other directory for common code, I would like to see theIf I am not mistaken, plugins all run locally and modules run on the remote host. As such I assume that all
module_utils
are sent to the remote host. Given this, it may be beneficial to haveplugin_utils
which are only available to plugins and are hence not sent to remote hosts. This is not to say thatmodule_utils
shouldn't also be available to plugins to avoid the need for the same code inplugin_utils
andmodule_utils
.STEPS TO REPRODUCE
I have created a small project which shows that the files under
module_utils
can be usedTo run this sample, use
ansible -vvv playbook.yml
.EXPECTED RESULTS
I would like the common code to be imported and for the module to run successfully with the following output for the second task:
ACTUAL RESULTS
The import fails and so the module cannot be loaded:
The text was updated successfully, but these errors were encountered: