# Ansible custom module\_utils in Ansible 2.1 & 2.2

**URL:** <https://forum.ansible.com/t/ansible-custom-module-utils-in-ansible-2-1-2-2/27310>\
**Category:** Ansible Project\
**Created:** [April 18, 2018, 6:34am UTC](https://forum.ansible.com/t/ansible-custom-module-utils-in-ansible-2-1-2-2/27310 "2018-04-18T06:34:44Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Raja\_Shekar](https://avatars.discourse-cdn.com/v4/letter/r/ea5d25/32.png) [@Raja\_Shekar](https://forum.ansible.com/u/Raja_Shekar)\
**Post date:** [April 18, 2018, 6:34am UTC](https://forum.ansible.com/t/ansible-custom-module-utils-in-ansible-2-1-2-2/27310/1 "2018-04-18T06:34:44Z")

</div>

Hi,

I am working on Juniper.junos role. We are trying to correct our module\_utils import style to include ansiballz framework. Currently, for our role we support Ansible \>= 2.1. I understand that there was no custom module\_utils support in Ansible 2.1, 2.2 . I need help with a workaround that lets me use ansiballz for Ansible \> 2.2 and the import\_juniper\_junos\_common function for Ansible \<= 2.2.

Using ansible.module\_utils fails in Ansible \< 2.2 as it searches for string `from ansible.module_utils` in module code and changes the module\_style & module\_substyle to ‘new’. The custom module\_utils support is not provided in Ansible \< 2.2.

As a workaround, we decided to use imp library to import from ansible.module\_utils in Ansible \> 2.2 ,else use import\_juniper\_junos\_common function.This workaround fails in Ansible \> 2.2 as ansiballz doesn’t recognise the import statement and hence doesn’t package module\_utils code into zip.

Any pointers on how to make this work ??

Ansible Core code snippet causing the error: [Ansible snippet](https://github.com/ansible/ansible/blob/7baf994f2c7c9f07adf94ab9fa147cf31cdf738d/lib/ansible/executor/module_common.py#L522)

```auto
[import_juniper_junos_common function](https://github.com/Juniper/ansible-junos-stdlib/blob/5b8a15b0408b6423db8162da8bc19349bdcf030a/library/juniper_junos_ping.py#L383)

```

```auto

```

```auto

```

```auto

```

---

<div class="post-metadata">

**Author:** ![tkuratom](https://avatars.discourse-cdn.com/v4/letter/t/b19c9b/32.png) [@tkuratom](https://forum.ansible.com/u/tkuratom)\
**Post date:** [April 18, 2018, 3:37pm UTC](https://forum.ansible.com/t/ansible-custom-module-utils-in-ansible-2-1-2-2/27310/2 "2018-04-18T15:37:44Z")

</div>

First, I should warn you that what you are attempting is very likely  
to turn into a large time sink without a fully satisfactory outcome on  
the other side. You should probably reevaluate the scope of what you  
are doing. Ask yourself these questions:

\* Why support ansible less than 2.4? 2.3 and earlier are unsupported  
by upstream. Any bugs there (including security bugs) will never be  
fixed.

\* Why try to shoehorn this into the ansible.module\_utils framework? It  
will be much easier to work with such old versions and current  
versions and potentially new versions if you make your common code  
into a library that is installed by the users into the remote machine  
(host it on pypi for users to pip install or make system packages for  
them to use their favorite distro tools or come up with something in  
your own role that drops the file into a known location so your module  
can add it to sys.path). You can also have your users install your  
extensions into ansible's official module\_utils directory on their  
control machines. Then ansible can find it when it constructs modules  
to send over the wire.

\* Working at such a low level runs the risk of breaking when we next  
enhance how modules are processed, sent over the wire, and invoked  
remotely. A simpler solution that deviates less from the standard way  
modules operate is less likely to break.

Those disclaimers out of the way, the first thing to figure out is  
what your parameters actually are. You talk about adding custom  
module\_utils, circumventing ansiballz, and using imp in your module to  
import your custom module\_utils however, these are three different  
things.

Ansiballz is the way we locate module\_utils and package them together  
with the module to be sent over the wire for execution by python on  
the remote machine. It seems for your purposes you are trying to make  
use of this to bundle your module\_utils file with your modules  
automatically. This had been available since 2.1.

Custom module\_utils allows you to put a module\_utils file into a  
directory other than site-packages/ansible/module\_utils and ansiballz  
will find it when searching for the libraries it will package with the  
module to transport over the wire. This has been available since 2.3.

Loading of libraries in the modules is entirely separate from the  
latter two. You are free to add to sys.path inside of the module or  
imp.load inside of the module but those won't affect what ansiballz  
found on the controller side.

Taking a look at the code here:  
[https://github.com/Juniper/ansible-junos-stdlib/blob/master/library/juniper\_junos\_facts.py#L174](https://github.com/Juniper/ansible-junos-stdlib/blob/master/library/juniper_junos_facts.py#L174)  
(Let me know if that's not the code that you are using), I think that  
you're sorta taking the route that I mentioned above about trying not  
to use the module\_utils facility since you want to support old  
versions of Ansible. Instead of hardcoding a path that your installer  
establishes as I suggested, it looks like you've chosen to make that  
path configurable via a module parameter. That seems like it will  
work fine. It steps entirely outside of the AnsiballZ framework so  
there won't be conflicts with it.

So it looks like the problem is you want to both use this code which  
circumvents AnsiballZ and also \*not\* circumvent AnsiballZ. That's not  
going to work. If you're going to work outside of the framework you  
need to stay outside of the framework. If you're going to work within  
the framework, you need to stay within the framework. AnsiballZ scans  
module and module\_utils code for python imports (Not a specific  
string, btw, but imports in the abstract syntax tree). Any imports of  
module\_utils code that it finds are used to include those module\_utils  
into an archive with the module code and shipped to the remote machine  
for execution. There is no facility to say "Include this module\_util  
file if you can find it. Otherwise, skip it". Being strict on the  
controller side allows us to be less paranoid in module code...  
Modules can safely assume that any module\_utils import that they make  
will have the module\_utils file available to them. You do not have to  
code a module to handle missing module\_utils.

I would recommend dropping support for older Ansible versions as the  
best way to handle this. However, if you feel you can't do that, then  
you should commit fully to stepping outside of the framework. Do not  
use module\_utils at all for your common code. Instead, install it as  
you do for Ansible-2.1 and 2.2 on every other version of Ansible as  
well. Instead of trying to use import\_juniper\_junos\_common only on  
old versions of Ansible, use it on every version of Ansible. By doing  
those things, you'll be able to stay outside of the framework and not  
interfere with how AnsiballZ functions.

-Toshio
