<p dir="auto">The Ansible documentation for modules does not distinguish between modules that are pure modules and modules that have both a plugin and a module part.</p>
<p dir="auto">After the new rewrite of the internals, where eg. plugins are derived from a base clase rather than being associated with a runner object, the situation can be confusing.</p>
<p dir="auto">An action plugin will be derived from ActionBase, which has the function _execute_module().</p>
<p dir="auto">This method will only call the module part of a "module" (terminology could be better), but not invoke the plugin part of the same.</p>
<p dir="auto">This affects a few plugins. For example the unarchive plugin has a parameter called "copy=yes/no" to transfer files to a remote.</p>
<p dir="auto">But copying files to a remote is in the plugin part, not in the module part.</p>
<p dir="auto">So when this runs in a playbook it will do what the user is expecting, but when invoked from a plugin it won't and would fail with "file failed to transfer". This means code already present in unarchive have to be duplicated into the new plugin to action that part, which is illogical and frustrating.</p>
<p dir="auto">Worse, there is also an issue with a much more basic module - the "stat" plugin.</p>
<p dir="auto">The "stat" plugin has a parameter called "follow=yes/no" to follow symbolic links.</p>
<p dir="auto">Again, the logic for that is in module_utils/basic.py, which does not get invoked from a plugin so that particular (and perhaps other parameters) do not function correctly within a plugin context.</p>
<p dir="auto">In V1 this was solveable, because V1 had two different ways of executing a module. The same as exists now in V2, but there was also a self.runner._executor_internal_inner() which would invoke a module as a plugin, not as a pure remote module. This is now absent in V2 and I have not figured out how to work around that for now.</p>
<p dir="auto">To conclude, if it is meant to be possible to program plugins for Ansible, then it needs to be clear from a developer perspective what functionality exists in a module which can be invoked from a plugin (this means the documentation needs to state parameters that won't have any effect when running _execute_module()) or there must be another function within eg. ActionBase to invoke other plugins (or some other documented way).</p>
<p dir="auto">Keeping as it is now creates troubleshooting frustration and API paranoia: "will it do what it says it should or not?"</p>
<p dir="auto"><em>From <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sdubrul/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sdubrul">@sdubrul</a> on December 8, 2016 10:49</em></p>
<h5 dir="auto">ISSUE TYPE</h5>

<ul dir="auto">
<li>Bug Report</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>
<p dir="auto">os_security_group_rule</p>
<h5 dir="auto">ANSIBLE VERSION</h5>

<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ansible 2.2.0.0"><pre class="notranslate"><code class="notranslate">ansible 2.2.0.0
</code></pre></div>
<h5 dir="auto">CONFIGURATION</h5>

<p dir="auto">N/A</p>
<h5 dir="auto">OS / ENVIRONMENT</h5>
<p dir="auto">macOS 10.12.1</p>
<h5 dir="auto">SUMMARY</h5>

<p dir="auto">When logged in as admin and trying to update the default security group rules for this tenant the command fails as there are multiple security groups that are called default. Security group default is found in the admin and services tenant.</p>
<h5 dir="auto">STEPS TO REPRODUCE</h5>


<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# clouds.yml
clouds:
  mycloud:
    auth:
      auth_url: https://mycloud:5000/v2.0
      username: admin
      password: password
      project_name: admin


# task in playbook.yml
    - name: update default security group to allow ssh
      os_security_group_rule:
        cloud: mycloud
        security_group: default
        protocol: tcp
        direction: ingress
        remote_ip_prefix: 0.0.0.0/0
        port_range_min: 22
        port_range_max: 22
"><pre class="notranslate"><code class="notranslate"># clouds.yml
clouds:
  mycloud:
    auth:
      auth_url: https://mycloud:5000/v2.0
      username: admin
      password: password
      project_name: admin


# task in playbook.yml
    - name: update default security group to allow ssh
      os_security_group_rule:
        cloud: mycloud
        security_group: default
        protocol: tcp
        direction: ingress
        remote_ip_prefix: 0.0.0.0/0
        port_range_min: 22
        port_range_max: 22

</code></pre></div>

<h5 dir="auto">EXPECTED RESULTS</h5>

<p dir="auto">Expecting the command to update the admin tenant default security group as project name is defined in clouds.yml .</p>
<h5 dir="auto">ACTUAL RESULTS</h5>

<p dir="auto">Task fails with:</p>

<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="fatal: [server]: FAILED! =&gt; {&quot;changed&quot;: false, &quot;failed&quot;: true, &quot;msg&quot;: &quot;Multiple matches found for default&quot;}"><pre class="notranslate"><code class="notranslate">fatal: [server]: FAILED! =&gt; {"changed": false, "failed": true, "msg": "Multiple matches found for default"}
</code></pre></div>
<p dir="auto"><em>Copied from original issue: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="194303953" data-permission-text="Title is private" data-url="https://github.com/ansible/ansible-modules-core/issues/5862" data-hovercard-type="issue" data-hovercard-url="/ansible/ansible-modules-core/issues/5862/hovercard" href="https://github.com/ansible/ansible-modules-core/issues/5862">ansible/ansible-modules-core#5862</a></em></p>