diff --git a/changelogs/fragments/clear-distro-interp-map.yml b/changelogs/fragments/clear-distro-interp-map.yml new file mode 100644 index 00000000000..ae9242ed168 --- /dev/null +++ b/changelogs/fragments/clear-distro-interp-map.yml @@ -0,0 +1,2 @@ +minor_changes: +- Interpreter Discovery - Remove hardcoded references to specific python interpreters to use for certain distro versions, and modify logic for python3 to become the default. diff --git a/lib/ansible/config/base.yml b/lib/ansible/config/base.yml index 079cb55c0d7..9a5686dba91 100644 --- a/lib/ansible/config/base.yml +++ b/lib/ansible/config/base.yml @@ -1553,18 +1553,9 @@ INTERPRETER_PYTHON: _INTERPRETER_PYTHON_DISTRO_MAP: name: Mapping of known included platform pythons for various Linux distros default: - redhat: - '6': /usr/bin/python - '8': /usr/libexec/platform-python - '9': /usr/bin/python3 - debian: - '8': /usr/bin/python - '10': /usr/bin/python3 - fedora: - '23': /usr/bin/python3 - ubuntu: - '14': /usr/bin/python - '16': /usr/bin/python3 + # Entry only for testing + ansible test: + '99': /usr/bin/python99 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 for, eg, freebsd/macos/etc? @@ -1578,9 +1569,7 @@ INTERPRETER_PYTHON_FALLBACK: - python3.8 - python3.7 - /usr/bin/python3 - - /usr/libexec/platform-python - - /usr/bin/python - - python + - python3 vars: - name: ansible_interpreter_python_fallback type: list diff --git a/lib/ansible/executor/interpreter_discovery.py b/lib/ansible/executor/interpreter_discovery.py index deba1a5515f..6d105817b03 100644 --- a/lib/ansible/executor/interpreter_discovery.py +++ b/lib/ansible/executor/interpreter_discovery.py @@ -53,7 +53,7 @@ def discover_interpreter(action, interpreter_name, discovery_mode, task_vars): host = task_vars.get('inventory_hostname', 'unknown') res = None platform_type = 'unknown' - found_interpreters = [u'/usr/bin/python'] # fallback value + found_interpreters = [u'/usr/bin/python3'] # fallback value is_auto_legacy = discovery_mode.startswith('auto_legacy') is_silent = discovery_mode.endswith('_silent') @@ -89,7 +89,7 @@ def discover_interpreter(action, interpreter_name, discovery_mode, task_vars): action._discovery_warnings.append(u'No python interpreters found for ' u'host {0} (tried {1})'.format(host, bootstrap_python_list)) # this is lame, but returning None or throwing an exception is uglier - return u'/usr/bin/python' + return u'/usr/bin/python3' if platform_type != 'linux': raise NotImplementedError('unsupported platform for extended discovery: {0}'.format(to_native(platform_type))) @@ -106,7 +106,6 @@ def discover_interpreter(action, interpreter_name, discovery_mode, task_vars): platform_info = json.loads(res.get('stdout')) distro, version = _get_linux_distro(platform_info) - if not distro or not version: raise NotImplementedError('unable to get Linux distribution/version info') @@ -120,15 +119,15 @@ def discover_interpreter(action, interpreter_name, discovery_mode, task_vars): # provide a transition period for hosts that were using /usr/bin/python previously (but shouldn't have been) if is_auto_legacy: - if platform_interpreter != u'/usr/bin/python' and u'/usr/bin/python' in found_interpreters: + if platform_interpreter != u'/usr/bin/python3' and u'/usr/bin/python3' in found_interpreters: if not is_silent: action._discovery_warnings.append( u"Distribution {0} {1} on host {2} should use {3}, but is using " - u"/usr/bin/python for backward compatibility with prior Ansible releases. " + u"/usr/bin/python3 for backward compatibility with prior Ansible releases. " u"See {4} for more information" .format(distro, version, host, platform_interpreter, get_versioned_doclink('reference_appendices/interpreter_discovery.html'))) - return u'/usr/bin/python' + return u'/usr/bin/python3' if platform_interpreter not in found_interpreters: if platform_interpreter not in bootstrap_python_list: diff --git a/test/integration/targets/interpreter_discovery_python/tasks/main.yml b/test/integration/targets/interpreter_discovery_python/tasks/main.yml index 7e9b2e87a58..13c11d9363a 100644 --- a/test/integration/targets/interpreter_discovery_python/tasks/main.yml +++ b/test/integration/targets/interpreter_discovery_python/tasks/main.yml @@ -141,8 +141,6 @@ - name: debian assertions assert: that: - # Debian 8 and older - - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and distro_version is version('8', '<=') or distro_version is version('8', '>') # Debian 10 and newer - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' and distro_version is version('10', '>=') or distro_version is version('10', '<') when: distro == 'debian' @@ -150,27 +148,21 @@ - name: fedora assertions assert: that: - - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' + - "'/bin/python3' in auto_out.ansible_facts.discovered_interpreter_python" when: distro == 'fedora' and distro_version is version('23', '>=') - name: rhel assertions assert: that: - # rhel 6/7 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and distro_major_version is version('8','<')) or distro_major_version is version('8','>=') - # rhel 8 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/libexec/platform-python' and distro_major_version is version('8','==')) or distro_major_version is version('8','!=') # rhel 9 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' and distro_major_version is version('9','==')) or distro_major_version is version('9','!=') + - ('/bin/python3' in auto_out.ansible_facts.discovered_interpreter_python and distro_major_version is version('9','==')) or distro_major_version is version('9','!=') when: distro == 'redhat' - name: ubuntu assertions assert: that: - # ubuntu < 16 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and distro_version is version('16.04','<')) or distro_version is version('16.04','>=') # ubuntu >= 16 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' and distro_version is version('16.04','>=')) or distro_version is version('16.04','<') + - ('/bin/python3' in auto_out.ansible_facts.discovered_interpreter_python and distro_version is version('16.04','>=')) or distro_version is version('16.04','<') when: distro == 'ubuntu' - name: mac assertions diff --git a/test/units/executor/test_interpreter_discovery.py b/test/units/executor/test_interpreter_discovery.py index 35d0dacd104..876c779fc9b 100644 --- a/test/units/executor/test_interpreter_discovery.py +++ b/test/units/executor/test_interpreter_discovery.py @@ -12,63 +12,63 @@ from ansible.module_utils.common.text.converters import to_text from ansible.errors import AnsibleConnectionFailure mock_ubuntu_platform_res = to_text( - r'{"osrelease_content": "NAME=\"Ubuntu\"\nVERSION=\"16.04.5 LTS (Xenial Xerus)\"\nID=ubuntu\nID_LIKE=debian\n' - r'PRETTY_NAME=\"Ubuntu 16.04.5 LTS\"\nVERSION_ID=\"16.04\"\nHOME_URL=\"http://www.ubuntu.com/\"\n' - r'SUPPORT_URL=\"http://help.ubuntu.com/\"\nBUG_REPORT_URL=\"http://bugs.launchpad.net/ubuntu/\"\n' - r'VERSION_CODENAME=xenial\nUBUNTU_CODENAME=xenial\n", "platform_dist_result": ["Ubuntu", "16.04", "xenial"]}' + r'{"osrelease_content": "NAME=\"Ansible Test\"\nVERSION=\"100\"\nID=ansible-test\nID_LIKE=debian\n' + r'PRETTY_NAME=\"Ansible Test 100\"\nVERSION_ID=\"100\"\nHOME_URL=\"http://ansible.com/\"\n' + r'SUPPORT_URL=\"http://github.com/ansible/ansible\"\nBUG_REPORT_URL=\"http://github.com/ansible/ansible/\"\n' + r'VERSION_CODENAME=beans\nUBUNTU_CODENAME=beans\n", "platform_dist_result": ["Ansible Test", "100", "beans"]}' ) def test_discovery_interpreter_linux_auto_legacy(): - res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python\n/usr/bin/python3\nENDFOUND' + res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python99\n/usr/bin/python3\nENDFOUND' mock_action = MagicMock() mock_action._low_level_execute_command.side_effect = [{'stdout': res1}, {'stdout': mock_ubuntu_platform_res}] actual = discover_interpreter(mock_action, 'python', 'auto_legacy', {'inventory_hostname': u'host-fóöbär'}) - assert actual == u'/usr/bin/python' + assert actual == u'/usr/bin/python3' assert len(mock_action.method_calls) == 3 assert mock_action.method_calls[2][0] == '_discovery_warnings.append' - assert u'Distribution Ubuntu 16.04 on host host-fóöbär should use /usr/bin/python3, but is using /usr/bin/python' \ + assert u'Distribution Ansible Test 100 on host host-fóöbär should use /usr/bin/python99, but is using /usr/bin/python3' \ u' for backward compatibility' in mock_action.method_calls[2][1][0] def test_discovery_interpreter_linux_auto_legacy_silent(): - res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python\n/usr/bin/python3\nENDFOUND' + res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python3.9\n/usr/bin/python3\nENDFOUND' mock_action = MagicMock() mock_action._low_level_execute_command.side_effect = [{'stdout': res1}, {'stdout': mock_ubuntu_platform_res}] actual = discover_interpreter(mock_action, 'python', 'auto_legacy_silent', {'inventory_hostname': u'host-fóöbär'}) - assert actual == u'/usr/bin/python' + assert actual == u'/usr/bin/python3' assert len(mock_action.method_calls) == 2 def test_discovery_interpreter_linux_auto(): - res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python\n/usr/bin/python3\nENDFOUND' + res1 = u'PLATFORM\nLinux\nFOUND\n/usr/bin/python99\n/usr/bin/python3\nENDFOUND' mock_action = MagicMock() mock_action._low_level_execute_command.side_effect = [{'stdout': res1}, {'stdout': mock_ubuntu_platform_res}] actual = discover_interpreter(mock_action, 'python', 'auto', {'inventory_hostname': u'host-fóöbär'}) - assert actual == u'/usr/bin/python3' + assert actual == u'/usr/bin/python99' assert len(mock_action.method_calls) == 2 def test_discovery_interpreter_non_linux(): mock_action = MagicMock() mock_action._low_level_execute_command.return_value = \ - {'stdout': u'PLATFORM\nDarwin\nFOUND\n/usr/bin/python\nENDFOUND'} + {'stdout': u'PLATFORM\nDarwin\nFOUND\n/usr/bin/python3\nENDFOUND'} actual = discover_interpreter(mock_action, 'python', 'auto_legacy', {'inventory_hostname': u'host-fóöbär'}) - assert actual == u'/usr/bin/python' + assert actual == u'/usr/bin/python3' assert len(mock_action.method_calls) == 2 assert mock_action.method_calls[1][0] == '_discovery_warnings.append' - assert u'Platform darwin on host host-fóöbär is using the discovered Python interpreter at /usr/bin/python, ' \ + assert u'Platform darwin on host host-fóöbär is using the discovered Python interpreter at /usr/bin/python3, ' \ u'but future installation of another Python interpreter could change the meaning of that path' \ in mock_action.method_calls[1][1][0] @@ -79,7 +79,7 @@ def test_no_interpreters_found(): actual = discover_interpreter(mock_action, 'python', 'auto_legacy', {'inventory_hostname': u'host-fóöbär'}) - assert actual == u'/usr/bin/python' + assert actual == u'/usr/bin/python3' assert len(mock_action.method_calls) == 2 assert mock_action.method_calls[1][0] == '_discovery_warnings.append' assert u'No python interpreters found for host host-fóöbär (tried' \