<h5 dir="auto">ISSUE TYPE</h5>
<ul dir="auto">
<li>Feature Idea</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>
<p dir="auto">Windows</p>
<h5 dir="auto">ANSIBLE VERSION</h5>
<p dir="auto">v2.5</p>
<h5 dir="auto">SUMMARY</h5>
<p dir="auto">Much like sudo on Unix, it would be nice to be able to run modules as any user (from an Administrator account) without the need to use passwords (which you may not know). When managing multi-user systems this is a necessity in order to manage configuration items of user environments.</p>
<p dir="auto">This is a continuation of <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="284359437" data-permission-text="Title is private" data-url="https://github.com/ansible/ansible/issues/34214" data-hovercard-type="issue" data-hovercard-url="/ansible/ansible/issues/34214/hovercard" href="https://github.com/ansible/ansible/issues/34214">#34214</a></p>
<h5 dir="auto">ISSUE TYPE</h5>
<ul dir="auto">
<li>Bug Report</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>
<p dir="auto">core</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.0.0
  config file = 
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118]"><pre class="notranslate"><code class="notranslate">ansible 2.3.0.0
  config file = 
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118]
</code></pre></div>
<h5 dir="auto">CONFIGURATION</h5>
<p dir="auto">N/A</p>
<h5 dir="auto">OS / ENVIRONMENT</h5>
<p dir="auto">N/A</p>
<h5 dir="auto">SUMMARY</h5>
<p dir="auto">Ansible 2.3 shows failures like</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {&quot;failed&quot;: true, &quot;msg&quot;: &quot;the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n&quot;}
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {&quot;failed&quot;: true, &quot;msg&quot;: &quot;the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n&quot;}"><pre class="notranslate"><code class="notranslate">fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n"}
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n"}
</code></pre></div>
<p dir="auto">for a playbook that worked fine in 2.2.  This happens only when the host in question is duplicated in the inventory.</p>
<p dir="auto">The playbook itself looks like this:</p>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="---
- name: user accounts for sysadmins
  user: name={{ item }} state=present
  with_items: &quot;{{ admin_users }}&quot;

# two tasks skipped here for conciseness:
# - name: authorized keys for sysadmins
# - name: sudo rights for sysadmins

- name: list user accounts
  command: &quot;awk -F: '$3 &gt;\\= 1000 &amp;&amp; $3 &lt; 65534 { print $1 }' /etc/passwd&quot;
  register: list_users_result
  check_mode: no
  changed_when: false

- name: prepare a list of expected user accounts
  set_fact:
    actual_accounts: &quot;{{ list_users_result.stdout_lines|sort }}&quot;
    expected_accounts: &quot;{{ admin_users|sort }}&quot;

- name: compare the account lists
  set_fact:
    unexpected_accounts: &quot;{{ actual_accounts|difference(expected_accounts) }}&quot;
    missing_accounts: &quot;{{ expected_accounts|difference(actual_accounts) }}&quot;

- name: show unexpected accounts
  debug: var=unexpected_accounts
  when: unexpected_accounts

- name: show missing accounts
  debug: var=missing_accounts
  when: missing_accounts

- name: check user accounts
  assert:
    that: &quot;expected_accounts == actual_accounts&quot;"><pre class="notranslate">---
- <span class="pl-ent">name</span>: <span class="pl-s">user accounts for sysadmins</span>
  <span class="pl-ent">user</span>: <span class="pl-s">name={{ item }} state=present</span>
  <span class="pl-ent">with_items</span>: <span class="pl-s"><span class="pl-pds">"</span>{{ admin_users }}<span class="pl-pds">"</span></span>

<span class="pl-c"><span class="pl-c">#</span> two tasks skipped here for conciseness:</span>
<span class="pl-c"><span class="pl-c">#</span> - name: authorized keys for sysadmins</span>
<span class="pl-c"><span class="pl-c">#</span> - name: sudo rights for sysadmins</span>

- <span class="pl-ent">name</span>: <span class="pl-s">list user accounts</span>
  <span class="pl-ent">command</span>: <span class="pl-s"><span class="pl-pds">"</span>awk -F: '$3 &gt;<span class="pl-cce">\\</span>= 1000 &amp;&amp; $3 &lt; 65534 { print $1 }' /etc/passwd<span class="pl-pds">"</span></span>
  <span class="pl-ent">register</span>: <span class="pl-s">list_users_result</span>
  <span class="pl-ent">check_mode</span>: <span class="pl-s">no</span>
  <span class="pl-ent">changed_when</span>: <span class="pl-c1">false</span>

- <span class="pl-ent">name</span>: <span class="pl-s">prepare a list of expected user accounts</span>
  <span class="pl-ent">set_fact</span>:
    <span class="pl-ent">actual_accounts</span>: <span class="pl-s"><span class="pl-pds">"</span>{{ list_users_result.stdout_lines|sort }}<span class="pl-pds">"</span></span>
    <span class="pl-ent">expected_accounts</span>: <span class="pl-s"><span class="pl-pds">"</span>{{ admin_users|sort }}<span class="pl-pds">"</span></span>

- <span class="pl-ent">name</span>: <span class="pl-s">compare the account lists</span>
  <span class="pl-ent">set_fact</span>:
    <span class="pl-ent">unexpected_accounts</span>: <span class="pl-s"><span class="pl-pds">"</span>{{ actual_accounts|difference(expected_accounts) }}<span class="pl-pds">"</span></span>
    <span class="pl-ent">missing_accounts</span>: <span class="pl-s"><span class="pl-pds">"</span>{{ expected_accounts|difference(actual_accounts) }}<span class="pl-pds">"</span></span>

- <span class="pl-ent">name</span>: <span class="pl-s">show unexpected accounts</span>
  <span class="pl-ent">debug</span>: <span class="pl-s">var=unexpected_accounts</span>
  <span class="pl-ent">when</span>: <span class="pl-s">unexpected_accounts</span>

- <span class="pl-ent">name</span>: <span class="pl-s">show missing accounts</span>
  <span class="pl-ent">debug</span>: <span class="pl-s">var=missing_accounts</span>
  <span class="pl-ent">when</span>: <span class="pl-s">missing_accounts</span>

- <span class="pl-ent">name</span>: <span class="pl-s">check user accounts</span>
  <span class="pl-ent">assert</span>:
    <span class="pl-ent">that</span>: <span class="pl-s"><span class="pl-pds">"</span>expected_accounts == actual_accounts<span class="pl-pds">"</span></span></pre></div>
<p dir="auto">You can see that the variable Ansible claims is undefined (<code class="notranslate">actual_accounts</code>) is defined by a <code class="notranslate">set_fact</code> task before it is used.</p>
<p dir="auto">A curious thing is that the error shows up while executing an earlier task:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="PLAY [all] *********************************************************************

TASK [users : user accounts for sysadmins] *************************************
...
TASK [users : authorized keys for sysadmins] ***********************************
...
TASK [users : sudo rights for sysadmins] ***************************************
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {&quot;failed&quot;: true, &quot;msg&quot;: &quot;the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n&quot;}
...
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {&quot;failed&quot;: true, &quot;msg&quot;: &quot;the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n&quot;}
.."><pre class="notranslate"><code class="notranslate">PLAY [all] *********************************************************************

TASK [users : user accounts for sysadmins] *************************************
...
TASK [users : authorized keys for sysadmins] ***********************************
...
TASK [users : sudo rights for sysadmins] ***************************************
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n"}
...
fatal: [bolagsfakta-debian.pov.lt]: FAILED! =&gt; {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'actual_accounts' is undefined\n\nThe error appears to have been in '/home/mg/src/tilaajavastuu/bolagsfakta/deployment/roles/users/tasks/main.yml': line 38, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: compare the account lists\n  ^ here\n"}
..
</code></pre></div>
<p dir="auto">It is also noteworthy that each task shows it is being executed on <code class="notranslate">bolagsfakta-debian.pov.lt</code> twice.</p>
<p dir="auto">Now, why do I have the host twice in my inventory and why can't I remove one of the copies?  This gets complicated:</p>
<ul dir="auto">
<li>there are several environments (dev, test, prod)</li>
<li>every developer can run ansible on the <code class="notranslate">dev</code> environment, but only some ops people have access to <code class="notranslate">prod</code></li>
<li>there's a vault file with encrypted secrets needed for <code class="notranslate">prod</code>, but developers don't know the password</li>
<li>to allow developers use ansible we must let them run with an inventory file that doesn't include the hosts/groups that have the encrypted vault file under group_vars/prod</li>
<li>ops people want to run ansible (usually in check mode) over all the environments in one run</li>
</ul>
<p dir="auto">The solution we came up with was to create a directory <code class="notranslate">env</code> with one inventory file per environment.<br>
This way developers can run <code class="notranslate">ansible-playbook -i env/dev playbook.yml</code> and do their deployments.<br>
Ops people can run things like <code class="notranslate">ansible-playbook -i env/prod --ask-vault-password playbook.yml</code> to deploy to one environment, or <code class="notranslate">ansible-playbook -i env --ask-vault-password playbook.yml -C</code> to compare the playbook with reality across all the environments in one go.</p>
<p dir="auto">The <code class="notranslate">bolagsfakta-debian</code> host needs to be defined both in <code class="notranslate">env/dev</code> and in <code class="notranslate">env/prod</code>, because both need to delegate some tasks to it.  This leads to duplication when using <code class="notranslate">ansible-playbook -i env</code>, which resulted in this bug report.</p>
<h5 dir="auto">STEPS TO REPRODUCE</h5>
<ul dir="auto">
<li>mention a host twice in the inventory</li>
<li>define a variable using <code class="notranslate">set_fact</code></li>
<li>use that variable in the following task</li>
</ul>