Answers: <p>See:</p>
  <ul>
  <li><p><a href="https://stackoverflow.com/questions/61257164/ansible-is-using-wrong-version-of-python">Ansible is using the wrong version of Python</a></p>
  </li>
  <li><p><a href="https://stackoverflow.com/questions/58450608/how-can-i-specify-the-version-of-python-to-use-in-an-ansible-playbook">How can I specify the version of Python to use in an Ansible playbook?</a></p>
  </li>
  <li><p><a href="https://stackoverflow.com/questions/59380824/how-to-choose-a-python-interpreter-for-ansible-playbook">How to choose Python interpreter for Ansible playbook?</a></p>
  </li>
  </ul>
  <p>See also <a href="https://docs.ansible.com/ansible/latest/os_guide/intro_bsd.html#setting-the-python-interpreter" rel="nofollow noreferrer">Setting the Python interpreter</a> that explains various configurations' options, variables, and debugging.</p>
  <hr>
  <p>Q: <em><strong>&quot;None of that explains why - and that is/was my point - <strong>ansible_python wrongly claims to be running on Python 3.x on the local node</strong>. Because all I do by setting <strong>interpreter_python</strong> in ansible.cfg is to give Ansible free rein on how it interprets things.&quot;</strong></em></p>
  <p>Short answer: You can't configure the version of Python the Ansible utils use ($ ansible --version). <a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python" rel="nofollow noreferrer">INTERPRETER_PYTHON</a> configures the Python version used by the Ansible modules on the remote hosts.</p>
  <p>A: Configuration option INTERPRETER_PYTHON works as expected. There is nothing wrong when Python3 is discovered when asked by <code>interpreter_python=auto</code>.</p>
  <ul>
  <li><a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python" rel="nofollow noreferrer">auto</a> (default)</li>
  </ul>
  <p>See implementation details of the function <a href="https://github.com/ansible/ansible/blob/devel/lib/ansible/executor/interpreter_discovery.py" rel="nofollow noreferrer">discover_interpreter</a>. When the version of the distro is not in <a href="https://github.com/ansible/ansible/blob/devel/lib/ansible/config/base.yml" rel="nofollow noreferrer">_INTERPRETER_PYTHON_DISTRO_MAP</a></p>
  <blockquote>
  <p><em>&quot;return nearest previous version we're newer than&quot;</em></p>
  </blockquote>
  <pre class="lang-py prettyprint-override"><code>def _version_fuzzy_match(version, version_map):
  ...
      # slot match; return nearest previous version we're newer than
      kpos = bisect.bisect(sorted_looseversions, find_looseversion)
  </code></pre>
  <pre class="lang-ini prettyprint-override"><code>interpreter_python=auto
  </code></pre>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; ansible localhost -m setup -a 'filter=ansible_python_version'
  localhost | SUCCESS =&gt; {
      &quot;ansible_facts&quot;: {
          &quot;ansible_python_version&quot;: &quot;3.7.3&quot;, 
          &quot;discovered_interpreter_python&quot;: &quot;/usr/bin/python3&quot;
      }, 
      &quot;changed&quot;: false
  }
  </code></pre>
  <ul>
  <li><a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python" rel="nofollow noreferrer">auto_legacy</a> (default is <em>/usr/bin/python</em>)</li>
  </ul>
  <blockquote>
  <p><em>&quot;The default value of <strong>auto_legacy</strong> provides all the same behavior, but for backward compatibility with older Ansible releases that always defaulted to <strong>/usr/bin/python</strong>, will use that interpreter if present (and issue a warning that the default behavior will change to that of auto in a future Ansible release.&quot;</em></p>
  </blockquote>
  <pre class="lang-ini prettyprint-override"><code>interpreter_python=auto_legacy
  </code></pre>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; ansible localhost -m setup -a 'filter=ansible_python_version'
  [DEPRECATION WARNING]: Distribution Ubuntu 19.04 on host localhost should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future
   Ansible release will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more 
  information. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
  localhost | SUCCESS =&gt; {
      &quot;ansible_facts&quot;: {
          &quot;ansible_python_version&quot;: &quot;2.7.16&quot;, 
          &quot;discovered_interpreter_python&quot;: &quot;/usr/bin/python&quot;
      }, 
      &quot;changed&quot;: false
  }
  </code></pre>
  <p>See the notes and examples below.</p>
  <hr>
  <p>Q: <em><strong>&quot;What does the ansible command line tool have to do with the behavior I see with ansible-playbook?&quot;</strong></em></p>
  <p>A: Both ansible command line tool and ansible-playbook will report the same value of <em>ansible_python_version</em>. For example,</p>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; ansible localhost -m setup | grep ansible_python_version
          &quot;ansible_python_version&quot;: &quot;2.7.16&quot;,
  </code></pre>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; cat playbook.yml
  - hosts: localhost
    tasks:
      - debug:
          var: ansible_python_version
  </code></pre>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; ansible-playbook playbook.yml
  
  ok: [localhost] =&gt; {
      &quot;ansible_python_version&quot;: &quot;2.7.16&quot;
  }
  </code></pre>
  <hr>
  Notes
  <ol>
  <li><a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python" rel="nofollow noreferrer">INTERPRETER_PYTHON</a> configuration parameter says:</li>
  </ol>
  <blockquote>
  <p>Path to the Python interpreter to be used for module execution <strong>on remote targets</strong></p>
  </blockquote>
  <p>See <a href="https://stackoverflow.com/questions/59380824/how-to-choose-a-python-interpreter-for-ansible-playbook/">How to choose a python interpreter for Ansible playbook?</a></p>
  <ol start="2">
  <li>Ansible will tell what Python is used <strong>on master</strong></li>
  </ol>
  <pre class="lang-bash prettyprint-override"><code>shell&gt; ansible --version
  ansible 2.9.2
    config file = /home/vlado/.ansible.cfg
    configured module search path = [u'/home/vlado/.ansible/my_modules']
    ansible python module location = /usr/lib/python2.7/dist-packages/ansible
    executable location = /usr/bin/ansible
    python version = 2.7.16 (default, Oct  7 2019, 17:36:04) [GCC 8.3.0]
  </code></pre>
  <ol start="3">
  <li><a href="https://docs.ansible.com/ansible/latest/plugins/lookup/dig.html#dig-query-dns-using-the-dnspython-library" rel="nofollow noreferrer">dig</a> says</li>
  </ol>
  <blockquote>
  <p>The below requirements are needed <strong>on the local master node</strong> that executes this lookup: dnspython</p>
  </blockquote>
  <ol start="4">
  <li>It's possible to install both versions</li>
  </ol>
  <pre class="lang-bash prettyprint-override"><code>shell&gt; dpkg -l | grep dnspython
  ii  python-dnspython         1.16.0-1 all          DNS toolkit for Python
  ii  python3-dnspython        1.16.0-1 all          DNS toolkit for Python 3
  </code></pre>
  <ol start="5">
  <li><p>See <a href="https://packages.ubuntu.com/search?keywords=ansible" rel="nofollow noreferrer">Ansible packages in Ubuntu</a> what version of Python was used.</p>
  </li>
  <li><p><a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python" rel="nofollow noreferrer">ansible_python_interpreter</a> works as expected</p>
  </li>
  </ol>
  <p><strong>On master(Ubuntu) the playbook</strong></p>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; cat playbook.yml
  - hosts: test_01
    tasks:
      - getent:
          database: hosts
  </code></pre>
  <pre class="lang-ini prettyprint-override"><code>shell&gt; cat hosts
  test_01 ansible_python_interpreter=/usr/local/bin/python3.6
  </code></pre>
  <pre class="lang-yaml prettyprint-override"><code>shell&gt; ansible-playbook playbook.yml -i hosts -vvv | grep python
  </code></pre>
  <p>gives</p>
  <blockquote>
  <p>ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  <strong>python version = 2.7.16</strong> (default, Oct  7 2019, 17:36:04) [GCC 8.3.0]</p>
  </blockquote>
  <p>...</p>
  <blockquote>
  <p>&lt;test_01&gt; SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User=&quot;admin&quot;' -o ConnectTimeout=10 -o ControlPath=/export/home/vlado.config/.ansible/cp/5a3ab05cf7 -tt test_01 '/bin/sh -c '&quot;'&quot;'sudo -H -S -n  -u root /bin/sh -c '&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'echo BECOME-SUCCESS-xnvwkdksdqqoehvrgebdgcnrzcrmoszv ; <strong>/usr/local/bin/python3.6</strong> /home/admin/.ansible/tmp/ansible-tmp-1576667662.62-67468482045094/AnsiballZ_getent.py'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;' &amp;&amp; sleep 0'&quot;'&quot;''</p>
  </blockquote>
  <ul>
  <li>ansible-playbook <strong>on master</strong> runs with <code>python version = 2.7.16</code></li>
  <li>module <strong>on remote</strong> (test_01) runs with <code>/usr/local/bin/python3.6</code></li>
  </ul>
  <p><strong>Change ansible_python_interpreter</strong></p>
  <pre class="lang-ini prettyprint-override"><code>shell&gt; cat hosts
  test_01 ansible_python_interpreter=/usr/local/bin/python2.7
  </code></pre>
  <p>the same playbook gives</p>
  <blockquote>
  <p>ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  <strong>python version = 2.7.16</strong> (default, Oct  7 2019, 17:36:04) [GCC 8.3.0]</p>
  </blockquote>
  <p>...</p>
  <blockquote>
  <p>&lt;test_01&gt; SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User=&quot;admin&quot;' -o ConnectTimeout=10 -o ControlPath=/export/home/vlado.config/.ansible/cp/5a3ab05cf7 -tt test_01 '/bin/sh -c '&quot;'&quot;'sudo -H -S -n  -u root /bin/sh -c '&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'echo BECOME-SUCCESS-fidpgwptggdoizirumvjmzuorxqawypu ; <strong>/usr/local/bin/python2.7</strong> /home/admin/.ansible/tmp/ansible-tmp-1576668475.22-210929624017605/AnsiballZ_getent.py'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;'&quot;' &amp;&amp; sleep 0'&quot;'&quot;''</p>
  </blockquote>
  <ul>
  <li>ansible-playbook <strong>on master</strong> runs with <code>python version = 2.7.16</code></li>
  <li>but module <strong>on remote</strong> (test_01) runs with <code>/usr/local/bin/python2.7</code> as requested</li>
  </ul>
  
Answers: CC BY-SA 4.0
Answers: 2019-12-18T09:01:41.990Z
Answers: Yes, but _none_ of that explains why - and _that_ is/was my point - `ansible_python` wrongly claims to be running on Python 3.x on the _local node_. Because all I do by setting `interpreter_python` in `ansible.cfg` is to give Ansible free rein on how it interprets things. But since I am depending on its choices and its information being consistent (which it evidently isn't), things blow up in my face. Regarding point 4, it's completely beside the point, because I am attempting to install the appropriate version _based on_ `ansible_python`, but Ansible simply lies to me ...
Answers: 0xC0000022L
Answers: CC BY-SA 4.0
Answers: 2019-12-18T11:51:36.480Z
Answers: There is no evidence that *`ansible_python wrongly claims to be running on Python 3.x on the local node`*. I've added more details that might help to clarify the situation.
Answers: Vladimir Botka
Answers: CC BY-SA 4.0
Answers: 2019-12-18T13:19:04.433Z
Answers: The evidence is the behavior one gets _with_ `when:` ... the wrong package that gets installed (provided _neither_, i.e. `python-dnspython`/`python3-dnspython`, was installed before). This is actually reproducible. But you're right, this only happens with `interpreter_python=auto` set in `ansible.cfg` for me. But then I consistently see it (and I have actually used the `debug` module to verify the value of `ansible_python` is wrong). Only if `python-dnspython` is preinstalled (`samba` installs it, for example) don't I see the issue. Otherwise I can reproduce on all 18.04 so far.
Answers: 0xC0000022L
Answers: CC BY-SA 4.0
Answers: 2019-12-18T13:33:49.790Z
Answers: Just to make sure. I understand that the lookup plugins get called on the control/master. In my real-world case the `Preparing Ansible host` part is getting actually executed on the control/master, but the `Preparations` part gets executed on the remote machine(s). With the sole exception of the loopkup plugin, so I understand that the `dnspython` package needs to be installed on control/master and that the _result_ of the lookup is passed (by value) to the remote machine(s). In my MWE I had to condense this for obvious reasons.
Answers: 0xC0000022L
Answers: CC BY-SA 4.0
Answers: 2019-12-18T14:12:22.233Z
Answers: _A: Both ansible command line tool and ansible-playbook will report the same value of **ansible_python_version**._ ... unfortunately not true, at least not unconditionally (see amendments to the question).
Answers: 0xC0000022L
Answers: CC BY-SA 4.0
Answers: 2023-08-04T15:29:26.700Z
Answers: When executing "remotely" on the control host, Ansible uses the logic used for remote hosts when determining which Python to use for execution. The Python it was started with may not be the same.
Answers: reinierpost
Answers: CC BY-SA 4.0
Answers: 2023-08-07T10:07:40.283Z
Answers: @Vladimir Botka: This is where I ended up now. StackExchange questions and answers are supposed to be useful to anyone who finds them, so they must be kept up to date.
Answers: reinierpost
Answers: CC BY-SA 4.0
Answers: 2023-08-07T20:55:10.147Z
Answers: I updated the answer. Is there anything, in particular, you can't find?
Answers: Vladimir Botka
Answers: CC BY-SA 4.0
Answers: 2019-12-18T02:53:21.290Z
Answers: 2023-08-07T20:49:35.070Z
Answers: 2023-08-07T20:49:35.070Z
Answers: Vladimir Botka
Answers: <p>Since this confused the hell out of me and cost me about an hour to figure out, I am going to post an answer.</p>
  
  <p>As you can see I am using <code>ansible_python</code> to determine the Python version and install the appropriate version of <code>dnspython</code>. Since this is on Ubuntu 18.04 it defaults to <code>python3</code>. I am suppressing the respective warning with <code>interpreter_python=auto</code> in the <code>ansible.cfg</code> inside the same folder.</p>
  
  <p>But here's the bummer. Apparently <code>connection: local</code> somehow violates the rule about using <code>python3</code> whose <code>dnspython</code> package is installed. It made sense once I looked for <code>dig.py</code> (hoping for the <a href="https://docs.ansible.com/ansible/latest/plugins/lookup/dig.html" rel="nofollow noreferrer">Ansible lookup module of the same name</a>). And indeed I found it:</p>
  
  <pre><code>$ locate dig.py
  /usr/lib/python2.7/dist-packages/ansible/plugins/lookup/dig.py
  /usr/lib/python2.7/dist-packages/ansible/plugins/lookup/dig.pyc
  </code></pre>
  
  <p>... alas, this means my version of Ansible uses Python 2.7 and so the <code>dig</code> module won't be able to make use of the <code>python3-dnspython</code> (Debian) package which I installed.</p>
  
  <p>Still puzzling. But with the cause determined, I can work around it now.</p>
  
Answers: CC BY-SA 4.0
Answers: 2019-12-18T00:22:31.457Z
Answers: 2019-12-18T00:22:31.457Z
Answers: 0xC0000022L
Answers: <p>In ansible, <code>lookup</code>'s are <a href="https://docs.ansible.com/ansible/latest/plugins/lookup.html" rel="nofollow noreferrer">executed locally</a> where ansible runs, not on the target server.</p>
  <p>So you will have to ensure that <code>dnspython</code> is installed on your ansible machine.</p>
  
Answers: CC BY-SA 4.0
Answers: 2021-05-16T19:53:56.407Z
Answers: 2021-05-16T19:53:56.407Z
Answers: lifeofguenter
Body: <p>I am trying to look up the IPv4 address (a single one, which I will <code>assert</code> on!) for a given name using Ansible and use that as a fact "down the line".</p>
  
  <p>An MWE looks like this:</p>
  
  <pre><code>---
  # vim: set autoindent smartindent tabstop=2 shiftwidth=2 softtabstop=2 expandtab filetype=ansible:
  
  - name: Preparations
    hosts: localhost
    connection: local
    vars:
      host2lookup: "example.com"
    tasks:
      - getent:
          database: ahostsv4
          key: "{{host2lookup}}"
      - debug:
          var: getent_ahostsv4
      - name: Lookup for {{host2lookup}}
        debug:
          msg: "{{lookup('dig', '{{host2lookup}}./A')}}"
  </code></pre>
  
  <p>... and fails as follows (relevant excerpt):</p>
  
  <pre><code>  localhost failed | msg: An unhandled exception occurred while running the lookup plugin 'dig'. Error was a &lt;class 'ansible.errors.AnsibleError'&gt;, original message: The dig lookup requires the python 'dnspython' library and it is not installed
  </code></pre>
  
  <p>So I thought to myself I'd install the <code>dnspython</code> library for the appropriate Python version, making the playbook look as follows:</p>
  
  <pre><code>---
  # vim: set autoindent smartindent tabstop=2 shiftwidth=2 softtabstop=2 expandtab filetype=ansible:
  
  - name: Preparing Ansible host
    hosts: localhost
    connection: local
    tasks:
      - name: Install dnspython package on Ansible host
        block:
          - name: Installing python-dnspython package
            apt:
              pkg:
                - python-dnspython
              update_cache: yes
              install_recommends: no
              state: present
            when: ansible_python.version.major == 2
          - name: Installing python3-dnspython package
            apt:
              pkg:
                - python3-dnspython
              update_cache: yes
              install_recommends: no
              state: present
            when: ansible_python.version.major == 3
        become: true
  - name: Preparations
    hosts: localhost
    connection: local
    vars:
      host2lookup: "example.com"
    tasks:
      - getent:
          database: ahostsv4
          key: "{{host2lookup}}"
      - debug:
          var: getent_ahostsv4
      - name: Lookup for {{host2lookup}}
        debug:
          msg: "{{lookup('dig', '{{host2lookup}}./A')}}"
  </code></pre>
  
  <p>But the ultimate failure remains the same. Either that error is misleading or something else is fishy ...</p>
  
  <pre><code>Executing playbook dbg.yml
  
  - Preparing Ansible host on hosts: localhost -
  Gathering Facts...
    localhost ok
  Installing python-dnspython package...
  Installing python3-dnspython package...
    localhost ok
  
  - Preparations on hosts: localhost -
  Gathering Facts...
    localhost ok
  getent...
    localhost ok
  debug...
    localhost ok: {
      "changed": false,
      "getent_ahostsv4": {
          "93.184.216.34": [
              "RAW"
          ]
      }
  }
  Lookup for example.com...
    localhost failed | msg: An unhandled exception occurred while running the lookup plugin 'dig'. Error was a &lt;class 'ansible.errors.AnsibleError'&gt;, original message: The dig lookup requires the python 'dnspython' library and it is not installed
  
  - Play recap -
    localhost                  : ok=5    changed=0    unreachable=0    failed=1    rescued=0    ignored=0
  </code></pre>
  
  <p>What other than the appropriate <code>dnspython</code> package am I missing here?</p>
  
  <hr>
  
  <p>The <code>dnsutils</code> package (containing <code>dig</code>) and its library dependencies is installed. Adding these as prerequisites into the <code>apt:</code> task therefore makes no difference.</p>
  
  <p>Found another smoking gun, though:</p>
  
  <pre><code>$ python3 -m dnspython
  /usr/bin/python3: No module named dnspython
  $ sudo -H pip3 install dnspython
  Requirement already satisfied: dnspython in /usr/lib/python3/dist-packages
  </code></pre>
  
  <p>I stand corrected. As per the <a href="http://www.dnspython.org/examples.html" rel="nofollow noreferrer">examples page</a> I should import something like <code>dns.query</code> (<code>python3 -m dns.query</code>). And that succeeds.</p>
  
  <p>My <code>ansible.cfg</code> is this:</p>
  
  <pre><code>$ cat ansible.cfg
  [defaults]
  nocows = true
  command_warnings = false
  stdout_callback = unixy
  display_skipped_hosts = false
  interpreter_python=auto
  </code></pre>
  
  <p>The whole thing runs on Ubuntu 18.04.</p>
  
  <hr>
  
  <p>As per request in a comment, I am providing more output. This is still on Ubuntu 18.04. With the (above shown) <code>ansible.cfg</code> in place, I get the following output:</p>
  
  <pre><code>$ ansible localhost -m setup -a 'filter=ansible_python*'
  localhost | SUCCESS =&gt; {
      "ansible_facts": {
          "ansible_python": {
              "executable": "/usr/bin/python2",
              "has_sslcontext": true,
              "type": "CPython",
              "version": {
                  "major": 2,
                  "micro": 17,
                  "minor": 7,
                  "releaselevel": "final",
                  "serial": 0
              },
              "version_info": [
                  2,
                  7,
                  17,
                  "final",
                  0
              ]
          },
          "ansible_python_version": "2.7.17"
      },
      "changed": false
  }
  </code></pre>
  
  <p>However, <code>ansible-playbook</code> behaves differently here. Consider the following playbook:</p>
  
  <pre><code>---
  
  - hosts: all
    tasks:
      - debug:
          var: ansible_python
      - debug:
          var: ansible_python_version
  </code></pre>
  
  <p>The output becomes:</p>
  
  <pre><code>$ ansible-playbook -i localhost, -c local dbg.yml
  Executing playbook dbg.yml
  
  - all on hosts: all -
  Gathering Facts...
    localhost ok
  debug...
    localhost ok: {
      "ansible_python": {
          "executable": "/usr/bin/python3",
          "has_sslcontext": true,
          "type": "cpython",
          "version": {
              "major": 3,
              "micro": 9,
              "minor": 6,
              "releaselevel": "final",
              "serial": 0
          },
          "version_info": [
              3,
              6,
              9,
              "final",
              0
          ]
      },
      "changed": false
  }
  debug...
    localhost ok: {
      "ansible_python_version": "3.6.9",
      "changed": false
  }
  
  - Play recap -
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    rescued=0    ignored=0
  </code></pre>
  
  <p>... <strong>comment out the following line</strong> from <code>ansible.cfg</code>:</p>
  
  <pre><code>interpreter_python=auto
  </code></pre>
  
  <p>... and the output (when rerunning the previous command) becomes:</p>
  
  <pre><code>$ ansible-playbook -i localhost, -c local dbg.yml
  Executing playbook dbg.yml
  
  - all on hosts: all -
  Gathering Facts...
    localhost ok
  debug...
    localhost ok: {
      "ansible_python": {
          "executable": "/usr/bin/python",
          "has_sslcontext": true,
          "type": "CPython",
          "version": {
              "major": 2,
              "micro": 17,
              "minor": 7,
              "releaselevel": "final",
              "serial": 0
          },
          "version_info": [
              2,
              7,
              17,
              "final",
              0
          ]
      },
      "changed": false
  }
  debug...
    localhost ok: {
      "ansible_python_version": "2.7.17",
      "changed": false
  }
  
  - Play recap -
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    rescued=0    ignored=0
  </code></pre>
  
  <p>Nothing <a href="https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html" rel="nofollow noreferrer">in the documentation</a> suggests that this should happen.</p>
  
Comments: CC BY-SA 4.0
Comments: 2019-12-18T13:33:55.640Z
Comments: Update the question and add the output of the command `ansible localhost -m setup | grep ansible_python_version`
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2019-12-18T13:42:19.497Z
Comments: @VladimirBotka I _honestly_ appreciate your effort, but what does the `ansible` command line tool have to do with behavior I see with `ansible-playbook`? I will amend the question shortly. You'll notice that the two tools behave differently in this exact case. No clue why, but it can be reproduced.
Comments: 0xC0000022L
Comments: CC BY-SA 4.0
Comments: 2019-12-18T13:58:44.157Z
Comments: @VladimirBotka amended the question with requested information ... and a little more, since the information you requested isn't representative of the issue I am encountering.
Comments: 0xC0000022L
Comments: CC BY-SA 4.0
Comments: 2019-12-18T14:15:12.240Z
Comments: You did not amend the question with the requested information. I asked you to use `-hosts: localhost`, but you used `- hosts: all`. This is really `little more`.
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2019-12-18T14:23:19.333Z
Comments: @VladimirBotka Huh? Which part of `ansible localhost -m setup -a 'filter=ansible_python*'` (other than using a filter instead of `grep`) _lacks_ the requested information? Your request was for output from `ansible` and I pointed out the discrepancy with that of `ansible-playbook` based on the `interpreter_python=auto` setting.
Comments: 0xC0000022L
Tags: <ansible>
Title: Using `dig` Ansible module?
UserDisplayName: 0xC0000022L
ThreadText: # Using `dig` Ansible module?
  
  (Asked by: username_0 on 2019-12-18)
  
  I am trying to look up the IPv4 address (a single one, which I will `assert` on!) for a given name using Ansible and use that as a fact "down the line".
  
  An MWE looks like this:
  
  ```
  ---
  # vim: set autoindent smartindent tabstop=2 shiftwidth=2 softtabstop=2 expandtab filetype=ansible:
  
  - name: Preparations
    hosts: localhost
    connection: local
    vars:
      host2lookup: "example.com"
    tasks:
      - getent:
          database: ahostsv4
          key: "{{host2lookup}}"
      - debug:
          var: getent_ahostsv4
      - name: Lookup for {{host2lookup}}
        debug:
          msg: "{{lookup('dig', '{{host2lookup}}./A')}}"
  
  ```
  
  ... and fails as follows (relevant excerpt):
  
  ```
    localhost failed | msg: An unhandled exception occurred while running the lookup plugin 'dig'. Error was a <class 'ansible.errors.AnsibleError'>, original message: The dig lookup requires the python 'dnspython' library and it is not installed
  
  ```
  
  So I thought to myself I'd install the `dnspython` library for the appropriate Python version, making the playbook look as follows:
  
  ```
  ---
  # vim: set autoindent smartindent tabstop=2 shiftwidth=2 softtabstop=2 expandtab filetype=ansible:
  
  - name: Preparing Ansible host
    hosts: localhost
    connection: local
    tasks:
      - name: Install dnspython package on Ansible host
        block:
          - name: Installing python-dnspython package
            apt:
              pkg:
                - python-dnspython
              update_cache: yes
              install_recommends: no
              state: present
            when: ansible_python.version.major == 2
          - name: Installing python3-dnspython package
            apt:
              pkg:
                - python3-dnspython
              update_cache: yes
              install_recommends: no
              state: present
            when: ansible_python.version.major == 3
        become: true
  - name: Preparations
    hosts: localhost
    connection: local
    vars:
      host2lookup: "example.com"
    tasks:
      - getent:
          database: ahostsv4
          key: "{{host2lookup}}"
      - debug:
          var: getent_ahostsv4
      - name: Lookup for {{host2lookup}}
        debug:
          msg: "{{lookup('dig', '{{host2lookup}}./A')}}"
  
  ```
  
  But the ultimate failure remains the same. Either that error is misleading or something else is fishy ...
  
  ```
  Executing playbook dbg.yml
  
  - Preparing Ansible host on hosts: localhost -
  Gathering Facts...
    localhost ok
  Installing python-dnspython package...
  Installing python3-dnspython package...
    localhost ok
  
  - Preparations on hosts: localhost -
  Gathering Facts...
    localhost ok
  getent...
    localhost ok
  debug...
    localhost ok: {
      "changed": false,
      "getent_ahostsv4": {
          "93.184.216.34": [
              "RAW"
          ]
      }
  }
  Lookup for example.com...
    localhost failed | msg: An unhandled exception occurred while running the lookup plugin 'dig'. Error was a <class 'ansible.errors.AnsibleError'>, original message: The dig lookup requires the python 'dnspython' library and it is not installed
  
  - Play recap -
    localhost                  : ok=5    changed=0    unreachable=0    failed=1    rescued=0    ignored=0
  
  ```
  
  What other than the appropriate `dnspython` package am I missing here?
  
  ---
  
  The `dnsutils` package (containing `dig`) and its library dependencies is installed. Adding these as prerequisites into the `apt:` task therefore makes no difference.
  
  Found another smoking gun, though:
  
  ```
  $ python3 -m dnspython
  /usr/bin/python3: No module named dnspython
  $ sudo -H pip3 install dnspython
  Requirement already satisfied: dnspython in /usr/lib/python3/dist-packages
  
  ```
  
  I stand corrected. As per the [examples page](http://www.dnspython.org/examples.html) I should import something like `dns.query` (`python3 -m dns.query`). And that succeeds.
  
  My `ansible.cfg` is this:
  
  ```
  $ cat ansible.cfg
  [defaults]
  nocows = true
  command_warnings = false
  stdout_callback = unixy
  display_skipped_hosts = false
  interpreter_python=auto
  
  ```
  
  The whole thing runs on Ubuntu 18.04.
  
  ---
  
  As per request in a comment, I am providing more output. This is still on Ubuntu 18.04. With the (above shown) `ansible.cfg` in place, I get the following output:
  
  ```
  $ ansible localhost -m setup -a 'filter=ansible_python*'
  localhost | SUCCESS => {
      "ansible_facts": {
          "ansible_python": {
              "executable": "/usr/bin/python2",
              "has_sslcontext": true,
              "type": "CPython",
              "version": {
                  "major": 2,
                  "micro": 17,
                  "minor": 7,
                  "releaselevel": "final",
                  "serial": 0
              },
              "version_info": [
                  2,
                  7,
                  17,
                  "final",
                  0
              ]
          },
          "ansible_python_version": "2.7.17"
      },
      "changed": false
  }
  
  ```
  
  However, `ansible-playbook` behaves differently here. Consider the following playbook:
  
  ```
  ---
  
  - hosts: all
    tasks:
      - debug:
          var: ansible_python
      - debug:
          var: ansible_python_version
  
  ```
  
  The output becomes:
  
  ```
  $ ansible-playbook -i localhost, -c local dbg.yml
  Executing playbook dbg.yml
  
  - all on hosts: all -
  Gathering Facts...
    localhost ok
  debug...
    localhost ok: {
      "ansible_python": {
          "executable": "/usr/bin/python3",
          "has_sslcontext": true,
          "type": "cpython",
          "version": {
              "major": 3,
              "micro": 9,
              "minor": 6,
              "releaselevel": "final",
              "serial": 0
          },
          "version_info": [
              3,
              6,
              9,
              "final",
              0
          ]
      },
      "changed": false
  }
  debug...
    localhost ok: {
      "ansible_python_version": "3.6.9",
      "changed": false
  }
  
  - Play recap -
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    rescued=0    ignored=0
  
  ```
  
  ... **comment out the following line** from `ansible.cfg`:
  
  ```
  interpreter_python=auto
  
  ```
  
  ... and the output (when rerunning the previous command) becomes:
  
  ```
  $ ansible-playbook -i localhost, -c local dbg.yml
  Executing playbook dbg.yml
  
  - all on hosts: all -
  Gathering Facts...
    localhost ok
  debug...
    localhost ok: {
      "ansible_python": {
          "executable": "/usr/bin/python",
          "has_sslcontext": true,
          "type": "CPython",
          "version": {
              "major": 2,
              "micro": 17,
              "minor": 7,
              "releaselevel": "final",
              "serial": 0
          },
          "version_info": [
              2,
              7,
              17,
              "final",
              0
          ]
      },
      "changed": false
  }
  debug...
    localhost ok: {
      "ansible_python_version": "2.7.17",
      "changed": false
  }
  
  - Play recap -
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    rescued=0    ignored=0
  
  ```
  
  Nothing [in the documentation](https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html) suggests that this should happen.
  
  **Tags:** ansible
  
  > **Comments:**
  > **username_1**: Update the question and add the output of the command `ansible localhost -m setup | grep ansible_python_version`  
  > **username_0**: @username_1 I _honestly_ appreciate your effort, but what does the `ansible` command line tool have to do with behavior I see with `ansible-playbook`? I will amend the question shortly. You'll notice that the two tools behave differently in this exact case. No clue why, but it can be reproduced.  
  > **username_0**: @username_1 amended the question with requested information ... and a little more, since the information you requested isn't representative of the issue I am encountering.  
  > **username_1**: You did not amend the question with the requested information. I asked you to use `-hosts: localhost`, but you used `- hosts: all`. This is really `little more`.  
  > **username_0**: @username_1 Huh? Which part of `ansible localhost -m setup -a 'filter=ansible_python*'` (other than using a filter instead of `grep`) _lacks_ the requested information? Your request was for output from `ansible` and I pointed out the discrepancy with that of `ansible-playbook` based on the `interpreter_python=auto` setting.  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_1 on 2019-12-18. Score: 2 | Accepted answer
  
  See:
  
  * [Ansible is using the wrong version of Python](https://stackoverflow.com/questions/61257164/ansible-is-using-wrong-version-of-python)
  * [How can I specify the version of Python to use in an Ansible playbook?](https://stackoverflow.com/questions/58450608/how-can-i-specify-the-version-of-python-to-use-in-an-ansible-playbook)
  * [How to choose Python interpreter for Ansible playbook?](https://stackoverflow.com/questions/59380824/how-to-choose-a-python-interpreter-for-ansible-playbook)
  
  See also [Setting the Python interpreter](https://docs.ansible.com/ansible/latest/os_guide/intro_bsd.html#setting-the-python-interpreter) that explains various configurations' options, variables, and debugging.
  
  ---
  
  Q: ***"None of that explains why - and that is/was my point - **ansible\_python wrongly claims to be running on Python 3.x on the local node**. Because all I do by setting **interpreter\_python** in ansible.cfg is to give Ansible free rein on how it interprets things."***
  
  Short answer: You can't configure the version of Python the Ansible utils use ($ ansible --version). [INTERPRETER\_PYTHON](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python) configures the Python version used by the Ansible modules on the remote hosts.
  
  A: Configuration option INTERPRETER\_PYTHON works as expected. There is nothing wrong when Python3 is discovered when asked by `interpreter_python=auto`.
  
  * [auto](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python) (default)
  
  See implementation details of the function [discover\_interpreter](https://github.com/ansible/ansible/blob/devel/lib/ansible/executor/interpreter_discovery.py). When the version of the distro is not in [\_INTERPRETER\_PYTHON\_DISTRO\_MAP](https://github.com/ansible/ansible/blob/devel/lib/ansible/config/base.yml)
  
  > *"return nearest previous version we're newer than"*
  
  ```py
  def _version_fuzzy_match(version, version_map):
  ...
      # slot match; return nearest previous version we're newer than
      kpos = bisect.bisect(sorted_looseversions, find_looseversion)
  
  ```
  
  ```ini
  interpreter_python=auto
  
  ```
  
  ```yaml
  shell> ansible localhost -m setup -a 'filter=ansible_python_version'
  localhost | SUCCESS => {
      "ansible_facts": {
          "ansible_python_version": "3.7.3", 
          "discovered_interpreter_python": "/usr/bin/python3"
      }, 
      "changed": false
  }
  
  ```
  
  * [auto\_legacy](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python) (default is */usr/bin/python*)
  
  > *"The default value of **auto\_legacy** provides all the same behavior, but for backward compatibility with older Ansible releases that always defaulted to **/usr/bin/python**, will use that interpreter if present (and issue a warning that the default behavior will change to that of auto in a future Ansible release."*
  
  ```ini
  interpreter_python=auto_legacy
  
  ```
  
  ```yaml
  shell> ansible localhost -m setup -a 'filter=ansible_python_version'
  [DEPRECATION WARNING]: Distribution Ubuntu 19.04 on host localhost should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future
   Ansible release will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more 
  information. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
  localhost | SUCCESS => {
      "ansible_facts": {
          "ansible_python_version": "2.7.16", 
          "discovered_interpreter_python": "/usr/bin/python"
      }, 
      "changed": false
  }
  
  ```
  
  See the notes and examples below.
  
  ---
  
  Q: ***"What does the ansible command line tool have to do with the behavior I see with ansible-playbook?"***
  
  A: Both ansible command line tool and ansible-playbook will report the same value of *ansible\_python\_version*. For example,
  
  ```yaml
  shell> ansible localhost -m setup | grep ansible_python_version
          "ansible_python_version": "2.7.16",
  
  ```
  
  ```yaml
  shell> cat playbook.yml
  - hosts: localhost
    tasks:
      - debug:
          var: ansible_python_version
  
  ```
  
  ```yaml
  shell> ansible-playbook playbook.yml
  
  ok: [localhost] => {
      "ansible_python_version": "2.7.16"
  }
  
  ```
  
  ---
  
  Notes
  
  1. [INTERPRETER\_PYTHON](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python) configuration parameter says:
  
  > Path to the Python interpreter to be used for module execution **on remote targets**
  
  See [How to choose a python interpreter for Ansible playbook?](https://stackoverflow.com/questions/59380824/how-to-choose-a-python-interpreter-for-ansible-playbook/)
  
  2. Ansible will tell what Python is used **on master**
  
  ```bash
  shell> ansible --version
  ansible 2.9.2
    config file = /home/vlado/.ansible.cfg
    configured module search path = [u'/home/vlado/.ansible/my_modules']
    ansible python module location = /usr/lib/python2.7/dist-packages/ansible
    executable location = /usr/bin/ansible
    python version = 2.7.16 (default, Oct  7 2019, 17:36:04) [GCC 8.3.0]
  
  ```
  
  3. [dig](https://docs.ansible.com/ansible/latest/plugins/lookup/dig.html#dig-query-dns-using-the-dnspython-library) says
  
  > The below requirements are needed **on the local master node** that executes this lookup: dnspython
  
  4. It's possible to install both versions
  
  ```bash
  shell> dpkg -l | grep dnspython
  ii  python-dnspython         1.16.0-1 all          DNS toolkit for Python
  ii  python3-dnspython        1.16.0-1 all          DNS toolkit for Python 3
  
  ```
  
  5. See [Ansible packages in Ubuntu](https://packages.ubuntu.com/search?keywords=ansible) what version of Python was used.
  6. [ansible\_python\_interpreter](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#interpreter-python) works as expected
  
  **On master(Ubuntu) the playbook**
  
  ```yaml
  shell> cat playbook.yml
  - hosts: test_01
    tasks:
      - getent:
          database: hosts
  
  ```
  
  ```ini
  shell> cat hosts
  test_01 ansible_python_interpreter=/usr/local/bin/python3.6
  
  ```
  
  ```yaml
  shell> ansible-playbook playbook.yml -i hosts -vvv | grep python
  
  ```
  
  gives
  
  > ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  > **python version = 2.7.16** (default, Oct 7 2019, 17:36:04) [GCC 8.3.0]
  
  ...
  
  > <test\_01> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="admin"' -o ConnectTimeout=10 -o ControlPath=/export/home/vlado.config/.ansible/cp/5a3ab05cf7 -tt test\_01 '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-xnvwkdksdqqoehvrgebdgcnrzcrmoszv ; **/usr/local/bin/python3.6** /home/admin/.ansible/tmp/ansible-tmp-1576667662.62-67468482045094/AnsiballZ\_getent.py'"'"'"'"'"'"'"'"' && sleep 0'"'"''
  
  * ansible-playbook **on master** runs with `python version = 2.7.16`
  * module **on remote** (test\_01) runs with `/usr/local/bin/python3.6`
  
  **Change ansible\_python\_interpreter**
  
  ```ini
  shell> cat hosts
  test_01 ansible_python_interpreter=/usr/local/bin/python2.7
  
  ```
  
  the same playbook gives
  
  > ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  > **python version = 2.7.16** (default, Oct 7 2019, 17:36:04) [GCC 8.3.0]
  
  ...
  
  > <test\_01> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="admin"' -o ConnectTimeout=10 -o ControlPath=/export/home/vlado.config/.ansible/cp/5a3ab05cf7 -tt test\_01 '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-fidpgwptggdoizirumvjmzuorxqawypu ; **/usr/local/bin/python2.7** /home/admin/.ansible/tmp/ansible-tmp-1576668475.22-210929624017605/AnsiballZ\_getent.py'"'"'"'"'"'"'"'"' && sleep 0'"'"''
  
  * ansible-playbook **on master** runs with `python version = 2.7.16`
  * but module **on remote** (test\_01) runs with `/usr/local/bin/python2.7` as requested
  
  > **Comments:**
  > **username_0**: Yes, but _none_ of that explains why - and _that_ is/was my point - `ansible_python` wrongly claims to be running on Python 3.x on the _local node_. Because all I do by setting `interpreter_python` in `ansible.cfg` is to give Ansible free rein on how it interprets things. But since I am depending on its choices and its information being consistent (which it evidently isn't), things blow up in my face. Regarding point 4, it's completely beside the point, because I am attempting to install the appropriate version _based on_ `ansible_python`, but Ansible simply lies to me ...  
  > **username_1**: There is no evidence that *`ansible_python wrongly claims to be running on Python 3.x on the local node`*. I've added more details that might help to clarify the situation.  
  > **username_0**: The evidence is the behavior one gets _with_ `when:` ... the wrong package that gets installed (provided _neither_, i.e. `python-dnspython`/`python3-dnspython`, was installed before). This is actually reproducible. But you're right, this only happens with `interpreter_python=auto` set in `ansible.cfg` for me. But then I consistently see it (and I have actually used the `debug` module to verify the value of `ansible_python` is wrong). Only if `python-dnspython` is preinstalled (`samba` installs it, for example) don't I see the issue. Otherwise I can reproduce on all 18.04 so far.  
  > **username_0**: Just to make sure. I understand that the lookup plugins get called on the control/master. In my real-world case the `Preparing Ansible host` part is getting actually executed on the control/master, but the `Preparations` part gets executed on the remote machine(s). With the sole exception of the loopkup plugin, so I understand that the `dnspython` package needs to be installed on control/master and that the _result_ of the lookup is passed (by value) to the remote machine(s). In my MWE I had to condense this for obvious reasons.  
  > **username_0**: _A: Both ansible command line tool and ansible-playbook will report the same value of **ansible_python_version**._ ... unfortunately not true, at least not unconditionally (see amendments to the question).  
  > **username_2**: When executing "remotely" on the control host, Ansible uses the logic used for remote hosts when determining which Python to use for execution. The Python it was started with may not be the same.  
  > **username_2**: @username_1: This is where I ended up now. StackExchange questions and answers are supposed to be useful to anyone who finds them, so they must be kept up to date.  
  > **username_1**: I updated the answer. Is there anything, in particular, you can't find?  
  
  ---
  
  ### Answer by username_0 on 2019-12-18. Score: 1
  
  Since this confused the hell out of me and cost me about an hour to figure out, I am going to post an answer.
  
  As you can see I am using `ansible_python` to determine the Python version and install the appropriate version of `dnspython`. Since this is on Ubuntu 18.04 it defaults to `python3`. I am suppressing the respective warning with `interpreter_python=auto` in the `ansible.cfg` inside the same folder.
  
  But here's the bummer. Apparently `connection: local` somehow violates the rule about using `python3` whose `dnspython` package is installed. It made sense once I looked for `dig.py` (hoping for the [Ansible lookup module of the same name](https://docs.ansible.com/ansible/latest/plugins/lookup/dig.html)). And indeed I found it:
  
  ```
  $ locate dig.py
  /usr/lib/python2.7/dist-packages/ansible/plugins/lookup/dig.py
  /usr/lib/python2.7/dist-packages/ansible/plugins/lookup/dig.pyc
  
  ```
  
  ... alas, this means my version of Ansible uses Python 2.7 and so the `dig` module won't be able to make use of the `python3-dnspython` (Debian) package which I installed.
  
  Still puzzling. But with the cause determined, I can work around it now.
  
  
  ---
  
  ### Answer by username_3 on 2021-05-16. Score: 0
  
  In ansible, `lookup`'s are [executed locally](https://docs.ansible.com/ansible/latest/plugins/lookup.html) where ansible runs, not on the target server.
  
  So you will have to ensure that `dnspython` is installed on your ansible machine.
  
  
  ---
  
  