<h5 dir="auto">ISSUE TYPE</h5>

<ul dir="auto">
<li>Feature Idea</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>

<p dir="auto">module_utils</p>
<h5 dir="auto">ANSIBLE VERSION</h5>

<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ansible 2.3.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jul 21 2017, 03:24:34) [GCC 7.1.1 20170630]"><pre class="notranslate"><code class="notranslate">ansible 2.3.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jul 21 2017, 03:24:34) [GCC 7.1.1 20170630]
</code></pre></div>
<h5 dir="auto">CONFIGURATION</h5>

<p dir="auto">No specific configuration</p>
<h5 dir="auto">OS / ENVIRONMENT</h5>

<p dir="auto">N/A</p>
<h5 dir="auto">SUMMARY</h5>

<p dir="auto">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.</p>
<p dir="auto">For modules, a <code class="notranslate">modules_utils</code> 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 making <code class="notranslate">modules_utils</code> inside action plugins or by creating some other directory for common code, I would like to see the</p>
<p dir="auto">If I am not mistaken, plugins all run locally and modules run on the remote host. As such I assume that all <code class="notranslate">module_utils</code> are sent to the remote host. Given this, it may be beneficial to have <code class="notranslate">plugin_utils</code> which are only available to plugins and are hence not sent to remote hosts. This is not to say that <code class="notranslate">module_utils</code> shouldn't also be available to plugins to avoid the need for the same code in <code class="notranslate">plugin_utils</code> and <code class="notranslate">module_utils</code>.</p>
<h5 dir="auto">STEPS TO REPRODUCE</h5>
<p dir="auto">I have created a <a href="https://github.com/flungo/ansible-module_utils-test">small project</a> which shows that the files under <code class="notranslate">module_utils</code> can be used</p>
<p dir="auto">To run this sample, use <code class="notranslate">ansible -vvv playbook.yml</code>.</p>
<h5 dir="auto">EXPECTED RESULTS</h5>

<p dir="auto">I would like the common code to be imported and for the module to run successfully with the following output for the second task:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="TASK [Get the time using the plugin] ********************************************************************
task path: /home/flungo/developer/ansible/module_util_test/playbook.yml:5
ok: [localhost] =&gt; {
    &quot;changed&quot;: false, 
    &quot;datetime&quot;: &quot;2017-08-29 14:58:19.903485&quot;
}"><pre class="notranslate"><code class="notranslate">TASK [Get the time using the plugin] ********************************************************************
task path: /home/flungo/developer/ansible/module_util_test/playbook.yml:5
ok: [localhost] =&gt; {
    "changed": false, 
    "datetime": "2017-08-29 14:58:19.903485"
}
</code></pre></div>
<h5 dir="auto">ACTUAL RESULTS</h5>

<p dir="auto">The import fails and so the module cannot be loaded:</p>

<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ERROR! Unexpected Exception: No module named datetime_helper
the full traceback was:

Traceback (most recent call last):
  File &quot;/usr/bin/ansible-playbook&quot;, line 109, in &lt;module&gt;
    exit_code = cli.run()
  File &quot;/usr/lib/python2.7/site-packages/ansible/cli/playbook.py&quot;, line 154, in run
    results = pbex.run()
  File &quot;/usr/lib/python2.7/site-packages/ansible/executor/playbook_executor.py&quot;, line 153, in run
    result = self._tqm.run(play=play)
  File &quot;/usr/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py&quot;, line 288, in run
    play_return = strategy.run(iterator, play_context)
  File &quot;/usr/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py&quot;, line 203, in run
    action = action_loader.get(task.action, class_only=True)
  File &quot;/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py&quot;, line 358, in get
    self._module_cache[path] = self._load_module_source(name, path)
  File &quot;/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py&quot;, line 343, in _load_module_source
    module = imp.load_source(full_name, path, module_file)
  File &quot;/home/flungo/developer/ansible/module_util_test/action_plugins/datetime_plugin.py&quot;, line 2, in &lt;module&gt;
    from ansible.module_utils.datetime_helper import get_datetime
ImportError: No module named datetime_helper"><pre class="notranslate"><code class="notranslate">ERROR! Unexpected Exception: No module named datetime_helper
the full traceback was:

Traceback (most recent call last):
  File "/usr/bin/ansible-playbook", line 109, in &lt;module&gt;
    exit_code = cli.run()
  File "/usr/lib/python2.7/site-packages/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/usr/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 153, in run
    result = self._tqm.run(play=play)
  File "/usr/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py", line 288, in run
    play_return = strategy.run(iterator, play_context)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py", line 203, in run
    action = action_loader.get(task.action, class_only=True)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py", line 358, in get
    self._module_cache[path] = self._load_module_source(name, path)
  File "/usr/lib/python2.7/site-packages/ansible/plugins/__init__.py", line 343, in _load_module_source
    module = imp.load_source(full_name, path, module_file)
  File "/home/flungo/developer/ansible/module_util_test/action_plugins/datetime_plugin.py", line 2, in &lt;module&gt;
    from ansible.module_utils.datetime_helper import get_datetime
ImportError: No module named datetime_helper
</code></pre></div>
<p dir="auto">I suspect that <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/bcoca/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/bcoca">@bcoca</a>'s atomic-copy changes in <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/ansible/ansible/commit/caf6bd6ce580f7e9bac719629eff3f77ded52e46/hovercard" href="https://github.com/ansible/ansible/commit/caf6bd6ce580f7e9bac719629eff3f77ded52e46"><tt>caf6bd6</tt></a> can cause some unintended SELinux-related side effects. I've got a playbook that copies a file to the destination host:</p>
<p dir="auto">Before:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[root@nagios limits.d]# ls -lZ
-rw-r--r--. root root system_u:object_r:etc_t:s0       90-nproc.conf
-rw-r--r--. root root unconfined_u:object_r:etc_t:s0   riak.conf"><pre class="notranslate"><code class="notranslate">[root@nagios limits.d]# ls -lZ
-rw-r--r--. root root system_u:object_r:etc_t:s0       90-nproc.conf
-rw-r--r--. root root unconfined_u:object_r:etc_t:s0   riak.conf
</code></pre></div>
<p dir="auto">After:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[root@nagios ~]# ls -lZ /etc/security/limits.d/
-rw-r--r--. root root system_u:object_r:etc_t:s0       90-nproc.conf
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 riak.conf"><pre class="notranslate"><code class="notranslate">[root@nagios ~]# ls -lZ /etc/security/limits.d/
-rw-r--r--. root root system_u:object_r:etc_t:s0       90-nproc.conf
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 riak.conf
</code></pre></div>
<p dir="auto">This particular change actually breaks root login and I suspect it's because of the change in SELinux security context from "etc_t" to "admin_home_t".</p>
<p dir="auto">I don't really know enough about SELinux to comment more extensively on this. I hope someone else can shed some light.</p>