Skip to content
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

Non-module files in the module directory conflict with modules; "setup.py" in particular #20702

Closed
bdowling opened this issue Jan 26, 2017 · 7 comments
Labels
affects_2.3 This issue/PR affects Ansible v2.3 bug This issue/PR relates to a bug. c:module_utils/facts module This issue/PR relates to a module. support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@bdowling
Copy link
Contributor

bdowling commented Jan 26, 2017

ISSUE TYPE
  • Bug Report
COMPONENT NAME

executer.py
setup.py

ANSIBLE VERSION
ansible 2.3.0 (devel 07a517aebd) last updated 2017/01/09 13:04:28 (GMT -400)
  config file = /home/bdowling/.ansible.cfg
  configured module search path = [u'/home/bdowling/src/ansible-modules/']
SUMMARY

When using and developing/improving other modules from 3rd parties it is often easier to keep the working git directory in your module path to streamline development cycle.

However one conflict with ansible prevents doing this with many python projects due to the naming conflict with setup.py. Ansible scans everywhere for the setup.py and could find it (recursively) in the module path, thus finding the wrong setup module. This has also been observed to find "setup.cfg" files as well and attempt to load those, which is also a problematic second issue that alternative non-exec files are being found.

STEPS TO REPRODUCE
# Setup ansible to have a library path, CD into that directory:
$ cd ~/src/ansible-modules
$ git clone https://github.com/networktocode/ntc-ansible --recursive
$ cd
$ ansible -vvv -m setup localhost
Using /home/bdowling/.ansible.cfg as config file
Using module file /home/bdowling/src/ansible-modules/ntc-ansible/setup.cfg
127.0.0.1 | FAILED! => {
    "failed": true, 
    "msg": "module (setup) is missing interpreter line"

# Any playbook with gather_facts on will error out..
$ ansible-playbook -vvv -l onerouter dump-vars.yaml
Using /home/bdowling/.ansible.cfg as config file

PLAYBOOK: dump-vars.yaml ***********************************************************************
1 plays in dump-vars.yaml

PLAY [test] ***********************************************************************************

TASK [Gathering Facts] *************************************************************************
*Using module file /home/bdowling/src/ansible-modules/ntc-ansible/setup.cfg*
fatal: [rtr02]: FAILED! => {
    "failed": true, 
    "msg": "module (setup) is missing interpreter line"
}

msg: module (setup) is missing interpreter line

PLAY RECAP *************************************************************************************
rtr02              : ok=0    changed=0    unreachable=0    failed=1   

Playbook used above:

---

- hosts: test
  connection: local
  gather_facts: yes

  tasks:
  - name: Dump All Variables
    action: template src=templates/dumpall-raw.j2 dest=/tmp/ansible-vars.txt
EXPECTED RESULTS

Ansible should find it's setup module in it's own namespace/directory not in the library path.

ACTUAL RESULTS
See Above
@ansibot ansibot added affects_2.3 This issue/PR affects Ansible v2.3 bug_report module This issue/PR relates to a module. needs_triage Needs a first human triage before being processed. labels Jan 26, 2017
@bdowling
Copy link
Contributor Author

Mentioned this to @gundalow on networktocode..

Here's a downstream in reference to this issue.. networktocode/ntc-ansible#142

@bdowling
Copy link
Contributor Author

I just noticed this first complained about the setup.cfg, just for completeness of reporting the issue, renaming that with DISABLED- prefix, results in it then finding the setup.py, etc etc..

Using module file /home/bdowling/src/ansible-modules/ntc-ansible/setup.py

@ansibot ansibot removed the module This issue/PR relates to a module. label Jan 26, 2017
@gundalow gundalow removed the needs_triage Needs a first human triage before being processed. label Jan 27, 2017
@gundalow
Copy link
Contributor

So there is a proposed fix in #20717

However there isn't a short term fix, there is one for in 4 versions time, due to deprecating the existing term that's used in many playbooks

@jctanner
Copy link
Contributor

resolved_by_pr #20717

@jctanner jctanner added c:module_utils/facts module This issue/PR relates to a module. labels Jan 30, 2017
@bdowling
Copy link
Contributor Author

In looking closer at the issues this raised, I wanted to understand the module loading better.

Below you can see output of the instrumentation I added to help follow the code.

Doing this has raised a few more questions/concerns about how things get found. If you look at the trace below, you can see that the 'setup' module is searched for in various module classes and then globally. I'm curious about the design goals here, as I would think there would be a desire to have more targeted loading of core modules than this portrays. setup aka gather_facts is in modules/system, but modules/system is not searched in a targeted way? The way modules are searched for today essentially flattens the module namespace. setup.py is just an easy conflict to occur, but there could be many others as the search path grows 2-3 levels deep, etc.

Perhaps more parts of the hierarchy should be considered. e.g. if I want to override ansible/modules/system/foo, I should be putting my override in my package/system/foo (or package/modules/system/foo if it were to be really consistent). I think this issue is related to an old issue I saw discussed before where modules were found recursively, and it was found this was an unintended, but depended on behavior by the community.

Here are the lines cut from below just related to finding 'setup', e.g. via ActionModule.get(), then ActionModule.find_module(), finally module_loader.find_module():

plugins/__init__.py[360].get: setup, ActionModule. ansible.plugins.action
plugins/__init__.py[230].find_plugin: setup MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: setup MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[268].find_plugin: setup FIND class 'ActionModule' no paths left to search
plugins/__init__.py[334].find_plugin: setup module NOT FOUND
plugins/__init__.py[369].get: ...
plugins/__init__.py[230].find_plugin: setup MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: setup MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[268].find_plugin: setup FIND class 'ActionModule' no paths left to search
plugins/__init__.py[334].find_plugin: setup module NOT FOUND
plugins/__init__.py[230].find_plugin: setup MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[236].find_plugin: ALIAS EXISTS FOR setup -> gather_facts, BUT NOT USED because get() NOT CALLED
plugins/__init__.py[255].find_plugin: setup MODULE path ~/src/ansible-modules/ntc-ansible/setup.cfg
action/__init__.py[585]._execute_module: Using module file ~/src/ansible-modules/ntc-ansible/setup.cfg

I did see the built-in alias functionality that already exists PluginLoader(s), however adding an alias for 'setup' has no effect via module_loader in this case. You can see from the bottom of this trace, the last call to find_plugin is called without going through the .get() method, so the alias does not take effect. action/__init.py__[132,143] https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/action/__init__.py#L132..L143 calls find_plugin() directly. Not sure if this is an issue or intended side-effect, paramiko is the only existing alias, so this may not have been noticed before.

The other point about below is this is where it finds setup.cfg and bombs out when it realizes it does not have an interpreter. One thought might be that it should notice this earlier and just skip the file, attempting to find a better match. e.g. skip files that don't look like executable scripts/.py files? (in this case it'd find the package's setup.py install script, but still a little more specific.)

There are also a number of lookup for other "simple" module names (action, async, poll, meta, smart), that are not found (meta is looked for twice, one is found via ActionModule), not sure what those are about either.

Using ~/.ansible.cfg as config file
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: memory, CacheModule. ansible.plugins.cache
plugins/__init__.py[230].find_plugin: memory MODULE, class: 'CacheModule', package: ansible.plugins.cache, mod_type: ''
plugins/__init__.py[242].find_plugin: memory MODULE find in class CacheModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: memory FIND class 'CacheModule' searching paths: ['~/src/ansible/lib/ansible/plugins/cache', '~/src/ansible/lib/ansible/plugins/cache/__pycache__']
plugins/__init__.py[315].find_plugin: memory MODULE cached path == ~/src/ansible/lib/ansible/plugins/cache/memory.py
plugins/__init__.py[368].get: memory MODULE is path ~/src/ansible/lib/ansible/plugins/cache/memory.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[230].find_plugin: action MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[266].find_plugin: action FIND class '' searching paths: [u'~/src/ansible-modules/ntc-ansible', u'~/src/ansible-modules/ntc-ansible/group_vars', u'~/src/ansible-modules/ntc-ansible/build', u'~/src/ansible-modules/ntc-ansible/filter_plugins', u'~/src/ansible-modules/ntc-ansible/ntc-templates', u'~/src/ansible-modules/ntc-ansible/library', u'~/src/ansible-modules/ntc-ansible/dist', u'~/src/ansible-modules', '~/src/ansible/lib/ansible/modules', '~/src/ansible/lib/ansible/modules/clustering', '~/src/ansible/lib/ansible/modules/files', '~/src/ansible/lib/ansible/modules/identity', '~/src/ansible/lib/ansible/modules/system', '~/src/ansible/lib/ansible/modules/storage', '~/src/ansible/lib/ansible/modules/monitoring', '~/src/ansible/lib/ansible/modules/web_infrastructure', '~/src/ansible/lib/ansible/modules/inventory', '~/src/ansible/lib/ansible/modules/notification', '~/src/ansible/lib/ansible/modules/network', '~/src/ansible/lib/ansible/modules/commands', '~/src/ansible/lib/ansible/modules/crypto', '~/src/ansible/lib/ansible/modules/utilities', '~/src/ansible/lib/ansible/modules/packaging', '~/src/ansible/lib/ansible/modules/source_control', '~/src/ansible/lib/ansible/modules/cloud', '~/src/ansible/lib/ansible/modules/remote_management', '~/src/ansible/lib/ansible/modules/messaging', '~/src/ansible/lib/ansible/modules/__pycache__', '~/src/ansible/lib/ansible/modules/database', '~/src/ansible/lib/ansible/modules/identity/ipa', '~/src/ansible/lib/ansible/modules/identity/opendj', '~/src/ansible/lib/ansible/modules/storage/infinidat', '~/src/ansible/lib/ansible/modules/storage/zfs', '~/src/ansible/lib/ansible/modules/storage/netapp', '~/src/ansible/lib/ansible/modules/network/asa', '~/src/ansible/lib/ansible/modules/network/citrix', '~/src/ansible/lib/ansible/modules/network/ios', '~/src/ansible/lib/ansible/modules/network/vyos', '~/src/ansible/lib/ansible/modules/network/netconf', '~/src/ansible/lib/ansible/modules/network/f5', '~/src/ansible/lib/ansible/modules/network/panos', '~/src/ansible/lib/ansible/modules/network/junos', '~/src/ansible/lib/ansible/modules/network/basics', '~/src/ansible/lib/ansible/modules/network/openswitch', '~/src/ansible/lib/ansible/modules/network/netvisor', '~/src/ansible/lib/ansible/modules/network/cloudengine', '~/src/ansible/lib/ansible/modules/network/dellos9', '~/src/ansible/lib/ansible/modules/network/bigswitch', '~/src/ansible/lib/ansible/modules/network/cumulus', '~/src/ansible/lib/ansible/modules/network/iosxr', '~/src/ansible/lib/ansible/modules/network/ovs', '~/src/ansible/lib/ansible/modules/network/dellos6', '~/src/ansible/lib/ansible/modules/network/eos', '~/src/ansible/lib/ansible/modules/network/illumos', '~/src/ansible/lib/ansible/modules/network/exoscale', '~/src/ansible/lib/ansible/modules/network/sros', '~/src/ansible/lib/ansible/modules/network/nxos', '~/src/ansible/lib/ansible/modules/network/dellos10', '~/src/ansible/lib/ansible/modules/network/a10', '~/src/ansible/lib/ansible/modules/utilities/helper', '~/src/ansible/lib/ansible/modules/utilities/logic', '~/src/ansible/lib/ansible/modules/packaging/os', '~/src/ansible/lib/ansible/modules/packaging/language', '~/src/ansible/lib/ansible/modules/cloud/profitbricks', '~/src/ansible/lib/ansible/modules/cloud/cloudstack', '~/src/ansible/lib/ansible/modules/cloud/atomic', '~/src/ansible/lib/ansible/modules/cloud/openstack', '~/src/ansible/lib/ansible/modules/cloud/ovirt', '~/src/ansible/lib/ansible/modules/cloud/packet', '~/src/ansible/lib/ansible/modules/cloud/lxd', '~/src/ansible/lib/ansible/modules/cloud/linode', '~/src/ansible/lib/ansible/modules/cloud/centurylink', '~/src/ansible/lib/ansible/modules/cloud/azure', '~/src/ansible/lib/ansible/modules/cloud/digital_ocean', '~/src/ansible/lib/ansible/modules/cloud/dimensiondata', '~/src/ansible/lib/ansible/modules/cloud/cloudscale', '~/src/ansible/lib/ansible/modules/cloud/vmware', '~/src/ansible/lib/ansible/modules/cloud/smartos', '~/src/ansible/lib/ansible/modules/cloud/softlayer', '~/src/ansible/lib/ansible/modules/cloud/lxc', '~/src/ansible/lib/ansible/modules/cloud/docker', '~/src/ansible/lib/ansible/modules/cloud/misc', '~/src/ansible/lib/ansible/modules/cloud/rackspace', '~/src/ansible/lib/ansible/modules/cloud/webfaction', '~/src/ansible/lib/ansible/modules/cloud/ovh', '~/src/ansible/lib/ansible/modules/cloud/univention', '~/src/ansible/lib/ansible/modules/cloud/amazon', '~/src/ansible/lib/ansible/modules/cloud/google', '~/src/ansible/lib/ansible/modules/remote_management/stacki', '~/src/ansible/lib/ansible/modules/remote_management/ipmi', '~/src/ansible/lib/ansible/modules/remote_management/foreman', '~/src/ansible/lib/ansible/modules/database/postgresql', '~/src/ansible/lib/ansible/modules/database/influxdb', '~/src/ansible/lib/ansible/modules/database/misc', '~/src/ansible/lib/ansible/modules/database/mssql', '~/src/ansible/lib/ansible/modules/database/vertica', '~/src/ansible/lib/ansible/modules/database/mysql', '~/src/ansible/lib/ansible/modules/windows']
plugins/__init__.py[334].find_plugin: action module NOT FOUND
plugins/__init__.py[230].find_plugin: async MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[268].find_plugin: async FIND class '' no paths left to search
plugins/__init__.py[334].find_plugin: async module NOT FOUND
plugins/__init__.py[230].find_plugin: poll MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[268].find_plugin: poll FIND class '' no paths left to search
plugins/__init__.py[334].find_plugin: poll module NOT FOUND
plugins/__init__.py[230].find_plugin: async MODULE, class: 'LookupModule', package: ansible.plugins.lookup, mod_type: ''
plugins/__init__.py[242].find_plugin: async MODULE find in class LookupModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: async FIND class 'LookupModule' searching paths: ['~/src/ansible/lib/ansible/plugins/lookup', '~/src/ansible/lib/ansible/plugins/lookup/__pycache__']
plugins/__init__.py[334].find_plugin: async module NOT FOUND
plugins/__init__.py[230].find_plugin: poll MODULE, class: 'LookupModule', package: ansible.plugins.lookup, mod_type: ''
plugins/__init__.py[242].find_plugin: poll MODULE find in class LookupModule so looking for suffix .py..
plugins/__init__.py[268].find_plugin: poll FIND class 'LookupModule' no paths left to search
plugins/__init__.py[334].find_plugin: poll module NOT FOUND
plugins/__init__.py[230].find_plugin: minimal MODULE, class: 'CallbackModule', package: ansible.plugins.callback, mod_type: ''
plugins/__init__.py[242].find_plugin: minimal MODULE find in class CallbackModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: minimal FIND class 'CallbackModule' searching paths: [u'~/src/ansible-callbacks', '~/src/ansible/lib/ansible/plugins/callback']
plugins/__init__.py[315].find_plugin: minimal MODULE cached path == ~/src/ansible/lib/ansible/plugins/callback/minimal.py
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: minimal, CallbackModule. ansible.plugins.callback
plugins/__init__.py[230].find_plugin: minimal MODULE, class: 'CallbackModule', package: ansible.plugins.callback, mod_type: ''
plugins/__init__.py[242].find_plugin: minimal MODULE find in class CallbackModule so looking for suffix .py..
plugins/__init__.py[255].find_plugin: minimal MODULE path ~/src/ansible/lib/ansible/plugins/callback/minimal.py
plugins/__init__.py[368].get: minimal MODULE is path ~/src/ansible/lib/ansible/plugins/callback/minimal.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/actionable.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/context_demo.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/debug.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/default.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/dense.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/foreman.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/hipchat.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible-callbacks/human_log-v2.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/jabber.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/json.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/junit.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/log_plays.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/logentries.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/logstash.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/mail.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/oneline.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/osx_say.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/profile_tasks.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/selective.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/skippy.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/slack.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/syslog_json.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/timer.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/callback/tree.py
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: linear, StrategyModule. ansible.plugins.strategy
plugins/__init__.py[230].find_plugin: linear MODULE, class: 'StrategyModule', package: ansible.plugins.strategy, mod_type: ''
plugins/__init__.py[242].find_plugin: linear MODULE find in class StrategyModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: linear FIND class 'StrategyModule' searching paths: ['~/src/ansible/lib/ansible/plugins/strategy', '~/src/ansible/lib/ansible/plugins/strategy/__pycache__']
plugins/__init__.py[315].find_plugin: linear MODULE cached path == ~/src/ansible/lib/ansible/plugins/strategy/linear.py
plugins/__init__.py[368].get: linear MODULE is path ~/src/ansible/lib/ansible/plugins/strategy/linear.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[230].find_plugin: meta MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[255].find_plugin: meta MODULE path ~/src/ansible/lib/ansible/modules/utilities/helper/meta.py
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: meta, ActionModule. ansible.plugins.action
plugins/__init__.py[230].find_plugin: meta MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: meta MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: meta FIND class 'ActionModule' searching paths: ['~/src/ansible/lib/ansible/plugins/action', '~/src/ansible/lib/ansible/plugins/action/__pycache__']
plugins/__init__.py[334].find_plugin: meta module NOT FOUND
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: setup, ActionModule. ansible.plugins.action
plugins/__init__.py[230].find_plugin: setup MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: setup MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[268].find_plugin: setup FIND class 'ActionModule' no paths left to search
plugins/__init__.py[334].find_plugin: setup module NOT FOUND
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: ssh, Connection. ansible.plugins.connection
plugins/__init__.py[230].find_plugin: ssh MODULE, class: 'Connection', package: ansible.plugins.connection, mod_type: ''
plugins/__init__.py[242].find_plugin: ssh MODULE find in class Connection so looking for suffix .py..
plugins/__init__.py[266].find_plugin: ssh FIND class 'Connection' searching paths: ['~/src/ansible/lib/ansible/plugins/connection']
plugins/__init__.py[315].find_plugin: ssh MODULE cached path == ~/src/ansible/lib/ansible/plugins/connection/ssh.py
plugins/__init__.py[368].get: ssh MODULE is path ~/src/ansible/lib/ansible/plugins/connection/ssh.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/shell/csh.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/shell/fish.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/shell/powershell.py
plugins/__init__.py[429].all: Loading module source: ~/src/ansible/lib/ansible/plugins/shell/sh.py
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: sh, ShellModule. ansible.plugins.shell
plugins/__init__.py[230].find_plugin: sh MODULE, class: 'ShellModule', package: ansible.plugins.shell, mod_type: ''
plugins/__init__.py[242].find_plugin: sh MODULE find in class ShellModule so looking for suffix .py..
plugins/__init__.py[266].find_plugin: sh FIND class 'ShellModule' searching paths: ['~/src/ansible/lib/ansible/plugins/shell']
plugins/__init__.py[315].find_plugin: sh MODULE cached path == ~/src/ansible/lib/ansible/plugins/shell/sh.py
plugins/__init__.py[368].get: sh MODULE is path ~/src/ansible/lib/ansible/plugins/shell/sh.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[230].find_plugin: setup MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: setup MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[268].find_plugin: setup FIND class 'ActionModule' no paths left to search
plugins/__init__.py[334].find_plugin: setup module NOT FOUND
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: smart, Connection. ansible.plugins.connection
plugins/__init__.py[230].find_plugin: smart MODULE, class: 'Connection', package: ansible.plugins.connection, mod_type: ''
plugins/__init__.py[242].find_plugin: smart MODULE find in class Connection so looking for suffix .py..
plugins/__init__.py[268].find_plugin: smart FIND class 'Connection' no paths left to search
plugins/__init__.py[334].find_plugin: smart module NOT FOUND
plugins/__init__.py[359].get: ---
plugins/__init__.py[360].get: normal, ActionModule. ansible.plugins.action
plugins/__init__.py[230].find_plugin: normal MODULE, class: 'ActionModule', package: ansible.plugins.action, mod_type: ''
plugins/__init__.py[242].find_plugin: normal MODULE find in class ActionModule so looking for suffix .py..
plugins/__init__.py[255].find_plugin: normal MODULE path ~/src/ansible/lib/ansible/plugins/action/normal.py
plugins/__init__.py[368].get: normal MODULE is path ~/src/ansible/lib/ansible/plugins/action/normal.py
plugins/__init__.py[369].get: ...
plugins/__init__.py[230].find_plugin: setup MODULE, class: '', package: ansible.modules, mod_type: ''
plugins/__init__.py[236].find_plugin: ALIAS EXISTS FOR setup -> gather_facts, BUT NOT USED because get() NOT CALLED
plugins/__init__.py[255].find_plugin: setup MODULE path ~/src/ansible-modules/ntc-ansible/setup.cfg
action/__init__.py[585]._execute_module: Using module file ~/src/ansible-modules/ntc-ansible/setup.cfg
127.0.0.1 | FAILED! => {
    "failed": true, 
    "msg": "module (setup) is missing interpreter line"
}

@bcoca
Copy link
Member

bcoca commented Jan 31, 2017

  • There is no namespace, all modules need to have unique names or they will be overridden
  • The directories are there for 'documentation classification' not for Ansible execution namespacing.
  • Modules currently don't have a requirement of executable permissions, this would be a backwards incompatible change, specially for custom modules.
  • Modules are not required to have .py (or .ps) and can be written in any language, we only require this of those shipped with Ansible.
  • Plugin loader loads most plugins, but not modules, it 'finds' them, we have plans on separating both functions in the future to clarify this.
  • meta and other 'special' modules are implemented either via action plugins or other ways, the module file is actually only needed for documentation in these cases.

@ansibot ansibot added the support:core This issue/PR relates to code supported by the Ansible Engineering Team. label Jun 29, 2017
@abadger abadger changed the title Module namespace conflicts "setup.py" in particular Non-module files in the module directory conflict with modules; "setup.py" in particular Jul 13, 2017
@abadger
Copy link
Contributor

abadger commented Jul 13, 2017

To apply bcoca's answer a little more to the question:

This is ansible working as designed. Any file in a module directory can
potentially override another module in a directory that is lower on the food
chain. The controller-side Ansible can't tell whether a file will execute
successfully on the remote machine so it can't make decisions about whether
it's valid or not.

So I assume that the basic idea is to have a git repository with an ansible
module in it. Then you want to get the ansible module in the git repo into
your ansible LIBRARY path so that the module can be used on your system. There
are many ways to accomplish that. here's the ones I can think of off the top
of my head:

(1) Only include modules in the git repo. Then checkout the repository into an existing LIBRARY directory. (Files that don't presently conflict with other modules won't usually cause problems but they have the potential to if a real module of that name is created in the future or if someone typos something by mistake)

(2) Update the checkout then run setup.py to install the module. I'm assuming that there's a setup.py so that the code can be installed via python setup.py install or pip install or similar. Just run that command to put the code into place.

(3) Have a subdirectory in the git repo that is only for the module files. Add the subdirectory holding the modules to the library path. Instead of using a single path in ANSIBLE_LIBRARY and placing the git checkout inside of that path, perform your git checkout to another location and then add the subdirectory of the checkout that holds the modules into ANSIBLE_LIBRARY.

(4) Use a symlink. Instead of adding the subdirectory to ANSIBLE_LIBRARY, symlink the subdirectory into the existing library path.

Although we can (and plan to in the future once we figure out how the naming will fit into the plans we have for enhancing the whole structure of facts) partially mitigate the problem for the specific case of the setup module, there's not really anything we can do to change the underlying requirement that only module files should live inside of hte module directory. I'll close this ticket now as the underlying technology here is working as expected.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.3 This issue/PR affects Ansible v2.3 bug This issue/PR relates to a bug. c:module_utils/facts module This issue/PR relates to a module. support:core This issue/PR relates to code supported by the Ansible Engineering Team.
Projects
None yet
Development

No branches or pull requests

6 participants