Home Python How to force Ansible to use a specific version of Python

How to force Ansible to use a specific version of Python

Because we want Ansible to be able to manage a wide range of machines, the ansible-core code works on both Python 2 and Python 3. Contributors to ansible-core and Ansible Collections should endeavor to write code that runs on the identical versions of Python as the rest of Ansible.

Forcing the Python version in Ansible inventory

Method 1

Which Python version should be used on the client can be specified to Ansible. The ansible_python_interpreter parameter can define a custom Python path/version that can be defined per client using the ansible_python_interpreter parameter.

ansible@ansibleserver:~$ grep -h sles15 inventory/*
sles15.local ansible_ssh_host=10.161.208.42 ansible_python_interpreter=/usr/bin/python3

The playbook is now running on the SLES 15 computer with Python 3 and has been completed successfully:

PLAY RECAP *****************************************************************************************
sles15.local    : ok=14   changed=6    unreachable=0    failed=0    skipped=24   rescued=0    ignored=0

Method 2

On the remote system, tell Ansible to use a specified Python interpreter version.

First, check the system for a remote operating system by running the following command:

$ lsb_release -a

On the remote system, there are Python interpreters. To validate the type present, run the following command:

$ ls -l /usr/bin/python*

Playbook and inventory for Ansible

python_interpreter_test_inventory.yml is an example of an inventory file for Ansible.

---
python_interpreter_test_default:
  hosts:
    debian10_python_default:
      ansible_host: 192.168.50.221
python_interpreter_test_defined:
  vars:
    ansible_python_interpreter: /usr/bin/python3
  hosts:
    debian10_python_group_defined:
      ansible_host: 192.168.50.221
    debian10_python_defined:
      ansible_host: 192.168.50.221
      ansible_python_interpreter: /usr/bin/python2
    debian10_python_auto:
      ansible_host: 192.168.50.221
      ansible_python_interpreter: auto
    debian10_python_auto_legacy:
      ansible_host: 192.168.50.221
      ansible_python_interpreter: auto_legacy

Create and test a Python interpreter

We’re using Ansible 2.9.2 with a change to the INTERPRETER PYTHON DISTRO MAP map in the lib/ansible/config/base.yml file (to support Debian 10) from default to python3 on Debian 10 #63097 merge request. Ansible 2.10 will be the first version to incorporate this update.

INTERPRETER_PYTHON:
  name: Python interpreter path (or automatic discovery behavior) used for module execution
  default: auto_legacy
  env: [{name: ANSIBLE_PYTHON_INTERPRETER}]
  ini:
  - {key: interpreter_python, section: defaults}
  vars:
  - {name: ansible_python_interpreter}
  version_added: "2.8"
  description:
  - Path to the Python interpreter to be used for module execution on remote targets, or an automatic discovery mode.
    Supported discovery modes are ``auto``, ``auto_silent``, and ``auto_legacy`` (the default). All discovery modes
    employ a lookup table to use the included system Python (on distributions known to include one), falling back to a
    fixed ordered list of well-known Python interpreter locations if a platform-specific default is not available. The
    fallback behavior will issue a warning that the interpreter should be set explicitly (since interpreters installed
    later may change which one is used). This warning behavior can be disabled by setting ``auto_silent``. 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.
INTERPRETER_PYTHON_DISTRO_MAP:
  name: Mapping of known included platform pythons for various Linux distros
  default:
    centos: &rhelish
      '6': /usr/bin/python
      '8': /usr/libexec/platform-python
    debian:
      '10': /usr/bin/python3
    fedora:
      '23': /usr/bin/python3
    redhat: *rhelish
    rhel: *rhelish
    ubuntu:
      '14': /usr/bin/python
      '16': /usr/bin/python3
  version_added: "2.8"
  # FUTURE: add inventory override once we're sure it can't be abused by a rogue target
  # FUTURE: add a platform layer to the map so we could use it for, e.g., freebsd/macos/etc.?
INTERPRETER_PYTHON_FALLBACK:
  name: Ordered list of Python interpreters to check for in discovery
  default:
  - /usr/bin/python
  - python3.7
  - python3.6
  - python3.5
  - python2.7
  - python2.6
  - /usr/libexec/platform-python
  - /usr/bin/python3
  - python
  # FUTURE: add inventory override once we're sure it can't be abused by a rogue target
  version_added: "2.8"

The default choice for ansible python interpreter has been auto legacy since Ansible 2.8, which implies it will favor /usr/bin/python (if it exists) above the found Python version. You can change it to auto, which will be the default in the future and will work in the opposite direction.

Use the auto_legacy_silent or auto_silent settings to disable the deprecation and fallback warnings. Also, set it to the path of a specific Python interpreter instead. Use the Ansible playbook mentioned earlier to demonstrate this.

$ ansible-playbook -i python_interpreter_test_inventory.yml python_interpreter_test_playbook.yml
PLAY [python_interpreter_test_default, python_interpreter_test_defined] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [debian10_python_default]
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_default] => {
    "ansible_python_interpreter": "VARIABLE IS NOT DEFINED!"
}
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_default] => {
    "ansible_python_version": "2.7.16"
}
PLAY [python_interpreter_test_default, python_interpreter_test_defined] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [debian10_python_defined]
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_defined] => {
    "ansible_python_interpreter": "/usr/bin/python2"
}
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_defined] => {
    "ansible_python_version": "2.7.16"
}
PLAY [python_interpreter_test_default, python_interpreter_test_defined] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [debian10_python_auto]
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_auto] => {
    "ansible_python_interpreter": "auto"
}
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_auto] => {
    "ansible_python_version": "3.7.3"
}
PLAY [python_interpreter_test_default, python_interpreter_test_defined] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [debian10_python_auto_legacy]
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_auto_legacy] => {
    "ansible_python_interpreter": "auto_legacy"
}
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_auto_legacy] => {
    "ansible_python_version": "2.7.16"
}
PLAY [python_interpreter_test_default, python_interpreter_test_defined] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [debian10_python_group_defined]
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_group_defined] => {
    "ansible_python_interpreter": "/usr/bin/python3"
}
TASK [debug] **********************************************************************************************************************************************************************
ok: [debian10_python_group_defined] => {
    "ansible_python_version": "3.7.3"
}
PLAY RECAP ************************************************************************************************************************************************************************
debian10_python_auto          : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
debian10_python_auto_legacy   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
debian10_python_default       : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
debian10_python_defined       : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
debian10_python_group_defined : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

That’s all there is to it.

Conclusion

Using a list or set of lists known as inventory, Ansible operates against numerous managed nodes or “hosts” in your infrastructure simultaneously. After defining your inventory, you’ll utilize patterns to choose which hosts or groups Ansible should execute against.

You may also like

Leave a Comment