Merge pull request #1095 from moreati/ansible-2.17

Ansible 10 support
pull/1098/head
Alex Willmer 4 months ago committed by GitHub
commit 022f0c4b5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,7 +4,7 @@ import ci_lib
batches = [ batches = [
[ [
'aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws', 'if [ "${TF_BUILD:-false}" = "True" ]; then aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws; fi',
] ]
] ]

@ -32,10 +32,14 @@ jobs:
tox.env: py312-mode_localhost-ansible9 tox.env: py312-mode_localhost-ansible9
Van_312_9: Van_312_9:
tox.env: py312-mode_localhost-ansible9-strategy_linear tox.env: py312-mode_localhost-ansible9-strategy_linear
Loc_312_10:
tox.env: py312-mode_localhost-ansible10
Van_312_10:
tox.env: py312-mode_localhost-ansible10-strategy_linear
- job: Linux - job: Linux
pool: pool:
# https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md # https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2004-Readme.md
vmImage: ubuntu-20.04 vmImage: ubuntu-20.04
steps: steps:
- template: azure-pipelines-steps.yml - template: azure-pipelines-steps.yml
@ -152,3 +156,6 @@ jobs:
Ans_312_9: Ans_312_9:
python.version: '3.12' python.version: '3.12'
tox.env: py312-mode_ansible-ansible9 tox.env: py312-mode_ansible-ansible9
Ans_312_10:
python.version: '3.12'
tox.env: py312-mode_ansible-ansible10

@ -10,7 +10,7 @@ ci_lib.run_batches([
'python -m pip --no-python-version-warning --disable-pip-version-check "debops[ansible]==2.1.2"', 'python -m pip --no-python-version-warning --disable-pip-version-check "debops[ansible]==2.1.2"',
], ],
[ [
'aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws', 'if [ "${TF_BUILD:-false}" = "True" ]; then aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws; fi',
], ],
]) ])

@ -7,7 +7,7 @@ batches = [
if ci_lib.have_docker(): if ci_lib.have_docker():
batches.append([ batches.append([
'aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws', 'if [ "${TF_BUILD:-false}" = "True" ]; then aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws; fi',
]) ])

@ -4,7 +4,7 @@ import ci_lib
batches = [ batches = [
[ [
'aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws', 'if [ "${TF_BUILD:-false}" = "True" ]; then aws ecr-public get-login-password | docker login --username AWS --password-stdin public.ecr.aws; fi',
], ],
[ [
'curl https://dw.github.io/mitogen/binaries/ubuntu-python-2.4.6.tar.bz2 | sudo tar -C / -jxv', 'curl https://dw.github.io/mitogen/binaries/ubuntu-python-2.4.6.tar.bz2 | sudo tar -C / -jxv',

@ -49,7 +49,7 @@ __all__ = [
ANSIBLE_VERSION_MIN = (2, 10) ANSIBLE_VERSION_MIN = (2, 10)
ANSIBLE_VERSION_MAX = (2, 16) ANSIBLE_VERSION_MAX = (2, 17)
NEW_VERSION_MSG = ( NEW_VERSION_MSG = (
"Your Ansible version (%s) is too recent. The most recent version\n" "Your Ansible version (%s) is too recent. The most recent version\n"

@ -357,7 +357,9 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase):
def _execute_module(self, module_name=None, module_args=None, tmp=None, def _execute_module(self, module_name=None, module_args=None, tmp=None,
task_vars=None, persist_files=False, task_vars=None, persist_files=False,
delete_remote_tmp=True, wrap_async=False): delete_remote_tmp=True, wrap_async=False,
ignore_unknown_opts=False,
):
""" """
Collect up a module's execution environment then use it to invoke Collect up a module's execution environment then use it to invoke
target.run_module() or helpers.run_module_async() in the target target.run_module() or helpers.run_module_async() in the target
@ -370,6 +372,12 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase):
if task_vars is None: if task_vars is None:
task_vars = {} task_vars = {}
if ansible_mitogen.utils.ansible_version[:2] >= (2, 17):
self._update_module_args(
module_name, module_args, task_vars,
ignore_unknown_opts=ignore_unknown_opts,
)
else:
self._update_module_args(module_name, module_args, task_vars) self._update_module_args(module_name, module_args, task_vars)
env = {} env = {}
self._compute_environment_string(env) self._compute_environment_string(env)

@ -54,6 +54,7 @@ import mitogen.select
import ansible_mitogen.loaders import ansible_mitogen.loaders
import ansible_mitogen.parsing import ansible_mitogen.parsing
import ansible_mitogen.target import ansible_mitogen.target
import ansible_mitogen.utils.unsafe
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -215,12 +216,15 @@ class ScriptPlanner(BinaryPlanner):
""" """
def _rewrite_interpreter(self, path): def _rewrite_interpreter(self, path):
""" """
Given the original interpreter binary extracted from the script's Given the interpreter path (from the script's hashbang line), return
interpreter line, look up the associated `ansible_*_interpreter` the desired interpreter path. This tries, in order
variable, render it and return it.
1. Look up & render the `ansible_*_interpreter` variable, if set
2. Look up the `discovered_interpreter_*` fact, if present
3. The unmodified path from the hashbang line.
:param str path: :param str path:
Absolute UNIX path to original interpreter. Absolute path to original interpreter (e.g. '/usr/bin/python').
:returns: :returns:
Shell fragment prefix used to execute the script via "/bin/sh -c". Shell fragment prefix used to execute the script via "/bin/sh -c".
@ -228,13 +232,25 @@ class ScriptPlanner(BinaryPlanner):
involved here, the vanilla implementation uses it and that use is involved here, the vanilla implementation uses it and that use is
exploited in common playbooks. exploited in common playbooks.
""" """
key = u'ansible_%s_interpreter' % os.path.basename(path).strip() interpreter_name = os.path.basename(path).strip()
key = u'ansible_%s_interpreter' % interpreter_name
try: try:
template = self._inv.task_vars[key] template = self._inv.task_vars[key]
except KeyError: except KeyError:
return path pass
else:
configured_interpreter = self._inv.templar.template(template)
return ansible_mitogen.utils.unsafe.cast(configured_interpreter)
key = u'discovered_interpreter_%s' % interpreter_name
try:
discovered_interpreter = self._inv.task_vars['ansible_facts'][key]
except KeyError:
pass
else:
return ansible_mitogen.utils.unsafe.cast(discovered_interpreter)
return mitogen.utils.cast(self._inv.templar.template(template)) return path
def _get_interpreter(self): def _get_interpreter(self):
path, arg = ansible_mitogen.parsing.parse_hashbang( path, arg = ansible_mitogen.parsing.parse_hashbang(
@ -249,7 +265,8 @@ class ScriptPlanner(BinaryPlanner):
if arg: if arg:
fragment += ' ' + arg fragment += ' ' + arg
return fragment, path.startswith('python') is_python = path.startswith('python')
return fragment, is_python
def get_kwargs(self, **kwargs): def get_kwargs(self, **kwargs):
interpreter_fragment, is_python = self._get_interpreter() interpreter_fragment, is_python = self._get_interpreter()

@ -165,7 +165,9 @@ Noteworthy Differences
+-----------------+-----------------+ +-----------------+-----------------+
| 8 | 3.9 - 3.12 | | 8 | 3.9 - 3.12 |
+-----------------+-----------------+ +-----------------+-----------------+
| 9 | 3.10 - 3.12 | | 9 | |
+-----------------+ 3.10 - 3.12 |
| 10 | |
+-----------------+-----------------+ +-----------------+-----------------+
Verify your installation is running one of these versions by checking Verify your installation is running one of these versions by checking
@ -271,15 +273,14 @@ Noteworthy Differences
* "Module Replacer" style modules are not supported. These rarely appear in * "Module Replacer" style modules are not supported. These rarely appear in
practice, and light web searches failed to reveal many examples of them. practice, and light web searches failed to reveal many examples of them.
..
* The ``ansible_python_interpreter`` variable is parsed using a restrictive * The ``ansible_python_interpreter`` variable is parsed using a restrictive
:mod:`shell-like <shlex>` syntax, permitting values such as ``/usr/bin/env :mod:`shell-like <shlex>` syntax, permitting values such as ``/usr/bin/env
FOO=bar python`` or ``source /opt/rh/rh-python36/enable && python``, which FOO=bar python`` or ``source /opt/rh/rh-python36/enable && python``.
occur in practice. Jinja2 templating is also supported for complex task-level Jinja2 templating is also supported for complex task-level
interpreter settings. Ansible `documents this interpreter settings. Ansible documents `ansible_python_interpreter
<https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#ansible-python-interpreter>`_ <https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#ansible-python-interpreter>`_
as an absolute path, however the implementation passes it unquoted through as an absolute path and releases since June 2024 (e.g. Ansible 10.1)
the shell, permitting arbitrary code to be injected. reflect this. Older Ansible releases passed it to the shell unquoted.
.. ..
* Configurations will break that rely on the `hashbang argument splitting * Configurations will break that rely on the `hashbang argument splitting

@ -21,6 +21,9 @@ To avail of fixes in an unreleased version, please download a ZIP file
Unreleased Unreleased
---------- ----------
* :gh:issue:`1097` Respect `ansible_facts.discovered_interpreter_python` when
executing non new-style modules (e.g. JSONARGS style, WANT_JSON style).
* :gh:issue:`1074` Support Ansible 10 (ansible-core 2.17)
v0.3.8 (2024-07-30) v0.3.8 (2024-07-30)

@ -1,6 +1,9 @@
# code: language=ini # code: language=ini
# vim: syntax=dosini # vim: syntax=dosini
[become_same_user]
# become_same_user.yml # become_same_user.yml
bsu-joe ansible_user=joe bsu-joe ansible_user=joe
[become_same_user:vars]
ansible_python_interpreter=python3000

@ -4,7 +4,7 @@
# Connection delegation scenarios. It's impossible to connect to them, but their would-be # Connection delegation scenarios. It's impossible to connect to them, but their would-be
# config can be inspected using "mitogen_get_stack" action. # config can be inspected using "mitogen_get_stack" action.
[cd]
# Normal inventory host, no aliasing. # Normal inventory host, no aliasing.
cd-normal ansible_connection=mitogen_doas ansible_user=normal-user cd-normal ansible_connection=mitogen_doas ansible_user=normal-user
@ -23,6 +23,8 @@ cd-newuser-normal-normal mitogen_via=cd-normal ansible_user=newuser-normal-norma
# doas:newuser via host. # doas:newuser via host.
cd-newuser-doas-normal mitogen_via=cd-normal ansible_connection=mitogen_doas ansible_user=newuser-doas-normal-user cd-newuser-doas-normal mitogen_via=cd-normal ansible_connection=mitogen_doas ansible_user=newuser-doas-normal-user
[cd:vars]
ansible_python_interpreter = python3000
[connection-delegation-test] [connection-delegation-test]
cd-bastion cd-bastion

@ -40,7 +40,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
'python_path': ["{{ ansible_facts.discovered_interpreter_python | default('/usr/bin/python') }}"], 'python_path': ['python3000'],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -68,7 +68,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
'python_path': ["{{ ansible_facts.discovered_interpreter_python | default('/usr/bin/python') }}"], 'python_path': ['python3000'],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,

@ -19,7 +19,7 @@
'kind': 'lxc', 'kind': 'lxc',
'lxc_info_path': null, 'lxc_info_path': null,
'machinectl_path': null, 'machinectl_path': null,
'python_path': ['/usr/bin/python'], 'python_path': ['python3000'],
'remote_name': null, 'remote_name': null,
'username': null, 'username': null,
}, },

@ -23,7 +23,7 @@
'lxc_info_path': null, 'lxc_info_path': null,
'lxc_path': null, 'lxc_path': null,
'machinectl_path': null, 'machinectl_path': null,
'python_path': ["/usr/bin/python"], 'python_path': ["python3000"],
'username': 'ansible-cfg-remote-user', 'username': 'ansible-cfg-remote-user',
}, },
'method': 'setns', 'method': 'setns',

@ -40,7 +40,7 @@
"connect_timeout": 30, "connect_timeout": 30,
"doas_path": null, "doas_path": null,
"password": null, "password": null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
"username": "normal-user", "username": "normal-user",
}, },
@ -73,7 +73,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -115,7 +115,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -150,7 +150,7 @@
'connect_timeout': 30, 'connect_timeout': 30,
'doas_path': null, 'doas_path': null,
'password': null, 'password': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'username': 'normal-user', 'username': 'normal-user',
}, },
@ -168,7 +168,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -210,7 +210,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -238,7 +238,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -272,7 +272,7 @@
'connect_timeout': 30, 'connect_timeout': 30,
'doas_path': null, 'doas_path': null,
'password': null, 'password': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'username': 'normal-user', 'username': 'normal-user',
}, },
@ -290,7 +290,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -333,7 +333,7 @@
'keepalive_count': 10, 'keepalive_count': 10,
'password': null, 'password': null,
'port': null, 'port': null,
"python_path": ["/usr/bin/python"], "python_path": ["python3000"],
'remote_name': null, 'remote_name': null,
'ssh_args': [ 'ssh_args': [
-o, ControlMaster=auto, -o, ControlMaster=auto,
@ -388,7 +388,7 @@
'connect_timeout': 30, 'connect_timeout': 30,
'doas_path': null, 'doas_path': null,
'password': null, 'password': null,
'python_path': ["/usr/bin/python"], 'python_path': ["python3000"],
'remote_name': null, 'remote_name': null,
'username': 'normal-user', 'username': 'normal-user',
}, },
@ -399,7 +399,7 @@
'connect_timeout': 30, 'connect_timeout': 30,
'doas_path': null, 'doas_path': null,
'password': null, 'password': null,
'python_path': ["/usr/bin/python"], 'python_path': ["python3000"],
'remote_name': null, 'remote_name': null,
'username': 'newuser-doas-normal-user', 'username': 'newuser-doas-normal-user',
}, },

@ -4,6 +4,55 @@
- name: integration/interpreter_discovery/ansible_2_8_tests.yml - name: integration/interpreter_discovery/ansible_2_8_tests.yml
hosts: test-targets hosts: test-targets
gather_facts: true gather_facts: true
vars:
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_lt_2_12:
centos:
'6': /usr/bin/python
'7': /usr/bin/python
'8': /usr/libexec/platform-python
debian:
'9': /usr/bin/python
'10': /usr/bin/python3
'11': /usr/bin/python
'NA': /usr/bin/python # Debian 11, Ansible <= 7 (ansible-core <= 2.14)
'bullseye/sid': /usr/bin/python # Debian 11, Ansible 8 - 9 (ansible-core 2.15 - 2.16)
ubuntu:
'16': /usr/bin/python3
'18': /usr/bin/python3
'20': /usr/bin/python3
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_2_12_to_2_16:
centos:
'6': /usr/bin/python
'7': /usr/bin/python
'8': /usr/libexec/platform-python
debian:
'9': /usr/bin/python
'10': /usr/bin/python3
'11': /usr/bin/python3.9
'NA': /usr/bin/python3.9 # Debian 11, Ansible <= 7 (ansible-core <= 2.14)
'bullseye/sid': /usr/bin/python3.9 # Debian 11, Ansible 8 - 9 (ansible-core 2.15 - 2.16)
ubuntu:
'16': /usr/bin/python3
'18': /usr/bin/python3
'20': /usr/bin/python3
DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_ge_2_17:
debian:
'10': /usr/bin/python3.7
'11': /usr/bin/python3.9
'bullseye/sid': /usr/bin/python3.9
ubuntu:
'20': /usr/bin/python3.8
discovered_interpreter_expected: >-
{%- if ansible_version.full is version('2.12', '<', strict=True) -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_lt_2_12[distro][distro_major] }}
{%- elif ansible_version.full is version('2.17', '<', strict=True) -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_2_12_to_2_16[distro][distro_major] }}
{%- else -%}
{{ DISCOVERED_INTERPRETER_EXPECTED_MAP__ANSIBLE_ge_2_17[distro][distro_major] }}
{%- endif -%}
tasks: tasks:
- name: can only run these tests on ansible >= 2.8.0 - name: can only run these tests on ansible >= 2.8.0
block: block:
@ -18,9 +67,9 @@
- name: snag some facts to validate for later - name: snag some facts to validate for later
set_fact: set_fact:
distro: '{{ ansible_distribution | default("unknown") | lower }}' distro: '{{ ansible_facts.distribution | lower }}'
distro_version: '{{ ansible_distribution_version | default("unknown") }}' distro_major: '{{ ansible_facts.distribution_major_version }}'
os_family: '{{ ansible_os_family | default("unknown") }}' system: '{{ ansible_facts.system }}'
- name: test that python discovery is working and that fact persistence makes it only run once - name: test that python discovery is working and that fact persistence makes it only run once
block: block:
@ -159,50 +208,19 @@
- ansible_facts['ansible_bogus_interpreter'] | default('nope') == 'nope' - ansible_facts['ansible_bogus_interpreter'] | default('nope') == 'nope'
- ansible_facts['discovered_interpreter_bogus'] | default('nope') == 'nope' - ansible_facts['discovered_interpreter_bogus'] | default('nope') == 'nope'
- name: fedora assertions - name: Check discovered interpreter matches expected
assert:
that:
- auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3'
fail_msg: auto_out={{auto_out}}
when:
- distro == 'fedora'
- distro_version is version('23.0', '>=', strict=True)
- name: rhel < 8 assertions
assert:
that:
- auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python'
fail_msg: auto_out={{auto_out}}
when:
- distro in ('redhat', 'centos')
- distro_version is version('8.0', '<', strict=true)
- name: rhel 8+ assertions
assert:
that:
- auto_out.ansible_facts.discovered_interpreter_python == '/usr/libexec/platform-python'
fail_msg: auto_out={{auto_out}}
when:
- distro in ('redhat', 'centos')
- distro_version is version('8.0', '>=', strict=true)
- name: ubuntu < 16.04 assertions
assert:
that:
- auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python'
fail_msg: auto_out={{auto_out}}
when:
- distro == 'ubuntu'
- distro_version is version('16.04', '<', strict=true)
- name: ubuntu 16.04+ assertions
assert: assert:
that: that:
- auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' - auto_out.ansible_facts.discovered_interpreter_python == discovered_interpreter_expected
fail_msg: auto_out={{auto_out}} fail_msg: >-
distro={{ distro }}
distro_major= {{ distro_major }}
system={{ system }}
auto_out={{ auto_out }}
discovered_interpreter_expected={{ discovered_interpreter_expected }}
ansible_version.full={{ ansible_version.full }}
when: when:
- distro == 'ubuntu' - system in ['Linux']
- distro_version is version('16.04', '>=', strict=True)
always: always:
- meta: clear_facts - meta: clear_facts

@ -9,6 +9,13 @@
https_proxy: "{{ lookup('env', 'https_proxy') | default(omit) }}" https_proxy: "{{ lookup('env', 'https_proxy') | default(omit) }}"
no_proxy: "{{ lookup('env', 'no_proxy') | default(omit) }}" no_proxy: "{{ lookup('env', 'no_proxy') | default(omit) }}"
tasks: tasks:
# Ansible releases after June 2024 quote ansible_python_interpreter
# https://github.com/ansible/ansible/pull/83365
- meta: end_play
when:
- not is_mitogen
- ansible_version.full is version('2.17.1', '>=', strict=True)
- name: create temp file to source - name: create temp file to source
file: file:
path: /tmp/fake path: /tmp/fake
@ -25,8 +32,7 @@
# special_python: source /tmp/fake && python # special_python: source /tmp/fake && python
- name: set python using sourced file - name: set python using sourced file
set_fact: set_fact:
# Avoid 2.x vs 3.x cross-compatiblity issues (that I can't remember the exact details of). special_python: "source /tmp/fake || true && {{ ansible_facts.python.executable }}"
special_python: "source /tmp/fake || true && python{{ ansible_facts.python.version.major }}"
- name: run get_url with specially-sourced python - name: run get_url with specially-sourced python
uri: uri:

@ -1,7 +1,7 @@
# external2 is loaded from config path. # external2 is loaded from config path.
# external1 is loaded from integration/module_utils/roles/modrole/module_utils/.. # external1 is loaded from integration/module_utils/roles/modrole/module_utils/..
- name: integration/module_utils/adjacent_to_playbook.yml - name: integration/module_utils/adjacent_to_role.yml
hosts: test-targets hosts: test-targets
roles: roles:
- modrole - modrole

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils import external3 from ansible.module_utils import external3

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
import json import json
import ansible.module_utils.basic import ansible.module_utils.basic

@ -2,6 +2,12 @@
- name: integration/runner/custom_bash_hashbang_argument.yml - name: integration/runner/custom_bash_hashbang_argument.yml
hosts: test-targets hosts: test-targets
tasks: tasks:
# Ansible releases after June 2024 quote ansible_python_interpreter
# https://github.com/ansible/ansible/pull/83365
- meta: end_play
when:
- not is_mitogen
- ansible_version.full is version('2.17.1', '>=', strict=True)
- custom_bash_old_style_module: - custom_bash_old_style_module:
foo: true foo: true

@ -12,7 +12,6 @@
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_connection: kubectl ansible_connection: kubectl
ansible_python_interpreter: python # avoid Travis virtualenv breakage
mitogen_kubectl_path: stub-kubectl.py mitogen_kubectl_path: stub-kubectl.py
register: out register: out

@ -8,7 +8,6 @@
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_connection: lxc ansible_connection: lxc
ansible_python_interpreter: python # avoid Travis virtualenv breakage
mitogen_lxc_attach_path: stub-lxc-attach.py mitogen_lxc_attach_path: stub-lxc-attach.py
register: out register: out

@ -8,7 +8,6 @@
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_connection: lxd ansible_connection: lxd
ansible_python_interpreter: python # avoid Travis virtualenv breakage
mitogen_lxc_path: stub-lxc.py mitogen_lxc_path: stub-lxc.py
register: out register: out

@ -8,7 +8,6 @@
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_connection: mitogen_doas ansible_connection: mitogen_doas
ansible_python_interpreter: python # avoid Travis virtualenv breakage
ansible_doas_exe: stub-doas.py ansible_doas_exe: stub-doas.py
ansible_user: someuser ansible_user: someuser
register: out register: out

@ -8,7 +8,6 @@
- custom_python_detect_environment: - custom_python_detect_environment:
vars: vars:
ansible_connection: mitogen_sudo ansible_connection: mitogen_sudo
ansible_python_interpreter: python # avoid Travis virtualenv breakage
ansible_user: root ansible_user: root
ansible_become_exe: stub-sudo.py ansible_become_exe: stub-sudo.py
ansible_become_flags: -H --type=sometype --role=somerole ansible_become_flags: -H --type=sometype --role=somerole

@ -2,12 +2,17 @@
# Each case is followed by mitogen_via= case to test hostvars method. # Each case is followed by mitogen_via= case to test hostvars method.
# When no ansible_python_interpreter is set, ansible 2.8+ automatically # If ansible_python_interpreter isn't set, Ansible 2.8+ tries to connect and
# tries to detect the desired interpreter, falling back to "/usr/bin/python" if necessary # detect the interpreter. If that fails (e.g. connection timeout)
# - Ansible 2.8 - 9 (ansible-core 2.8 - 2.16) assumes "/usr/bin/python"
# - Ansible 10+ (ansible-core 2.17+) marks the target unreachable
- name: integration/transport_config/python_path.yml - name: integration/transport_config/python_path.yml
hosts: tc-python-path-unset hosts: tc-python-path-unset
tasks: tasks:
- include_tasks: ../_mitogen_only.yml - include_tasks: ../_mitogen_only.yml
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- {mitogen_get_stack: {}, register: out} - {mitogen_get_stack: {}, register: out}
- assert_equal: - assert_equal:
left: out.result[0].kwargs.python_path left: out.result[0].kwargs.python_path
@ -19,6 +24,9 @@
vars: {mitogen_via: tc-python-path-unset} vars: {mitogen_via: tc-python-path-unset}
tasks: tasks:
- include_tasks: ../_mitogen_only.yml - include_tasks: ../_mitogen_only.yml
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- {mitogen_get_stack: {}, register: out} - {mitogen_get_stack: {}, register: out}
- assert_equal: - assert_equal:
left: out.result[0].kwargs.python_path left: out.result[0].kwargs.python_path
@ -45,6 +53,9 @@
vars: {mitogen_via: tc-python-path-hostvar} vars: {mitogen_via: tc-python-path-hostvar}
tasks: tasks:
- include_tasks: ../_mitogen_only.yml - include_tasks: ../_mitogen_only.yml
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- {mitogen_get_stack: {}, register: out} - {mitogen_get_stack: {}, register: out}
- assert_equal: - assert_equal:
left: out.result[0].kwargs.python_path left: out.result[0].kwargs.python_path
@ -71,6 +82,9 @@
vars: {mitogen_via: localhost} vars: {mitogen_via: localhost}
tasks: tasks:
- include_tasks: ../_mitogen_only.yml - include_tasks: ../_mitogen_only.yml
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- {mitogen_get_stack: {}, register: out} - {mitogen_get_stack: {}, register: out}
- assert_equal: - assert_equal:
left: out.result[0].kwargs.python_path left: out.result[0].kwargs.python_path

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
# I am an Ansible Python JSONARGS module. I should receive an encoding string. # I am an Ansible Python JSONARGS module. I should receive an encoding string.
json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>""" json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>"""

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
# #591: call os.getcwd() before AnsibleModule ever gets a chance to fix up the # #591: call os.getcwd() before AnsibleModule ever gets a chance to fix up the
# process environment. # process environment.

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/python
# I am an Ansible Python WANT_JSON module. I should receive a JSON-encoded file. # I am an Ansible Python WANT_JSON module. I should receive a JSON-encoded file.
import json import json

@ -28,6 +28,10 @@
become: false become: false
serial: 1 serial: 1
tasks: tasks:
# FIXME https://github.com/mitogen-hq/mitogen/issues/1096
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- meta: reset_connection - meta: reset_connection
# The host key might be in ~/.ssh/known_hosts. If it's removed then no # The host key might be in ~/.ssh/known_hosts. If it's removed then no

@ -12,7 +12,9 @@
https_proxy: "{{ lookup('env', 'https_proxy')|default('') }}" https_proxy: "{{ lookup('env', 'https_proxy')|default('') }}"
no_proxy: "{{ lookup('env', 'no_proxy')|default('') }}" no_proxy: "{{ lookup('env', 'no_proxy')|default('') }}"
PATH: "{{ lookup('env', 'PATH') }}" PATH: "{{ lookup('env', 'PATH') }}"
shell: virtualenv /tmp/issue_152_virtualenv command:
cmd: virtualenv -p "{{ ansible_facts.python.executable }}" /tmp/issue_152_virtualenv
creates: /tmp/issue_152_virtualenv
when: when:
- lout.python.version.full is version('2.7', '>=', strict=True) - lout.python.version.full is version('2.7', '>=', strict=True)

@ -3,13 +3,25 @@
- name: regression/issue_776__load_plugins_called_twice.yml - name: regression/issue_776__load_plugins_called_twice.yml
hosts: test-targets hosts: test-targets
become: "{{ groups.linux is defined and inventory_hostname in groups.linux }}" become: "{{ groups.linux is defined and inventory_hostname in groups.linux }}"
gather_facts: yes # Delayed until after the end_play, due to Python version requirements
gather_facts: false
tags: tags:
- issue_776 - issue_776
vars: vars:
ansible_python_interpreter: "{{ pkg_mgr_python_interpreter }}" ansible_python_interpreter: "{{ pkg_mgr_python_interpreter }}"
package: rsync # Chosen to exist in all tested distros/package managers package: rsync # Chosen to exist in all tested distros/package managers
tasks: tasks:
# The package management modules require using the same Python version
# as the target's package manager libraries. This is sometimes in conflict
# with Ansible requirements, e.g. Ansible 10 (ansible-core 2.17) does not
# support Python 2.x on targets.
- meta: end_play
when:
- ansible_version.full is version('2.17', '>=', strict=True)
- name: Gather facts manually
setup:
- name: Switch to archived package repositories - name: Switch to archived package repositories
copy: copy:
dest: "{{ item.dest }}" dest: "{{ item.dest }}"

@ -10,9 +10,9 @@
# 2.4 2.3? <= 3.7.1 <= 1.3.7 <= 1.1 <= 2.1.3 <= 1.4 <= 1.8 # 2.4 2.3? <= 3.7.1 <= 1.3.7 <= 1.1 <= 2.1.3 <= 1.4 <= 1.8
# 2.5 <= 3.7.1 <= 1.4.22 <= 1.3.1 <= 2.1.3 <= 2.8.7 <= 1.6.1 <= 1.9.1 # 2.5 <= 3.7.1 <= 1.4.22 <= 1.3.1 <= 2.1.3 <= 2.8.7 <= 1.6.1 <= 1.9.1
# 2.6 <= 2.6.20 <= 2.12 <= 4.5.4 <= 1.6.11 <= 2.10.3 <= 9.0.3 <= 5.9.0 <= 3.2.5 <= 2.9.1 <= 15.2.0 # 2.6 <= 2.6.20 <= 2.12 <= 4.5.4 <= 1.6.11 <= 2.10.3 <= 9.0.3 <= 5.9.0 <= 3.2.5 <= 2.9.1 <= 15.2.0
# 2.7 <= 2.11 <= 5.5 <= 1.11.29 <= 2.11.3 <= 20 <= 4.6.11 <= 3.28 <= 20.15² # 2.7 <= 2.11 <= 2.16 <= 5.5 <= 1.11.29 <= 2.11.3 <= 20 <= 4.6.11 <= 3.28 <= 20.15²
# 3.5 <= 2.11 <= 2.15 <= 5.5 <= 2.2.28 <= 2.11.3 <= 20 <= 5.9.5 <= 6.1.0 <= 3.28 <= 20.15² # 3.5 <= 2.11 <= 2.15 <= 5.5 <= 2.2.28 <= 2.11.3 <= 20 <= 5.9.5 <= 6.1.0 <= 3.28 <= 20.15²
# 3.6 <= 2.11 <= 6.2 <= 3.2.20 <= 3.0.3 <= 21 <= 7.0.1 <= 3.28 <= 20.17² # 3.6 <= 2.11 <= 2.16 <= 6.2 <= 3.2.20 <= 3.0.3 <= 21 <= 7.0.1 <= 3.28 <= 20.17²
# 3.7 <= 2.12 <= 7.2.7 <= 3.2.20 <= 7.4.4 <= 4.8.0 # 3.7 <= 2.12 <= 7.2.7 <= 3.2.20 <= 7.4.4 <= 4.8.0
# 3.8 <= 2.12 # 3.8 <= 2.12
# 3.9 <= 2.15 # 3.9 <= 2.15
@ -46,18 +46,14 @@
# ansible == 7.x ansible-core ~= 2.14.0 # ansible == 7.x ansible-core ~= 2.14.0
# ansible == 8.x ansible-core ~= 2.15.0 # ansible == 8.x ansible-core ~= 2.15.0
# ansible == 9.x ansible-core ~= 2.16.0 # ansible == 9.x ansible-core ~= 2.16.0
# ansible == 10.x ansible-core ~= 2.17.0
# pip --no-python-version-warning
# pip --disable-pip-version-check
# TODO distros=-py3
[tox] [tox]
envlist = envlist =
init, init,
py{27,36}-mode_ansible-ansible{2.10,3,4}, py{27,36}-mode_ansible-ansible{2.10,3,4},
py{311}-mode_ansible-ansible{2.10,3,4,5}, py{311}-mode_ansible-ansible{2.10,3,4,5},
py{312}-mode_ansible-ansible{6,7,8,9}, py{312}-mode_ansible-ansible{6,7,8,9,10},
py{27,36,312}-mode_mitogen-distro_centos{6,7,8}, py{27,36,312}-mode_mitogen-distro_centos{6,7,8},
py{27,36,312}-mode_mitogen-distro_debian{9,10,11}, py{27,36,312}-mode_mitogen-distro_debian{9,10,11},
py{27,36,312}-mode_mitogen-distro_ubuntu{1604,1804,2004}, py{27,36,312}-mode_mitogen-distro_ubuntu{1604,1804,2004},
@ -86,6 +82,7 @@ deps =
ansible7: ansible~=7.0 ansible7: ansible~=7.0
ansible8: ansible~=8.0 ansible8: ansible~=8.0
ansible9: ansible~=9.0 ansible9: ansible~=9.0
ansible10: ansible~=10.0
install_command = install_command =
python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages} python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages}
commands_pre = commands_pre =
@ -104,6 +101,9 @@ passenv =
AWS_DEFAULT_REGION AWS_DEFAULT_REGION
AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY
HOME HOME
# Azure DevOps, TF_BUILD is set to 'True' when running in a build task
# https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables
TF_BUILD
setenv = setenv =
# See also azure-pipelines.yml # See also azure-pipelines.yml
ANSIBLE_STRATEGY = mitogen_linear ANSIBLE_STRATEGY = mitogen_linear
@ -126,8 +126,10 @@ setenv =
ansible6: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004 ansible6: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
ansible7: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004 ansible7: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
ansible8: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004 ansible8: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1604 ubuntu1804 ubuntu2004
# Ansible >= 9 (ansible-core >= 2.16) require Python 2.7 or >= 3.6 on targets # Ansible 9 (ansible-core 2.16) requires Python 2.7 or >= 3.6 on targets
ansible9: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1804 ubuntu2004 ansible9: DISTROS=centos7 centos8 debian9 debian10 debian11 ubuntu1804 ubuntu2004
# Ansible 10 (ansible-core 2.17) requires Python >= 3.7 on targets
ansible10: DISTROS=debian10-py3 debian11-py3 ubuntu2004-py3
distros_centos: DISTROS=centos6 centos7 centos8 distros_centos: DISTROS=centos6 centos7 centos8
distros_centos5: DISTROS=centos5 distros_centos5: DISTROS=centos5
distros_centos6: DISTROS=centos6 distros_centos6: DISTROS=centos6

Loading…
Cancel
Save