From 65a81121c5ac6b590a2c8b93c49b463e3e2ef521 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 29 May 2025 12:57:56 +0100 Subject: [PATCH 01/33] Begin 0.3.25dev --- docs/changelog.rst | 5 +++++ mitogen/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e092cf62..69755988 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,11 @@ To avail of fixes in an unreleased version, please download a ZIP file `directly from GitHub `_. +In progress (unreleased) +------------------------ + + + v0.3.24 (2025-05-29) -------------------- diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 3fe380fa..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 24) +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From 54ad3341f1bc97f83ad88ffee3040e46a63dd0a4 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Sun, 20 Apr 2025 10:57:29 -0400 Subject: [PATCH 02/33] Support tox tests on ansible 12 alphas --- tox.ini | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index ddb8c88d..67d6cf45 100644 --- a/tox.ini +++ b/tox.ini @@ -47,6 +47,7 @@ # ansible == 9.x ansible-core ~= 2.16.0 # ansible == 10.x ansible-core ~= 2.17.0 # ansible == 11.x ansible-core ~= 2.18.0 +# ansible == 12.x ansible-core ~= 2.19.0 # See also # - https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix @@ -56,7 +57,7 @@ envlist = init, py{27,36}-mode_ansible-ansible{2.10,3,4}, py{311}-mode_ansible-ansible{2.10,3,4,5}, - py{313}-mode_ansible-ansible{6,7,8,9,10,11}, + py{313}-mode_ansible-ansible{6,7,8,9,10,11,12}, py{27,36,313}-mode_mitogen, report, @@ -85,7 +86,8 @@ deps = ansible8: ansible~=8.0 ansible9: ansible~=9.0 ansible10: ansible~=10.0 - ansible11: ansible>=11.0 + ansible11: ansible~=11.0 + ansible12: ansible>=12.0a install_command = python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages} commands_pre = @@ -118,6 +120,7 @@ setenv = ansible10: MITOGEN_TEST_DISTRO_SPECS=debian10-py3 debian11-py3 ubuntu2004-py3 # Ansible 11 (ansible-core 2.18) requires Python >= 3.8 on targets ansible11: MITOGEN_TEST_DISTRO_SPECS=debian11-py3 ubuntu2004-py3 + ansible12: MITOGEN_TEST_DISTRO_SPECS=debian11-py3 ubuntu2004-py3 distros_centos: MITOGEN_TEST_DISTRO_SPECS=centos6 centos7 centos8 distros_centos5: MITOGEN_TEST_DISTRO_SPECS=centos5 distros_centos6: MITOGEN_TEST_DISTRO_SPECS=centos6 From d3413372b42fef19b8a265f2b1cc44203aecda9d Mon Sep 17 00:00:00 2001 From: Lee Garrett Date: Thu, 10 Apr 2025 10:40:55 -0400 Subject: [PATCH 03/33] Allow running with ansible-core 2.19 --- ansible_mitogen/loaders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible_mitogen/loaders.py b/ansible_mitogen/loaders.py index 123dd4ac..9597e3ee 100644 --- a/ansible_mitogen/loaders.py +++ b/ansible_mitogen/loaders.py @@ -49,7 +49,7 @@ __all__ = [ ANSIBLE_VERSION_MIN = (2, 10) -ANSIBLE_VERSION_MAX = (2, 18) +ANSIBLE_VERSION_MAX = (2, 19) NEW_VERSION_MSG = ( "Your Ansible version (%s) is too recent. The most recent version\n" From 375cdbe5cff728425a98e336a91921a23d063623 Mon Sep 17 00:00:00 2001 From: Lee Garrett Date: Fri, 11 Apr 2025 10:39:27 -0400 Subject: [PATCH 04/33] Work around missing internal method ansible 2.19 has removed the _strip_unsafe internal method, so work around this for now. --- ansible_mitogen/utils/unsafe.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ansible_mitogen/utils/unsafe.py b/ansible_mitogen/utils/unsafe.py index b2c3d533..c1bdaee7 100644 --- a/ansible_mitogen/utils/unsafe.py +++ b/ansible_mitogen/utils/unsafe.py @@ -31,7 +31,12 @@ _CAST_DISPATCH = { } _CAST_DISPATCH.update({t: _passthrough for t in mitogen.utils.PASSTHROUGH}) -if hasattr(ansible.utils.unsafe_proxy.AnsibleUnsafeText, '_strip_unsafe'): +if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): + _CAST_DISPATCH.update({ + ansible.utils.unsafe_proxy.AnsibleUnsafeBytes: bytes, + ansible.utils.unsafe_proxy.AnsibleUnsafeText: mitogen.core.UnicodeType, + }) +elif hasattr(ansible.utils.unsafe_proxy.AnsibleUnsafeText, '_strip_unsafe'): _CAST_DISPATCH.update({ ansible.utils.unsafe_proxy.AnsibleUnsafeBytes: _cast_unsafe, ansible.utils.unsafe_proxy.AnsibleUnsafeText: _cast_unsafe, From 8abafe8c8ee167515135e3d0c38f8fec1538955c Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Sun, 20 Apr 2025 11:01:13 -0400 Subject: [PATCH 05/33] Changelog entry for ansible 12 support --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 69755988..9f059eed 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,6 +21,7 @@ To avail of fixes in an unreleased version, please download a ZIP file In progress (unreleased) ------------------------ +* :gh:issue:`1258` Initial Ansible 12 (ansible-core 2.19) support v0.3.24 (2025-05-29) From e5a56a833cb9e29bbe732b786f82a540633c4f59 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 28 May 2025 12:47:52 +0100 Subject: [PATCH 06/33] docs: Add Ansible 12 to support table --- docs/ansible_detailed.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/ansible_detailed.rst b/docs/ansible_detailed.rst index 3d80a290..703e9b4b 100644 --- a/docs/ansible_detailed.rst +++ b/docs/ansible_detailed.rst @@ -141,7 +141,9 @@ Noteworthy Differences +-----------------+ 3.10 - 3.13 | | 10 | | +-----------------+-----------------+ - | 11 | 3.11 - 3.13 | + | 11 | | + +-----------------+ 3.11 - 3.13+ | + | 12 | | +-----------------+-----------------+ Verify your installation is running one of these versions by checking From 01874186974ee02e84589b0ba0768c7139fa14eb Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 29 May 2025 14:56:07 +0100 Subject: [PATCH 07/33] ansible_mitogen: alpha datatag handling & CI for Ansible 12 (ansible-core 2.19) refs #1258 --- .github/workflows/tests.yml | 12 ++++ ansible_mitogen/connection.py | 2 +- ansible_mitogen/mixins.py | 15 +++-- ansible_mitogen/planner.py | 5 +- ansible_mitogen/runner.py | 4 ++ ansible_mitogen/services.py | 8 ++- ansible_mitogen/utils/unsafe.py | 49 +++++++++++++-- docs/changelog.rst | 4 ++ docs/conf.py | 9 +++ .../integration/action/transfer_data.yml | 24 +++++++- .../runner/crashy_new_style_module.yml | 15 +++-- .../runner/custom_binary_producing_junk.yml | 1 + .../runner/custom_binary_single_null.yml | 4 +- .../integration/runner/missing_module.yml | 1 + tests/ansible/integration/ssh/timeouts.yml | 1 + .../integration/transport_config/password.yml | 25 ++++++++ ..._109__target_has_old_ansible_installed.yml | 3 +- .../issue_766__get_with_context.yml | 7 +++ tests/ansible/tests/utils_unsafe_test.py | 60 ++++++++++++++++--- 19 files changed, 219 insertions(+), 30 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6f6a6871..b48576ab 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -177,10 +177,16 @@ jobs: - name: Ans_313_11 python_version: '3.13' tox_env: py313-mode_ansible-ansible11 + - name: Ans_313_12 + python_version: '3.13' + tox_env: py313-mode_ansible-ansible12 - name: Van_313_11 python_version: '3.13' tox_env: py313-mode_ansible-ansible11-strategy_linear + - name: Van_313_12 + python_version: '3.13' + tox_env: py313-mode_ansible-ansible12-strategy_linear - name: Mito_313 python_version: '3.13' @@ -273,6 +279,12 @@ jobs: - name: Van_313_11 tox_env: py313-mode_localhost-ansible11-strategy_linear + - name: Loc_313_12 + tox_env: py313-mode_localhost-ansible12 + + - name: Van_313_12 + tox_env: py313-mode_localhost-ansible12-strategy_linear + steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index 5053a5f5..3e02b971 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -767,7 +767,7 @@ class Connection(ansible.plugins.connection.ConnectionBase): C.BECOME_ALLOW_SAME_USER): stack += (CONNECTION_METHOD[spec.become_method()](spec),) - return stack + return ansible_mitogen.utils.unsafe.cast(stack) def _build_stack(self): """ diff --git a/ansible_mitogen/mixins.py b/ansible_mitogen/mixins.py index dadf2c17..18518d69 100644 --- a/ansible_mitogen/mixins.py +++ b/ansible_mitogen/mixins.py @@ -402,15 +402,17 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): if not self._mitogen_rediscovered_interpreter: result['ansible_facts'][self._discovered_interpreter_key] = self._discovered_interpreter - if self._discovery_warnings: + discovery_warnings = getattr(self, '_discovery_warnings', []) + if discovery_warnings: if result.get('warnings') is None: result['warnings'] = [] - result['warnings'].extend(self._discovery_warnings) + result['warnings'].extend(discovery_warnings) - if self._discovery_deprecation_warnings: + discovery_deprecation_warnings = getattr(self, '_discovery_deprecation_warnings', []) + if discovery_deprecation_warnings: if result.get('deprecations') is None: result['deprecations'] = [] - result['deprecations'].extend(self._discovery_deprecation_warnings) + result['deprecations'].extend(discovery_deprecation_warnings) return ansible.utils.unsafe_proxy.wrap_var(result) @@ -429,7 +431,10 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): "stderr": "stderr data" } """ - data = self._parse_returned_data(result) + if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): + data = self._parse_returned_data(result, profile='legacy') + else: + data = self._parse_returned_data(result) # Cutpasted from the base implementation. if 'stdout' in data and 'stdout_lines' not in data: diff --git a/ansible_mitogen/planner.py b/ansible_mitogen/planner.py index 2915f4b7..5d0fbd78 100644 --- a/ansible_mitogen/planner.py +++ b/ansible_mitogen/planner.py @@ -170,6 +170,7 @@ class Planner(object): """ binding = self._inv.connection.get_binding() + kwargs = ansible_mitogen.utils.unsafe.cast(kwargs) new = dict((mitogen.core.UnicodeType(k), kwargs[k]) for k in kwargs) new.setdefault('good_temp_dir', @@ -204,7 +205,7 @@ class BinaryPlanner(Planner): module=self._inv.module_name, path=self._inv.module_path, json_args=json.dumps(self._inv.module_args), - env=self._inv.env, + env=ansible_mitogen.utils.unsafe.cast(self._inv.env), **kwargs ) @@ -546,7 +547,7 @@ def _invoke_async_task(invocation, planner): call_recv = context.call_async( ansible_mitogen.target.run_module_async, job_id=job_id, - timeout_secs=invocation.timeout_secs, + timeout_secs=ansible_mitogen.utils.unsafe.cast(invocation.timeout_secs), started_sender=started_recv.to_sender(), kwargs=planner.get_kwargs(), ) diff --git a/ansible_mitogen/runner.py b/ansible_mitogen/runner.py index b60e537c..ce7dceb9 100644 --- a/ansible_mitogen/runner.py +++ b/ansible_mitogen/runner.py @@ -73,6 +73,7 @@ except ImportError: from io import StringIO # Prevent accidental import of an Ansible module from hanging on stdin read. +# FIXME Should probably be b'{}' or None. Ansible 2.19 has bytes | None = None. import ansible.module_utils.basic ansible.module_utils.basic._ANSIBLE_ARGS = '{}' @@ -635,6 +636,7 @@ class NewStyleStdio(object): sys.stderr = StringIO() encoded = json.dumps({'ANSIBLE_MODULE_ARGS': args}) ansible.module_utils.basic._ANSIBLE_ARGS = utf8(encoded) + ansible.module_utils.basic._ANSIBLE_PROFILE = 'legacy' sys.stdin = StringIO(mitogen.core.to_text(encoded)) self.original_get_path = getattr(ansible.module_utils.basic, @@ -649,7 +651,9 @@ class NewStyleStdio(object): sys.stdout = self.original_stdout sys.stderr = self.original_stderr sys.stdin = self.original_stdin + # FIXME Should probably be b'{}' or None. Ansible 2.19 has bytes | None = None. ansible.module_utils.basic._ANSIBLE_ARGS = '{}' + ansible.module_utils.basic._ANSIBLE_PROFILE = None class ProgramRunner(Runner): diff --git a/ansible_mitogen/services.py b/ansible_mitogen/services.py index abc0e379..a48ab757 100644 --- a/ansible_mitogen/services.py +++ b/ansible_mitogen/services.py @@ -57,6 +57,7 @@ import mitogen.service import ansible_mitogen.loaders import ansible_mitogen.module_finder import ansible_mitogen.target +import ansible_mitogen.utils import ansible_mitogen.utils.unsafe @@ -338,7 +339,12 @@ class ContextService(mitogen.service.Service): 'ansible_mitogen.target', 'mitogen.fork', 'mitogen.service', - ) + ) + (( + 'ansible.module_utils._internal._json._profiles._module_legacy_c2m', + 'ansible.module_utils._internal._json._profiles._module_legacy_m2c', + 'ansible.module_utils._internal._json._profiles._module_modern_c2m', + 'ansible.module_utils._internal._json._profiles._module_legacy_m2c', + ) if ansible_mitogen.utils.ansible_version[:2] >= (2, 19) else ()) def _send_module_forwards(self, context): if hasattr(self.router.responder, 'forward_modules'): diff --git a/ansible_mitogen/utils/unsafe.py b/ansible_mitogen/utils/unsafe.py index c1bdaee7..a3aed462 100644 --- a/ansible_mitogen/utils/unsafe.py +++ b/ansible_mitogen/utils/unsafe.py @@ -16,8 +16,11 @@ __all__ = [ def _cast_to_dict(obj): return {cast(k): cast(v) for k, v in obj.items()} def _cast_to_list(obj): return [cast(v) for v in obj] +def _cast_to_set(obj): return set(cast(v) for v in obj) +def _cast_to_tuple(obj): return tuple(cast(v) for v in obj) def _cast_unsafe(obj): return obj._strip_unsafe() def _passthrough(obj): return obj +def _untag(obj): return obj._native_copy() # A dispatch table to cast objects based on their exact type. @@ -26,30 +29,64 @@ _CAST_DISPATCH = { bytes: bytes, dict: _cast_to_dict, list: _cast_to_list, - tuple: _cast_to_list, mitogen.core.UnicodeType: mitogen.core.UnicodeType, } _CAST_DISPATCH.update({t: _passthrough for t in mitogen.utils.PASSTHROUGH}) -if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): +_CAST_SUBTYPES = [ + dict, + list, +] + +if hasattr(ansible.utils.unsafe_proxy, 'TrustedAsTemplate'): + import datetime + import ansible.module_utils._internal._datatag _CAST_DISPATCH.update({ + set: _cast_to_set, + tuple: _cast_to_tuple, + ansible.module_utils._internal._datatag._AnsibleTaggedBytes: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedDate: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedDateTime: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedDict: _cast_to_dict, + ansible.module_utils._internal._datatag._AnsibleTaggedFloat: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedInt: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedList: _cast_to_list, + ansible.module_utils._internal._datatag._AnsibleTaggedSet: _cast_to_set, + ansible.module_utils._internal._datatag._AnsibleTaggedStr: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedTime: _untag, + ansible.module_utils._internal._datatag._AnsibleTaggedTuple: _cast_to_tuple, ansible.utils.unsafe_proxy.AnsibleUnsafeBytes: bytes, ansible.utils.unsafe_proxy.AnsibleUnsafeText: mitogen.core.UnicodeType, + datetime.date: _passthrough, + datetime.datetime: _passthrough, + datetime.time: _passthrough, }) + _CAST_SUBTYPES.extend([ + set, + tuple, + ]) elif hasattr(ansible.utils.unsafe_proxy.AnsibleUnsafeText, '_strip_unsafe'): _CAST_DISPATCH.update({ + tuple: _cast_to_list, ansible.utils.unsafe_proxy.AnsibleUnsafeBytes: _cast_unsafe, ansible.utils.unsafe_proxy.AnsibleUnsafeText: _cast_unsafe, ansible.utils.unsafe_proxy.NativeJinjaUnsafeText: _cast_unsafe, }) + _CAST_SUBTYPES.extend([ + tuple, + ]) elif ansible_mitogen.utils.ansible_version[:2] <= (2, 16): _CAST_DISPATCH.update({ + tuple: _cast_to_list, ansible.utils.unsafe_proxy.AnsibleUnsafeBytes: bytes, ansible.utils.unsafe_proxy.AnsibleUnsafeText: mitogen.core.UnicodeType, }) + _CAST_SUBTYPES.extend([ + tuple, + ]) else: mitogen_ver = '.'.join(str(v) for v in mitogen.__version__) - raise ImportError("Mitogen %s can't unwrap Ansible %s AnsibleUnsafe objects" + raise ImportError("Mitogen %s can't cast Ansible %s objects" % (mitogen_ver, ansible.__version__)) @@ -78,7 +115,9 @@ def cast(obj): return unwrapper(obj) # Slow path: obj is some unknown subclass - if isinstance(obj, dict): return _cast_to_dict(obj) - if isinstance(obj, (list, tuple)): return _cast_to_list(obj) + for typ_ in _CAST_SUBTYPES: + if isinstance(obj, typ_): + unwrapper = _CAST_DISPATCH[typ_] + return unwrapper(obj) return mitogen.utils.cast(obj) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9f059eed..01a5318d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -22,6 +22,10 @@ In progress (unreleased) ------------------------ * :gh:issue:`1258` Initial Ansible 12 (ansible-core 2.19) support +* :gh:issue:`1258` :mod:`ansible_mitogen`: Initial Ansible datatag support + (:gh:anspull:`84621`) +* :gh:issue:`1258` :mod:`ansible_mitogen`: Ansible 12 (ansible-core 2.19) test + jobs v0.3.24 (2025-05-29) diff --git a/docs/conf.py b/docs/conf.py index 9ad5b534..4fb2b300 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,6 +64,15 @@ domainrefs = { 'text': '#%s', 'url': 'https://github.com/mitogen-hq/mitogen/pull/%s', }, + 'gh:ansissue': { + 'text': 'Ansible #%s', + 'url': 'https://github.com/ansible/ansible/issues/%s', + }, + 'gh:anspull': { + 'text': 'Ansible #%s', + 'url': 'https://github.com/ansible/ansible/pull/%s', + }, + 'ans:mod': { 'text': '%s module', 'url': 'https://docs.ansible.com/ansible/latest/modules/%s_module.html', diff --git a/tests/ansible/integration/action/transfer_data.yml b/tests/ansible/integration/action/transfer_data.yml index ab994683..7dd726ed 100644 --- a/tests/ansible/integration/action/transfer_data.yml +++ b/tests/ansible/integration/action/transfer_data.yml @@ -1,7 +1,14 @@ -- name: integration/action/transfer_data.yml +- name: integration/action/transfer_data.yml, json hosts: test-targets tasks: + - meta: end_play + when: + # Ansible >= 12 (ansible-core >= 2.19) only allows bytes|str through + # `ansible.plugins.action.ActionBase._transfer_data()`. + - ansible_version.full is version('2.18.999', '>', strict=True) + - not is_mitogen + - name: Cleanup transfer data file: path: /tmp/transfer-data @@ -15,26 +22,41 @@ data: { "I am JSON": true } + - name: Slurp JSON transfer data slurp: src: /tmp/transfer-data register: out + - assert: that: | out.content|b64decode == '{"I am JSON": true}' fail_msg: | out={{ out }} + - name: Cleanup transfer data + file: + path: /tmp/transfer-data + state: absent + tags: + - transfer_data + + +- name: integration/action/transfer_data.yml, text + hosts: test-targets + tasks: - name: Create text transfer data action_passthrough: method: _transfer_data kwargs: remote_path: /tmp/transfer-data data: "I am text." + - name: Slurp text transfer data slurp: src: /tmp/transfer-data register: out + - assert: that: out.content|b64decode == 'I am text.' diff --git a/tests/ansible/integration/runner/crashy_new_style_module.yml b/tests/ansible/integration/runner/crashy_new_style_module.yml index 80833ab8..5a4d6651 100644 --- a/tests/ansible/integration/runner/crashy_new_style_module.yml +++ b/tests/ansible/integration/runner/crashy_new_style_module.yml @@ -18,10 +18,17 @@ - not out.changed - out is failed # https://github.com/ansible/ansible/commit/62d8c8fde6a76d9c567ded381e9b34dad69afcd6 - - out.msg is match(msg_pattern) - - (out.module_stdout == "" and out.module_stderr is search(tb_pattern)) - or - (out.module_stdout is search(tb_pattern) and out.module_stderr is match("Shared connection to localhost closed.")) + - | + out.msg is match(msg_pattern) + or out.msg in ( + "Task failed: Module failed: name 'kaboom' is not defined", + 'Module result deserialization failed: No start of json char found', + ) + # - out.exception is undefined + # or out.exception | default('') is match(tb_pattern) + # or out.module_stderr is search(tb_pattern) + # - out.module_stdout == '' + # - out.module_stderr is search(tb_pattern) fail_msg: | out={{ out }} tags: diff --git a/tests/ansible/integration/runner/custom_binary_producing_junk.yml b/tests/ansible/integration/runner/custom_binary_producing_junk.yml index 2a05fb75..c8ab869a 100644 --- a/tests/ansible/integration/runner/custom_binary_producing_junk.yml +++ b/tests/ansible/integration/runner/custom_binary_producing_junk.yml @@ -30,6 +30,7 @@ - out.failed - out.results[0].failed - out.results[0].msg.startswith('MODULE FAILURE') + or out.results[0].msg.startswith('Module result deserialization failed') - out.results[0].rc == 0 fail_msg: | out={{ out }} diff --git a/tests/ansible/integration/runner/custom_binary_single_null.yml b/tests/ansible/integration/runner/custom_binary_single_null.yml index cfd401f8..bb5ec5d0 100644 --- a/tests/ansible/integration/runner/custom_binary_single_null.yml +++ b/tests/ansible/integration/runner/custom_binary_single_null.yml @@ -15,7 +15,9 @@ that: - "out.failed" - "out.results[0].failed" - - "out.results[0].msg.startswith('MODULE FAILURE')" + - | + out.results[0].msg.startswith('MODULE FAILURE') + or out.results[0].msg == 'Module result deserialization failed: No start of json char found' # On Ubuntu 16.04 /bin/sh is dash 0.5.8. It treats custom_binary_single_null # as a valid executable. There's no error message, and rc == 0. - | diff --git a/tests/ansible/integration/runner/missing_module.yml b/tests/ansible/integration/runner/missing_module.yml index 4d3f6823..b42e3af3 100644 --- a/tests/ansible/integration/runner/missing_module.yml +++ b/tests/ansible/integration/runner/missing_module.yml @@ -26,6 +26,7 @@ - assert: that: | 'The module missing_module was not found in configured module paths' in out.stdout + or "Cannot resolve 'missing_module' to an action or module" in out.stdout fail_msg: | out={{ out }} tags: diff --git a/tests/ansible/integration/ssh/timeouts.yml b/tests/ansible/integration/ssh/timeouts.yml index afc5e5a2..7ea905f5 100644 --- a/tests/ansible/integration/ssh/timeouts.yml +++ b/tests/ansible/integration/ssh/timeouts.yml @@ -43,6 +43,7 @@ '"unreachable": true' in out.stdout - | '"msg": "Connection timed out."' in out.stdout + or '"msg": "Task failed: Connection timed out."' in out.stdout fail_msg: | out={{ out }} tags: diff --git a/tests/ansible/integration/transport_config/password.yml b/tests/ansible/integration/transport_config/password.yml index 5a1968e0..b447b8b6 100644 --- a/tests/ansible/integration/transport_config/password.yml +++ b/tests/ansible/integration/transport_config/password.yml @@ -8,9 +8,14 @@ tasks: - include_tasks: ../_mitogen_only.yml - {mitogen_get_stack: {}, register: out} + - assert_equal: + left: out.result[0].kwargs.password + right: null + when: ansible_version.full is version('2.18.999', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" # actually null, but assert_equal limitation + when: ansible_version.full is version('2.18.999', '<', strict=True) tags: - mitogen_only @@ -23,9 +28,14 @@ - assert_equal: left: out.result[0].kwargs.password right: "ansi-ssh-pass" + - assert_equal: + left: out.result[1].kwargs.password + right: null + when: ansible_version.full is version('2.18.999', '>=', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "" + when: ansible_version.full is version('2.18.999', '<', strict=True) tags: - mitogen_only @@ -48,9 +58,14 @@ tasks: - include_tasks: ../_mitogen_only.yml - {mitogen_get_stack: {}, register: out} + - assert_equal: + left: out.result[0].kwargs.password + right: null + when: ansible_version.full is version('2.18.999', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" + when: ansible_version.full is version('2.18.999', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "ansi-ssh-pass" @@ -76,9 +91,14 @@ tasks: - include_tasks: ../_mitogen_only.yml - {mitogen_get_stack: {}, register: out} + - assert_equal: + left: out.result[0].kwargs.password + right: null + when: ansible_version.full is version('2.18.999', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" + when: ansible_version.full is version('2.18.999', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "ansi-pass" @@ -104,9 +124,14 @@ tasks: - include_tasks: ../_mitogen_only.yml - {mitogen_get_stack: {}, register: out} + - assert_equal: + left: out.result[0].kwargs.password + right: null + when: ansible_version.full is version('2.18.999', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" + when: ansible_version.full is version('2.18.999', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "c.b.a" diff --git a/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml b/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml index a7ae0908..92bdfd7e 100644 --- a/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml +++ b/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml @@ -24,7 +24,8 @@ assert: that: - env.cwd == ansible_user_dir - - (not env.mitogen_loaded) or (env.python_path.count("") == 1) + - not env.mitogen_loaded + or (env.python_path | select('eq', '') | length == 1) fail_msg: | ansible_user_dir={{ ansible_user_dir }} env={{ env }} diff --git a/tests/ansible/regression/issue_766__get_with_context.yml b/tests/ansible/regression/issue_766__get_with_context.yml index 38e33275..09556939 100644 --- a/tests/ansible/regression/issue_766__get_with_context.yml +++ b/tests/ansible/regression/issue_766__get_with_context.yml @@ -28,6 +28,13 @@ - ansible_version.full is version('2.11', '>=', strict=True) - ansible_version.full is version('2.12', '<', strict=True) + - meta: end_play + when: + # TASK [Get running configuration and state data ] + # Error: : Task failed: ActionBase._parse_returned_data() missing 1 required positional argument: 'profile' + # https://github.com/ansible-collections/ansible.netcommon/issues/698#issuecomment-2910082548 + - ansible_version.full is version('2.18.999', '>=', strict=True) + - block: - name: Start container command: diff --git a/tests/ansible/tests/utils_unsafe_test.py b/tests/ansible/tests/utils_unsafe_test.py index 9aa461c5..2ca863b7 100644 --- a/tests/ansible/tests/utils_unsafe_test.py +++ b/tests/ansible/tests/utils_unsafe_test.py @@ -4,6 +4,7 @@ from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes from ansible.utils.unsafe_proxy import AnsibleUnsafeText from ansible.utils.unsafe_proxy import wrap_var +import ansible_mitogen.utils import ansible_mitogen.utils.unsafe import mitogen.core @@ -17,7 +18,7 @@ class Text(mitogen.core.UnicodeType): pass class Tuple(tuple): pass -class CastTest(unittest.TestCase): +class CastMixin(unittest.TestCase): def assertIsType(self, obj, cls, msg=None): self.assertIs(type(obj), cls, msg) @@ -29,6 +30,8 @@ class CastTest(unittest.TestCase): self.assertEqual(cast(obj), expected) self.assertIsType(cast(obj), type(expected)) + +class CastKnownTest(CastMixin): def test_ansible_unsafe(self): self.assertCasts(AnsibleUnsafeBytes(b'abc'), b'abc') self.assertCasts(AnsibleUnsafeText(u'abc'), u'abc') @@ -47,14 +50,12 @@ class CastTest(unittest.TestCase): self.assertCasts(wrap_var({}), {}) self.assertCasts(wrap_var([]), []) self.assertCasts(wrap_var(u''), u'') - self.assertCasts(wrap_var(()), []) def test_subtypes_roundtrip(self): self.assertCasts(wrap_var(Bytes()), b'') self.assertCasts(wrap_var(Dict()), {}) self.assertCasts(wrap_var(List()), []) self.assertCasts(wrap_var(Text()), u'') - self.assertCasts(wrap_var(Tuple()), []) def test_subtype_nested_dict(self): obj = Dict(foo=Dict(bar=u'abc')) @@ -75,18 +76,59 @@ class CastTest(unittest.TestCase): self.assertIsType(unwrapped[0], list) self.assertIsType(unwrapped[0][0], mitogen.core.UnicodeType) - def test_subtype_roundtrip_tuple(self): - # wrap_var() preserves sequence types, cast() does not (for now) + +@unittest.skipIf( + ansible_mitogen.utils.ansible_version[:2] <= (2, 18), + 'Ansible <= 11 (ansible-core >= 2.18) does not send/receive sets', +) +class CastSetTest(CastMixin): + def test_set(self): + self.assertCasts(wrap_var(set()), set()) + + def test_set_subclass(self): + self.assertCasts(wrap_var(Set()), set()) + + +class CastTupleTest(CastMixin): + def test_tuple(self): + if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): + expected = () + else: + expected = [] + self.assertCasts(wrap_var(Tuple()), expected) + + def test_tuple_subclass(self): + if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): + expected = () + else: + expected = [] + self.assertCasts(wrap_var(()), expected) + + def test_tuple_subclass_with_contents(self): + if ansible_mitogen.utils.ansible_version[:2] >= (2, 19): + expected = ((u'abc',),) + else: + expected = [[u'abc']] + obj = Tuple([Tuple([u'abc'])]) wrapped = wrap_var(obj) unwrapped = ansible_mitogen.utils.unsafe.cast(wrapped) - self.assertEqual(unwrapped, [[u'abc']]) - self.assertIsType(unwrapped, list) - self.assertIsType(unwrapped[0], list) + self.assertEqual(unwrapped, expected) + self.assertIsType(unwrapped, type(expected)) + self.assertIsType(unwrapped[0], type(expected[0])) self.assertIsType(unwrapped[0][0], mitogen.core.UnicodeType) - def test_unknown_types_raise(self): + +class CastUknownTypeTest(unittest.TestCase): + @unittest.skipIf( + ansible_mitogen.utils.ansible_version[:2] >= (2, 19), + 'Ansible >= 12 (ansible-core >= 2.19) uses/preserves sets', + ) + def test_set_raises(self): cast = ansible_mitogen.utils.unsafe.cast self.assertRaises(TypeError, cast, set()) self.assertRaises(TypeError, cast, Set()) + + def test_complex_raises(self): + cast = ansible_mitogen.utils.unsafe.cast self.assertRaises(TypeError, cast, 4j) From 208e37abef919e693d27b449165cd6d52884db2d Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 4 Jun 2025 23:26:49 +0100 Subject: [PATCH 08/33] packaging: Handle pre-release __version__ tuples --- docs/conf.py | 2 ++ setup.py | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4fb2b300..4bffabd8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -5,6 +5,8 @@ sys.path.append('.') def changelog_version(path, encoding='utf-8'): + "Return the 1st *stable* (not pre, dev) version in the changelog" + # See also grep_version() in setup.py version_pattern = re.compile( r'^v(?P[0-9]+\.[0-9]+\.[0-9]+)', re.MULTILINE, diff --git a/setup.py b/setup.py index 1639d383..f8aeffea 100644 --- a/setup.py +++ b/setup.py @@ -33,15 +33,34 @@ from setuptools import find_packages, setup def grep_version(): + # See also changlelog_version() in docs.conf.py path = os.path.join(os.path.dirname(__file__), 'mitogen/__init__.py') + + # Based on https://packaging.python.org/en/latest/specifications/version-specifiers/#appendix-parsing-version-strings-with-regular-expressions + # e.g. "__version__ = (0, 1, 2)", "__version__ = (0, 1, 3, 'dev')", + # "__version__ = (0, 1, 4, 'a', 1)" version_pattern = re.compile( - r"__version__ = \((\d+), (\d+), (\d+)(?:, '(dev)')?\)", + r''' + ^__version__\s=\s\( + (?P\d+) + ,\s + (?P\d+) + ,\s + (?P\d+) + (?: + (?:,\s '(?Pdev)') + | (?:,\s '(?Pa|b)' ,\s (?P\d+)) + )? + \) + $ + ''', + re.MULTILINE | re.VERBOSE, ) with open(path) as fp: match = version_pattern.search(fp.read()) if match is None: raise ValueError('Could not find __version__ string in %s', path) - # E.g. '0.1.2', '0.1.3dev' + # e.g. '0.1.2', '0.1.3dev', '0.1.4a1' return '.'.join(str(part) for part in match.groups() if part) From bd774b7489ac7535983d0151163fbf4f8f45cd7e Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 4 Jun 2025 23:29:54 +0100 Subject: [PATCH 09/33] Prepare v0.3.25a1 --- docs/changelog.rst | 4 ++-- mitogen/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 01a5318d..30d717f7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,8 +18,8 @@ To avail of fixes in an unreleased version, please download a ZIP file `directly from GitHub `_. -In progress (unreleased) ------------------------- +v0.3.25a1 (2025-06-05) +---------------------- * :gh:issue:`1258` Initial Ansible 12 (ansible-core 2.19) support * :gh:issue:`1258` :mod:`ansible_mitogen`: Initial Ansible datatag support diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..95a16ce7 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25, 'a', 1) #: This is :data:`False` in slave contexts. Previously it was used to prevent From dd4b5755efc87d6d13fe073129be2ef40351bf63 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 4 Jun 2025 23:31:01 +0100 Subject: [PATCH 10/33] Continue 0.3.25dev --- docs/changelog.rst | 5 +++++ mitogen/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 30d717f7..bae89718 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,11 @@ To avail of fixes in an unreleased version, please download a ZIP file `directly from GitHub `_. +In progress (unreleased) +------------------------ + + + v0.3.25a1 (2025-06-05) ---------------------- diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 95a16ce7..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'a', 1) +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From d224a61556819c44868c9f58522fec6822d444b8 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 28 May 2025 13:42:12 +0100 Subject: [PATCH 11/33] chore: Ignore locally installed collections, dummy modules, etc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With mock_modules ansible-lint creates files here, e.g. ```console ✗ find .ansible .ansible .ansible/roles .ansible/modules .ansible/modules/test_echo_module.py .ansible/modules/custom_python_leaky_class_vars.py .ansible/modules/custom_python_new_style_module.py ... ``` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7297d720..43e46a19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.ansible/ .coverage .tox .venv From 5ec61c90a664263f9849bf9d60b54c19a527ee67 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 8 Jun 2025 10:48:45 +0100 Subject: [PATCH 12/33] docs: Fix website download link when there is a pre-release The previous regex was incorrectly matching a prefix (e.g. 1.2.3) of a pre-release (e.g. 1.2.3a1, 1.2.3rc1). fixes #1276 --- docs/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 4bffabd8..276a05d6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,8 +7,9 @@ sys.path.append('.') def changelog_version(path, encoding='utf-8'): "Return the 1st *stable* (not pre, dev) version in the changelog" # See also grep_version() in setup.py + # e.g. "0.1.2, (1999-12-31)\n" version_pattern = re.compile( - r'^v(?P[0-9]+\.[0-9]+\.[0-9]+)', + r'^v(?P\d+\.\d+\.\d+) \((?P\d\d\d\d-\d\d-\d\d)\)$', re.MULTILINE, ) From 5f33849311da45db15fb7594e394aed87394d09e Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 8 Jun 2025 12:56:22 +0100 Subject: [PATCH 13/33] docs: Mention Ansible strategy plugin deprecation in changelog fixes #1272 --- docs/changelog.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index bae89718..5b2ec785 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,6 +21,16 @@ To avail of fixes in an unreleased version, please download a ZIP file In progress (unreleased) ------------------------ +Ansible 12 has deprecated third-party strategy plugins. This is currently +how Mitogen integrates with Ansible (e.g. `ANSIBLE_STRATEGY=mitogen_linear`). +Running Ansible 12 + Mitogen will currently print a deprecation warning + + [DEPRECATION WARNING]: Use of strategy plugins not included in + ansible.builtin are deprecated [...]. This feature will be removed from + ansible-core in a future release. + +Ansible + Mitogen will still work for now. Mitogen is considering alternatives +to strategy plugins under :gh:issue:`1278`. v0.3.25a1 (2025-06-05) From 667dd4237afc8f930ea00d098ce95df95f51dfff Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 10 Jun 2025 14:39:56 +0100 Subject: [PATCH 14/33] ansible_mitogen: Replace use of `ansible.parsing.utils.jsonify.jsonify()` The function is Ansible >= 12 (ansible-core >= 2.19). See #1274 for analysis of `json.dumps()` vs `jsonify()` differences. This change is a middle ground between full backward compatibility and using `json.dumps()` unadorned. - if `data` is `None`, then it will still be transferred as `{}` on older versions of Ansible, but 'null' in newer releases. Cases where 'null' caused a problem are suspected/reported, but no reproducers are available. - `ensure_ascii=True` will be still be tried, with fallback. I believe this is only relevant on Python 2.x. - `sort_keys=True` will no longer be used. - No indentation/pretty printing will be applied, this remains unchanged fixes #1274 --- ansible_mitogen/mixins.py | 9 +++++++-- docs/changelog.rst | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ansible_mitogen/mixins.py b/ansible_mitogen/mixins.py index 18518d69..8ddbb437 100644 --- a/ansible_mitogen/mixins.py +++ b/ansible_mitogen/mixins.py @@ -29,6 +29,7 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +import json import logging import os import pwd @@ -42,7 +43,6 @@ import ansible.vars.clean from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.six.moves import shlex_quote -from ansible.parsing.utils.jsonify import jsonify import mitogen.core import mitogen.select @@ -219,8 +219,13 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): Used by the base _execute_module(), and in <2.4 also by the template action module, and probably others. """ + if data is None and ansible_mitogen.utils.ansible_version[:2] <= (2, 18): + data = '{}' if isinstance(data, dict): - data = jsonify(data) + try: + data = json.dumps(data, ensure_ascii=False) + except UnicodeDecodeError: + data = json.dumps(data) if not isinstance(data, bytes): data = to_bytes(data, errors='surrogate_or_strict') diff --git a/docs/changelog.rst b/docs/changelog.rst index 5b2ec785..f0327e0f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,8 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. +* :gh:issue:`1274` :mod:`ansible_mitogen`: Replace use of `jsonify()`, which + is deprecated form Ansible 12 (ansible-core 2.19) v0.3.25a1 (2025-06-05) ---------------------- From 2598941384ad35c6377f6e610e6fb40c63ef0a77 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 17 Jun 2025 14:47:33 +0100 Subject: [PATCH 15/33] tests: Add Debian 11/bullseye security archive signing key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests that install packages are failing due to repos/packages that are signed with this key. ```console $ wget https://ftp-master.debian.org/keys/archive-key-11-security.asc --2025-06-17 14:36:04-- https://ftp-master.debian.org/keys/archive-key-11-security.asc Resolving ftp-master.debian.org (ftp-master.debian.org)... 192.91.235.231 Connecting to ftp-master.debian.org (ftp-master.debian.org)|192.91.235.231|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 11873 (12K) [application/pgp-keys] Saving to: ‘archive-key-11-security.asc’ archive-key-11-security.asc 100%[=================>] 11.59K --.-KB/s in 0.002s 2025-06-17 14:36:05 (6.64 MB/s) - ‘archive-key-11-security.asc’ saved [11873/11873] $ sha256sum archive-key-11-security.asc 716e79393c724d14ecba8be46e99ecbe1b689f67ceff3cb3cab28f6e69e8b8b8 archive-key-11-security.asc $ cp archive-key-11-security.asc \ ~/src/mitogen/tests/image_prep/roles/package_manager/files/debian-archive-bullseye-security-automatic.asc ``` --- tests/ansible/hosts/group_vars/debian11.yml | 2 + ...an-archive-bullseye-security-automatic.asc | 186 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 tests/image_prep/roles/package_manager/files/debian-archive-bullseye-security-automatic.asc diff --git a/tests/ansible/hosts/group_vars/debian11.yml b/tests/ansible/hosts/group_vars/debian11.yml index 9f62f43c..30c98341 100644 --- a/tests/ansible/hosts/group_vars/debian11.yml +++ b/tests/ansible/hosts/group_vars/debian11.yml @@ -1,5 +1,7 @@ package_manager_keys: - src: debian-archive-bullseye-automatic.gpg # Debian 11 dest: /etc/apt/trusted.gpg.d/debian-archive-bullseye-automatic.gpg + - src: debian-archive-bullseye-security-automatic.asc # Debian 11 + dest: /etc/apt/trusted.gpg.d/debian-archive-bullseye-security-automatic.asc - src: debian-archive-bookworm-automatic.gpg # Debian 12 dest: /etc/apt/trusted.gpg.d/debian-archive-bookworm-automatic.gpg diff --git a/tests/image_prep/roles/package_manager/files/debian-archive-bullseye-security-automatic.asc b/tests/image_prep/roles/package_manager/files/debian-archive-bullseye-security-automatic.asc new file mode 100644 index 00000000..e09eef42 --- /dev/null +++ b/tests/image_prep/roles/package_manager/files/debian-archive-bullseye-security-automatic.asc @@ -0,0 +1,186 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +TT9yj35WJXkuIZ7GV189g3gogTpu +=Xxba +-----END PGP PUBLIC KEY BLOCK----- From 41bee1a693cf92fed6aa58277abb05b5cedaa3b9 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 17 Jun 2025 15:32:08 +0100 Subject: [PATCH 16/33] CI: Ansible wheels and development releases notes --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 67d6cf45..41432eea 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ # ansible == 12.x ansible-core ~= 2.19.0 # See also -# - https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix +# - https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix [tox] envlist = @@ -81,6 +81,7 @@ deps = ansible3: ansible~=3.0 ansible4: ansible~=4.0 ansible5: ansible~=5.0 + # From Ansible 6 PyPI distributions include a wheel ansible6: ansible~=6.0 ansible7: ansible~=7.0 ansible8: ansible~=8.0 From 32b346371d438aba3d760d6fb175f8ec62169830 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 18 Jun 2025 09:50:00 +0100 Subject: [PATCH 17/33] CI: Reject Ansible 12.0a6, avoids bug in yaml callback plugin Avoids an error when the yaml stdout callback is enabled > module 'ansible._internal._yaml._dumper' has no attribute 'SafeRepresenter' refs #1284 --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tox.ini b/tox.ini index 41432eea..9f3be10f 100644 --- a/tox.ini +++ b/tox.ini @@ -89,6 +89,9 @@ deps = ansible10: ansible~=10.0 ansible11: ansible~=11.0 ansible12: ansible>=12.0a + # Avoid yaml callback bug, https://github.com/mitogen-hq/mitogen/issues/1284 + ansible12: ansible!=12.0a6 + ansible12: ansible-core!=2.19b6 install_command = python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages} commands_pre = From d481a035c38622072bd187f6d9a26b8b212a633d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=BA=F0=9F=87=A6=20Sviatoslav=20Sydorenko=20=28?= =?UTF-8?q?=D0=A1=D0=B2=D1=8F=D1=82=D0=BE=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1?= =?UTF-8?q?=D0=B8=D0=B4=D0=BE=D1=80=D0=B5=D0=BD=D0=BA=D0=BE=29?= Date: Wed, 18 Jun 2025 13:17:40 +0200 Subject: [PATCH 18/33] Keep comatibility with `setuptools` tagging wheels with `py2.py3` Modern versions of `setuptools` emit a warning when the `universal = 1` option of `bdist_wheel` is used. This warning will turn into an error on Aug 30, 2025. The only function of `universal = 1` is assigning the dual `py2.py3` tag to the wheels. It does not perform any content or metadata compatibility validation that might be related to this. It is possible to keep producing same-tagged wheels by setting the non-deprecated `python_tag` option instead, which is what this PR does. Fixes #1283 Ref https://github.com/pypa/setuptools/pull/4939 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 08919787..ded55039 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bdist_wheel] -universal=1 +python_tag = py2.py3 [coverage:run] branch = true From be4a214820218da35b58172fa9fca6538e80c807 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sat, 21 Jun 2025 09:06:12 +0100 Subject: [PATCH 19/33] Prep v0.3.25a2 --- docs/changelog.rst | 5 +++++ mitogen/__init__.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f0327e0f..78037347 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,9 +32,14 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. + +v0.3.25a2 (2025-06-21) +---------------------- + * :gh:issue:`1274` :mod:`ansible_mitogen`: Replace use of `jsonify()`, which is deprecated form Ansible 12 (ansible-core 2.19) + v0.3.25a1 (2025-06-05) ---------------------- diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..60aaf7f8 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25, 'a', 2) #: This is :data:`False` in slave contexts. Previously it was used to prevent From 239ee673da9e55f8d088c9d92c6983b4af0b0064 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sat, 21 Jun 2025 09:07:24 +0100 Subject: [PATCH 20/33] Continue 0.3.25dev --- mitogen/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 60aaf7f8..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'a', 2) +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From f330c2b1588cf1e4afea74dd7e3cde96b308fe1f Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Mon, 23 Jun 2025 08:32:11 +0100 Subject: [PATCH 21/33] CI: replace stdout=yaml with result_format=yaml for Ansible >= 6 tests Ansible >= 12 (ansible-core >= 2.19) deprecates `stdout_callback=yaml`, superceded by `callback_result_format=yaml`. There is a change in behaviour: `callback_result_format` applies to output of both `ansible-playbook` _and_ `ansible`. Tests that run `ansible` in a subprocess are now explicitly configured to use json (even if they don't inspect that output yet) for more assert-able output across all versions of Ansible. --- docs/changelog.rst | 3 +++ tests/ansible/ansible.cfg | 6 ++++-- tests/ansible/integration/process/unix_socket_cleanup.yml | 2 ++ tests/ansible/integration/runner/missing_module.yml | 2 ++ tests/ansible/integration/ssh/timeouts.yml | 2 ++ tests/ansible/integration/ssh/variables.yml | 4 ++++ tests/ansible/integration/stub_connections/setns_lxc.yml | 2 ++ tests/ansible/integration/stub_connections/setns_lxd.yml | 2 ++ tox.ini | 3 +++ 9 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 78037347..224b40c4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,9 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. +* :gh:issue:`1285` CI: use `result_format = yaml` for Ansible test output, + instead of deprecated `stdout_callback = yaml` + v0.3.25a2 (2025-06-21) ---------------------- diff --git a/tests/ansible/ansible.cfg b/tests/ansible/ansible.cfg index 48a4eec3..4060d9ea 100644 --- a/tests/ansible/ansible.cfg +++ b/tests/ansible/ansible.cfg @@ -1,5 +1,7 @@ [defaults] any_errors_fatal = true +# Ansible >= 6 (ansible-core >= 2.13) +callback_result_format = yaml # callbacks_enabled was added in Ansible 4 (ansible-core 2.11). # profile_tasks: Displays timing for each task and summary table of top N tasks # timer: Displays "Playbook run took 0 days, 0 hours, ..." @@ -17,13 +19,13 @@ strategy_plugins = ../../ansible_mitogen/plugins/strategy inventory_plugins = lib/inventory action_plugins = lib/action callback_plugins = lib/callback -stdout_callback = yaml vars_plugins = lib/vars library = lib/modules filter_plugins = lib/filters module_utils = lib/module_utils retry_files_enabled = False -show_task_path_on_failure = true # Added in ansible-core 2.11 +# Ansible >= 4 (ansible-core >= 2.11) +show_task_path_on_failure = true display_args_to_stdout = True forks = 100 diff --git a/tests/ansible/integration/process/unix_socket_cleanup.yml b/tests/ansible/integration/process/unix_socket_cleanup.yml index 21747494..4466aa2e 100644 --- a/tests/ansible/integration/process/unix_socket_cleanup.yml +++ b/tests/ansible/integration/process/unix_socket_cleanup.yml @@ -11,6 +11,8 @@ vars: ansible_python_interpreter: "{{ ansible_playbook_python }}" shell: >- + ANSIBLE_CALLBACK_RESULT_FORMAT=json + ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" diff --git a/tests/ansible/integration/runner/missing_module.yml b/tests/ansible/integration/runner/missing_module.yml index b42e3af3..b641cbe3 100644 --- a/tests/ansible/integration/runner/missing_module.yml +++ b/tests/ansible/integration/runner/missing_module.yml @@ -5,6 +5,8 @@ - name: Run missing_module connection: local environment: + ANSIBLE_CALLBACK_RESULT_FORMAT: json + ANSIBLE_LOAD_CALLBACK_PLUGINS: "false" ANSIBLE_STRATEGY: "{{ lookup('env', 'ANSIBLE_STRATEGY') | mandatory }}" ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}" vars: diff --git a/tests/ansible/integration/ssh/timeouts.yml b/tests/ansible/integration/ssh/timeouts.yml index 7ea905f5..0cb59422 100644 --- a/tests/ansible/integration/ssh/timeouts.yml +++ b/tests/ansible/integration/ssh/timeouts.yml @@ -13,6 +13,8 @@ - name: Cause Ansible connection timeout connection: local environment: + ANSIBLE_CALLBACK_RESULT_FORMAT: json + ANSIBLE_LOAD_CALLBACK_PLUGINS: "false" ANSIBLE_SSH_TIMEOUT: 10 ANSIBLE_STRATEGY: "{{ lookup('env', 'ANSIBLE_STRATEGY') | mandatory }}" ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}" diff --git a/tests/ansible/integration/ssh/variables.yml b/tests/ansible/integration/ssh/variables.yml index bb4bd179..5eb54dde 100644 --- a/tests/ansible/integration/ssh/variables.yml +++ b/tests/ansible/integration/ssh/variables.yml @@ -19,6 +19,8 @@ - name: ansible_user, ansible_ssh_private_key_file shell: > ANSIBLE_ANY_ERRORS_FATAL=false + ANSIBLE_CALLBACK_RESULT_FORMAT=json + ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" @@ -37,6 +39,8 @@ - name: ansible_user, wrong ansible_ssh_private_key_file shell: > ANSIBLE_ANY_ERRORS_FATAL=false + ANSIBLE_CALLBACK_RESULT_FORMAT=json + ANSIBLE_LOAD_CALLBACK_PLUGINS=false ANSIBLE_STRATEGY=mitogen_linear ANSIBLE_SSH_ARGS="-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa" ANSIBLE_VERBOSITY="{{ ansible_verbosity }}" diff --git a/tests/ansible/integration/stub_connections/setns_lxc.yml b/tests/ansible/integration/stub_connections/setns_lxc.yml index 584a6806..f7654ad8 100644 --- a/tests/ansible/integration/stub_connections/setns_lxc.yml +++ b/tests/ansible/integration/stub_connections/setns_lxc.yml @@ -15,6 +15,8 @@ - name: Run stub-lxc-info.py environment: + ANSIBLE_CALLBACK_RESULT_FORMAT: json + ANSIBLE_LOAD_CALLBACK_PLUGINS: "false" ANSIBLE_STRATEGY: "{{ lookup('env', 'ANSIBLE_STRATEGY') | mandatory }}" ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}" command: | diff --git a/tests/ansible/integration/stub_connections/setns_lxd.yml b/tests/ansible/integration/stub_connections/setns_lxd.yml index 2e07aca3..c461845e 100644 --- a/tests/ansible/integration/stub_connections/setns_lxd.yml +++ b/tests/ansible/integration/stub_connections/setns_lxd.yml @@ -15,6 +15,8 @@ - name: Run ansible stub-lxc.py environment: + ANSIBLE_CALLBACK_RESULT_FORMAT: json + ANSIBLE_LOAD_CALLBACK_PLUGINS: "false" ANSIBLE_STRATEGY: "{{ lookup('env', 'ANSIBLE_STRATEGY') | mandatory }}" ANSIBLE_VERBOSITY: "{{ ansible_verbosity }}" command: | diff --git a/tox.ini b/tox.ini index 9f3be10f..3cad99c0 100644 --- a/tox.ini +++ b/tox.ini @@ -112,6 +112,9 @@ setenv = NOCOVERAGE_ERASE = 1 NOCOVERAGE_REPORT = 1 PIP_CONSTRAINT={toxinidir}/tests/constraints.txt + # Superceded in Ansible >= 6 (ansible-core >= 2.13) by result_format=yaml + # Deprecated in Ansible 12 (ansible-core 2.19) + ansible{2.10,3-5}: DEFAULT_STDOUT_CALLBACK=yaml # Print warning on the first occurence at each module:linenno in Mitogen. Available Python 2.7, 3.2+. PYTHONWARNINGS=default:::ansible_mitogen,default:::mitogen # Ansible 6 - 8 (ansible-core 2.13 - 2.15) require Python 2.7 or >= 3.5 on targets From 3cba11a126f3e48f5cb1adde59672b4abdb1968e Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 1 Jul 2025 09:16:37 +0100 Subject: [PATCH 22/33] CI: Fix ansible_version comparison with ansible-core 2.19.0rc1 Note that tests/ansible/integration/ssh/templated_by_play_taskvar.yml was previously erroniously being skipped with ansible-core 2.19.0a and 2.19.0b. fixes #1293 refs #1175 --- docs/changelog.rst | 2 ++ tests/ansible/hosts/group_vars/all.yml | 11 +++++-- .../integration/_expected_ssh_port.yml | 6 ++-- .../integration/action/transfer_data.yml | 2 +- .../async/result_shell_echo_hi.yml | 6 ++-- .../integration/async/runner_one_job.yml | 8 ++--- .../async/runner_two_simultaneous_jobs.yml | 2 +- .../ansible/integration/connection/reset.yml | 4 +-- .../integration/connection/reset_become.yml | 4 +-- .../delegate_to_template.yml | 2 +- .../context_service/disconnect_cleanup.yml | 2 +- .../ansible_2_8_tests.yml | 10 +++---- .../interpreter_discovery/complex_args.yml | 2 +- .../runner/custom_bash_hashbang_argument.yml | 2 +- .../runner/custom_perl_json_args_module.yml | 2 +- .../runner/custom_perl_want_json_module.yml | 2 +- .../ssh/templated_by_play_taskvar.yml | 2 +- .../_end_play_if_not_sudo_linux.yml | 2 +- .../integration/stub_connections/kubectl.yml | 2 +- .../stub_connections/setns_lxc.yml | 2 +- .../stub_connections/setns_lxd.yml | 2 +- .../integration/transport_config/password.yml | 30 ++++++++++++------- .../transport_config/python_path.yml | 8 ++--- ...ssue_1066__add_host__host_key_checking.yml | 4 +-- ..._109__target_has_old_ansible_installed.yml | 2 +- .../issue_590__sys_modules_crap.yml | 2 +- .../issue_655__wait_for_connection_error.yml | 2 +- .../issue_766__get_with_context.yml | 6 ++-- .../issue_776__load_plugins_called_twice.yml | 2 +- tests/image_prep/_container_setup.yml | 2 +- tests/image_prep/group_vars/all.yml | 2 ++ 31 files changed, 80 insertions(+), 57 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 224b40c4..bd98a835 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -34,6 +34,8 @@ to strategy plugins under :gh:issue:`1278`. * :gh:issue:`1285` CI: use `result_format = yaml` for Ansible test output, instead of deprecated `stdout_callback = yaml` +* :gh:issue:`1293` CI: Fix ``ansible_version`` comparisons when an Ansible + release candidate is under test v0.3.25a2 (2025-06-21) diff --git a/tests/ansible/hosts/group_vars/all.yml b/tests/ansible/hosts/group_vars/all.yml index 6f518cad..7ec10d6a 100644 --- a/tests/ansible/hosts/group_vars/all.yml +++ b/tests/ansible/hosts/group_vars/all.yml @@ -1,4 +1,11 @@ --- +# Avoid `ansible_version.full is version(..., strict=True)` limitations. +# Pre-release info (alpha/beta/rc) is intentionally ignored. +# Behaviour that is present or expected in ansible-core 2.50.x should be +# tested even if ansible-core 2.50.0a1 or 2.50.0rc1 is under test. +ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}" +ansible_version_major_minor_patch: "{{ ansible_version.major }}.{{ ansible_version.minor }}.{{ ansible_version.revision | regex_search('^[0-9]+') }}" + become_unpriv_available: >- {# Vanilla Ansible >= 4 (ansible-core >= 2.11) can use `setfacl` for @@ -13,7 +20,7 @@ become_unpriv_available: >- ( not is_mitogen and is_macos_controller - and ansible_version.full is version("2.11", ">=", strict=True) + and ansible_version_major_minor is version("2.11", ">=", strict=True) ) or ( is_mitogen @@ -22,7 +29,7 @@ become_unpriv_available: >- or ( is_mitogen and ansible_python_interpreter is not defined - and ansible_version.full is version("2.18", "<", strict=True) + and ansible_version_major_minor is version("2.18", "<", strict=True) ) -}} diff --git a/tests/ansible/integration/_expected_ssh_port.yml b/tests/ansible/integration/_expected_ssh_port.yml index 442659a5..f85ec3e2 100644 --- a/tests/ansible/integration/_expected_ssh_port.yml +++ b/tests/ansible/integration/_expected_ssh_port.yml @@ -11,8 +11,10 @@ - set_fact: expected_ssh_port: null - when: ansible_version.full is version('2.11.1', '>=', strict=True) + when: + - ansible_version_major_minor_patch is version('2.11.1', '>=', strict=True) - set_fact: expected_ssh_port: 22 - when: ansible_version.full is version('2.11.1', '<', strict=True) + when: + - ansible_version_major_minor_patch is version('2.11.1', '<', strict=True) diff --git a/tests/ansible/integration/action/transfer_data.yml b/tests/ansible/integration/action/transfer_data.yml index 7dd726ed..c36dd463 100644 --- a/tests/ansible/integration/action/transfer_data.yml +++ b/tests/ansible/integration/action/transfer_data.yml @@ -6,7 +6,7 @@ when: # Ansible >= 12 (ansible-core >= 2.19) only allows bytes|str through # `ansible.plugins.action.ActionBase._transfer_data()`. - - ansible_version.full is version('2.18.999', '>', strict=True) + - ansible_version_major_minor is version('2.19', '>=', strict=True) - not is_mitogen - name: Cleanup transfer data diff --git a/tests/ansible/integration/async/result_shell_echo_hi.yml b/tests/ansible/integration/async/result_shell_echo_hi.yml index d3f9d42c..6e726fc5 100644 --- a/tests/ansible/integration/async/result_shell_echo_hi.yml +++ b/tests/ansible/integration/async/result_shell_echo_hi.yml @@ -35,8 +35,8 @@ # | Ansible <= 3 | ansible-core <= 2.10 | present | True | # | Ansible 4 - 6 | ansible-core 2.11 - 2.13 | deprecated | False | # | Ansible >= 7 | ansible-core >= 2.14 | absent | n/a | - - (ansible_version.full is version("2.14", ">=", strict=True) and async_out.invocation.module_args.warn is not defined) - or (ansible_version.full is version("2.11", ">=", strict=True) and async_out.invocation.module_args.warn == False) + - (ansible_version_major_minor is version("2.14", ">=", strict=True) and async_out.invocation.module_args.warn is not defined) + or (ansible_version_major_minor is version("2.11", ">=", strict=True) and async_out.invocation.module_args.warn == False) or (async_out.invocation.module_args.warn == True) - async_out.rc == 0 - async_out.start.startswith("20") @@ -53,7 +53,7 @@ fail_msg: | async_out={{ async_out }} when: - - ansible_version.full is version('2.4', '>=', strict=True) + - ansible_version_major_minor is version('2.4', '>=', strict=True) vars: async_out: "{{result.content|b64decode|from_json}}" tags: diff --git a/tests/ansible/integration/async/runner_one_job.yml b/tests/ansible/integration/async/runner_one_job.yml index de7a22e6..db9b126f 100644 --- a/tests/ansible/integration/async/runner_one_job.yml +++ b/tests/ansible/integration/async/runner_one_job.yml @@ -41,9 +41,9 @@ - result1.changed == True # ansible/b72e989e1837ccad8dcdc926c43ccbc4d8cdfe44 - | - (ansible_version.full is version('2.8', ">=", strict=True) and + (ansible_version_major_minor is version('2.8', ">=", strict=True) and result1.cmd == "echo alldone;\nsleep 1;\n") or - (ansible_version.full is version('2.8', '<', strict=True) and + (ansible_version_major_minor is version('2.8', '<', strict=True) and result1.cmd == "echo alldone;\n sleep 1;") - result1.delta|length == 14 - result1.start|length == 26 @@ -61,7 +61,7 @@ fail_msg: | result1={{ result1 }} when: - - ansible_version.full is version('2.8', '>', strict=True) # ansible#51393 + - ansible_version_major_minor is version('2.8', '>', strict=True) # ansible#51393 - assert: that: @@ -69,6 +69,6 @@ fail_msg: | result1={{ result1 }} when: - - ansible_version.full is version('2.4', '>', strict=True) + - ansible_version_major_minor is version('2.4', '>', strict=True) tags: - runner_one_job diff --git a/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml b/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml index 74a50318..8c462ec2 100644 --- a/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml +++ b/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml @@ -66,6 +66,6 @@ fail_msg: | result2={{ result2 }} when: - - ansible_version.full is version('2.8', '>=', strict=True) # ansible#51393 + - ansible_version_major_minor is version('2.8', '>=', strict=True) # ansible#51393 tags: - runner_two_simultaneous_jobs diff --git a/tests/ansible/integration/connection/reset.yml b/tests/ansible/integration/connection/reset.yml index 2d7a75d3..9dea33ee 100644 --- a/tests/ansible/integration/connection/reset.yml +++ b/tests/ansible/integration/connection/reset.yml @@ -10,11 +10,11 @@ - debug: msg="reset.yml skipped on Ansible<2.5.6" when: - - ansible_version.full is version('2.5.6', '<', strict=True) + - ansible_version_major_minor_patch is version('2.5.6', '<', strict=True) - meta: end_play when: - - ansible_version.full is version('2.5.6', '<', strict=True) + - ansible_version_major_minor_patch is version('2.5.6', '<', strict=True) - custom_python_detect_environment: register: out diff --git a/tests/ansible/integration/connection/reset_become.yml b/tests/ansible/integration/connection/reset_become.yml index 2548df17..0e0aefa9 100644 --- a/tests/ansible/integration/connection/reset_become.yml +++ b/tests/ansible/integration/connection/reset_become.yml @@ -8,11 +8,11 @@ tasks: - debug: msg="reset_become.yml skipped on Ansible<2.5.6" when: - - ansible_version.full is version('2.5.6', '<', strict=True) + - ansible_version_major_minor_patch is version('2.5.6', '<', strict=True) - meta: end_play when: - - ansible_version.full is version('2.5.6', '<', strict=True) + - ansible_version_major_minor_patch is version('2.5.6', '<', strict=True) - name: save pid of the become acct custom_python_detect_environment: diff --git a/tests/ansible/integration/connection_delegation/delegate_to_template.yml b/tests/ansible/integration/connection_delegation/delegate_to_template.yml index 60a67b82..4cff57e1 100644 --- a/tests/ansible/integration/connection_delegation/delegate_to_template.yml +++ b/tests/ansible/integration/connection_delegation/delegate_to_template.yml @@ -19,7 +19,7 @@ - meta: end_play when: - - ansible_version.full is version('2.4', '<', strict=True) + - ansible_version_major_minor is version('2.4', '<', strict=True) - mitogen_get_stack: delegate_to: "{{ physical_host }}" diff --git a/tests/ansible/integration/context_service/disconnect_cleanup.yml b/tests/ansible/integration/context_service/disconnect_cleanup.yml index 22ba12eb..a87dae3d 100644 --- a/tests/ansible/integration/context_service/disconnect_cleanup.yml +++ b/tests/ansible/integration/context_service/disconnect_cleanup.yml @@ -8,7 +8,7 @@ - meta: end_play when: - - ansible_version.full is version('2.5.6', '<', strict=True) + - ansible_version_major_minor_patch is version('2.5.6', '<', strict=True) # Start with a clean slate. - mitogen_shutdown_all: diff --git a/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml b/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml index eddca199..451b4dc3 100644 --- a/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml +++ b/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml @@ -46,9 +46,9 @@ '20': /usr/bin/python3.8 discovered_interpreter_expected: >- - {%- if ansible_version.full is version('2.12', '<', strict=True) -%} + {%- if ansible_version_major_minor 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) -%} + {%- elif ansible_version_major_minor 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] }} @@ -141,7 +141,7 @@ when: - legacy.ansible_facts.discovered_interpreter_python == '/usr/bin/python' - auto_out.ansible_facts.discovered_interpreter_python != '/usr/bin/python' - - ansible_version.full is version_compare('2.12.0', '<', strict=True) + - ansible_version_major_minor is version('2.12', '<', strict=True) - name: check for warning (only on platforms where auto result is not /usr/bin/python and legacy is) from ansible 2.12 on assert: @@ -153,7 +153,7 @@ when: - legacy.ansible_facts.discovered_interpreter_python == '/usr/bin/python' - auto_out.ansible_facts.discovered_interpreter_python != '/usr/bin/python' - - ansible_version.full is version_compare('2.12.0', '>=', strict=True) + - ansible_version_major_minor is version('2.12', '>=', strict=True) - name: test that auto_silent never warns and got the same answer as auto block: @@ -229,6 +229,6 @@ always: - meta: clear_facts when: - - ansible_version.full is version_compare('2.8.0', '>=', strict=True) + - ansible_version_major_minor is version('2.8', '>=', strict=True) tags: - ansible_2_8_tests diff --git a/tests/ansible/integration/interpreter_discovery/complex_args.yml b/tests/ansible/integration/interpreter_discovery/complex_args.yml index f9770876..555a676b 100644 --- a/tests/ansible/integration/interpreter_discovery/complex_args.yml +++ b/tests/ansible/integration/interpreter_discovery/complex_args.yml @@ -14,7 +14,7 @@ - meta: end_play when: - not is_mitogen - - ansible_version.full is version('2.17.1', '>=', strict=True) + - ansible_version_major_minor_patch is version('2.17.1', '>=', strict=True) - name: create temp file to source file: diff --git a/tests/ansible/integration/runner/custom_bash_hashbang_argument.yml b/tests/ansible/integration/runner/custom_bash_hashbang_argument.yml index 34a60e61..c750317a 100644 --- a/tests/ansible/integration/runner/custom_bash_hashbang_argument.yml +++ b/tests/ansible/integration/runner/custom_bash_hashbang_argument.yml @@ -7,7 +7,7 @@ - meta: end_play when: - not is_mitogen - - ansible_version.full is version('2.17.1', '>=', strict=True) + - ansible_version_major_minor_patch is version('2.17.1', '>=', strict=True) - custom_bash_old_style_module: foo: true diff --git a/tests/ansible/integration/runner/custom_perl_json_args_module.yml b/tests/ansible/integration/runner/custom_perl_json_args_module.yml index a34b6b75..c5c647cd 100644 --- a/tests/ansible/integration/runner/custom_perl_json_args_module.yml +++ b/tests/ansible/integration/runner/custom_perl_json_args_module.yml @@ -20,6 +20,6 @@ fail_msg: | out={{ out }} when: - - ansible_version.full is version('2.4', '>=', strict=True) + - ansible_version_major_minor is version('2.4', '>=', strict=True) tags: - custom_perl_json_args_module diff --git a/tests/ansible/integration/runner/custom_perl_want_json_module.yml b/tests/ansible/integration/runner/custom_perl_want_json_module.yml index 28ad7f7f..91ec5672 100644 --- a/tests/ansible/integration/runner/custom_perl_want_json_module.yml +++ b/tests/ansible/integration/runner/custom_perl_want_json_module.yml @@ -20,6 +20,6 @@ fail_msg: | out={{ out }} when: - - ansible_version.full is version('2.4', '>=', strict=True) + - ansible_version_major_minor is version('2.4', '>=', strict=True) tags: - custom_perl_want_json_module diff --git a/tests/ansible/integration/ssh/templated_by_play_taskvar.yml b/tests/ansible/integration/ssh/templated_by_play_taskvar.yml index c5c2e544..714d05dc 100644 --- a/tests/ansible/integration/ssh/templated_by_play_taskvar.yml +++ b/tests/ansible/integration/ssh/templated_by_play_taskvar.yml @@ -32,7 +32,7 @@ when: # https://github.com/ansible/ansible/issues/84238 - not is_mitogen - - ansible_version.full is version('2.19', '<', strict=True) + - ansible_version_major_minor is version('2.19', '<', strict=True) - meta: reset_connection - name: Templated variables in play, key authentication ping: diff --git a/tests/ansible/integration/stub_connections/_end_play_if_not_sudo_linux.yml b/tests/ansible/integration/stub_connections/_end_play_if_not_sudo_linux.yml index a53f75ed..3a4f4e6e 100644 --- a/tests/ansible/integration/stub_connections/_end_play_if_not_sudo_linux.yml +++ b/tests/ansible/integration/stub_connections/_end_play_if_not_sudo_linux.yml @@ -9,7 +9,7 @@ - command: sudo -n whoami args: - warn: "{{ False if ansible_version.full is version('2.10', '<=', strict=True) else omit }}" + warn: "{{ False if ansible_version_major_minor is version('2.10', '<=', strict=True) else omit }}" ignore_errors: true register: sudo_available diff --git a/tests/ansible/integration/stub_connections/kubectl.yml b/tests/ansible/integration/stub_connections/kubectl.yml index 8fe061d1..c9486d90 100644 --- a/tests/ansible/integration/stub_connections/kubectl.yml +++ b/tests/ansible/integration/stub_connections/kubectl.yml @@ -7,7 +7,7 @@ - meta: end_play when: - - ansible_version.full is version('2.5', '<', strict=True) + - ansible_version_major_minor is version('2.5', '<', strict=True) - custom_python_detect_environment: vars: diff --git a/tests/ansible/integration/stub_connections/setns_lxc.yml b/tests/ansible/integration/stub_connections/setns_lxc.yml index f7654ad8..dc7340a8 100644 --- a/tests/ansible/integration/stub_connections/setns_lxc.yml +++ b/tests/ansible/integration/stub_connections/setns_lxc.yml @@ -32,7 +32,7 @@ localhost args: chdir: ../.. - warn: "{{ False if ansible_version.full is version('2.10', '<=', strict=True) else omit }}" + warn: "{{ False if ansible_version_major_minor is version('2.10', '<=', strict=True) else omit }}" register: result - assert: diff --git a/tests/ansible/integration/stub_connections/setns_lxd.yml b/tests/ansible/integration/stub_connections/setns_lxd.yml index c461845e..127941f0 100644 --- a/tests/ansible/integration/stub_connections/setns_lxd.yml +++ b/tests/ansible/integration/stub_connections/setns_lxd.yml @@ -32,7 +32,7 @@ localhost args: chdir: ../.. - warn: "{{ False if ansible_version.full is version('2.10', '<=', strict=True) else omit }}" + warn: "{{ False if ansible_version_major_minor is version('2.10', '<=', strict=True) else omit }}" register: result - assert: diff --git a/tests/ansible/integration/transport_config/password.yml b/tests/ansible/integration/transport_config/password.yml index b447b8b6..34ed1a41 100644 --- a/tests/ansible/integration/transport_config/password.yml +++ b/tests/ansible/integration/transport_config/password.yml @@ -11,11 +11,13 @@ - assert_equal: left: out.result[0].kwargs.password right: null - when: ansible_version.full is version('2.18.999', '>=', strict=True) + when: + - ansible_version_major_minor is version('2.19', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" # actually null, but assert_equal limitation - when: ansible_version.full is version('2.18.999', '<', strict=True) + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) tags: - mitogen_only @@ -31,11 +33,13 @@ - assert_equal: left: out.result[1].kwargs.password right: null - when: ansible_version.full is version('2.18.999', '>=', strict=True) + when: + - ansible_version_major_minor is version('2.19', '>=', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "" - when: ansible_version.full is version('2.18.999', '<', strict=True) + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) tags: - mitogen_only @@ -61,11 +65,13 @@ - assert_equal: left: out.result[0].kwargs.password right: null - when: ansible_version.full is version('2.18.999', '>=', strict=True) + when: + - ansible_version_major_minor is version('2.19', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" - when: ansible_version.full is version('2.18.999', '<', strict=True) + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "ansi-ssh-pass" @@ -94,11 +100,13 @@ - assert_equal: left: out.result[0].kwargs.password right: null - when: ansible_version.full is version('2.18.999', '>=', strict=True) + when: + - ansible_version_major_minor is version('2.19', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" - when: ansible_version.full is version('2.18.999', '<', strict=True) + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "ansi-pass" @@ -127,11 +135,13 @@ - assert_equal: left: out.result[0].kwargs.password right: null - when: ansible_version.full is version('2.18.999', '>=', strict=True) + when: + - ansible_version_major_minor is version('2.19', '>=', strict=True) - assert_equal: left: out.result[0].kwargs.password right: "" - when: ansible_version.full is version('2.18.999', '<', strict=True) + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) - assert_equal: left: out.result[1].kwargs.password right: "c.b.a" diff --git a/tests/ansible/integration/transport_config/python_path.yml b/tests/ansible/integration/transport_config/python_path.yml index 21f3928c..b8bb286b 100644 --- a/tests/ansible/integration/transport_config/python_path.yml +++ b/tests/ansible/integration/transport_config/python_path.yml @@ -12,7 +12,7 @@ - include_tasks: ../_mitogen_only.yml - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - {mitogen_get_stack: {}, register: out} - assert_equal: left: out.result[0].kwargs.python_path @@ -27,7 +27,7 @@ - include_tasks: ../_mitogen_only.yml - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - {mitogen_get_stack: {}, register: out} - assert_equal: left: out.result[0].kwargs.python_path @@ -57,7 +57,7 @@ - include_tasks: ../_mitogen_only.yml - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - {mitogen_get_stack: {}, register: out} - assert_equal: left: out.result[0].kwargs.python_path @@ -87,7 +87,7 @@ - include_tasks: ../_mitogen_only.yml - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - {mitogen_get_stack: {}, register: out} - assert_equal: left: out.result[0].kwargs.python_path diff --git a/tests/ansible/regression/issue_1066__add_host__host_key_checking.yml b/tests/ansible/regression/issue_1066__add_host__host_key_checking.yml index dd754f84..cdc50fc3 100644 --- a/tests/ansible/regression/issue_1066__add_host__host_key_checking.yml +++ b/tests/ansible/regression/issue_1066__add_host__host_key_checking.yml @@ -31,7 +31,7 @@ # FIXME https://github.com/mitogen-hq/mitogen/issues/1096 - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - meta: reset_connection # The host key might be in ~/.ssh/known_hosts. If it's removed then no @@ -65,7 +65,7 @@ # ansible_host_key_checking don't work on Vanilla Ansible 2.10, even for # static inventory hosts (ansible/ansible#49254, ansible/ansible#73708). when: - - ansible_version.full is version('2.11', '>=', strict=True) + - ansible_version_major_minor is version('2.11', '>=', strict=True) or is_mitogen tags: - issue_1066 diff --git a/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml b/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml index 92bdfd7e..550a7f4c 100644 --- a/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml +++ b/tests/ansible/regression/issue_109__target_has_old_ansible_installed.yml @@ -7,7 +7,7 @@ tasks: - meta: end_play when: - - ansible_version.full is version('2.6', '<', strict=True) + - ansible_version_major_minor is version('2.6', '<', strict=True) - name: Copy the naughty ansible into place copy: diff --git a/tests/ansible/regression/issue_590__sys_modules_crap.yml b/tests/ansible/regression/issue_590__sys_modules_crap.yml index 2c2262f4..f2bda94c 100644 --- a/tests/ansible/regression/issue_590__sys_modules_crap.yml +++ b/tests/ansible/regression/issue_590__sys_modules_crap.yml @@ -3,7 +3,7 @@ tasks: - meta: end_play when: - - ansible_version.full is version('2.8', '<', strict=True) + - ansible_version_major_minor is version('2.8', '<', strict=True) - custom_python_uses_distro: register: out diff --git a/tests/ansible/regression/issue_655__wait_for_connection_error.yml b/tests/ansible/regression/issue_655__wait_for_connection_error.yml index 506d5516..297b6043 100644 --- a/tests/ansible/regression/issue_655__wait_for_connection_error.yml +++ b/tests/ansible/regression/issue_655__wait_for_connection_error.yml @@ -22,7 +22,7 @@ when: # Ansible 10 (ansible-core 2.17+) require Python 3.7+ on targets. # On CentOS 8 /usr/libexec/platform-python is Python 3.6 - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) - name: set up test container and run tests inside it block: diff --git a/tests/ansible/regression/issue_766__get_with_context.yml b/tests/ansible/regression/issue_766__get_with_context.yml index 09556939..5dae142f 100644 --- a/tests/ansible/regression/issue_766__get_with_context.yml +++ b/tests/ansible/regression/issue_766__get_with_context.yml @@ -25,15 +25,15 @@ # with Ansible 4 (ansible-core 2.11) & associated collections. # ansible.module_utils.connection.ConnectionError: Method not found # https://github.com/mitogen-hq/mitogen/actions/runs/12854359099/job/35838635886 - - ansible_version.full is version('2.11', '>=', strict=True) - - ansible_version.full is version('2.12', '<', strict=True) + - ansible_version_major_minor is version('2.11', '>=', strict=True) + - ansible_version_major_minor is version('2.12', '<', strict=True) - meta: end_play when: # TASK [Get running configuration and state data ] # Error: : Task failed: ActionBase._parse_returned_data() missing 1 required positional argument: 'profile' # https://github.com/ansible-collections/ansible.netcommon/issues/698#issuecomment-2910082548 - - ansible_version.full is version('2.18.999', '>=', strict=True) + - ansible_version_major_minor is version('2.19', '>=', strict=True) - block: - name: Start container diff --git a/tests/ansible/regression/issue_776__load_plugins_called_twice.yml b/tests/ansible/regression/issue_776__load_plugins_called_twice.yml index d482c41c..4a4cf7be 100755 --- a/tests/ansible/regression/issue_776__load_plugins_called_twice.yml +++ b/tests/ansible/regression/issue_776__load_plugins_called_twice.yml @@ -17,7 +17,7 @@ # support Python 2.x on targets. - meta: end_play when: - - ansible_version.full is version('2.17', '>=', strict=True) + - ansible_version_major_minor is version('2.17', '>=', strict=True) roles: - role: package_manager diff --git a/tests/image_prep/_container_setup.yml b/tests/image_prep/_container_setup.yml index 4aa3b46d..b95d67a9 100644 --- a/tests/image_prep/_container_setup.yml +++ b/tests/image_prep/_container_setup.yml @@ -66,7 +66,7 @@ dnf: dnf clean all command: "{{ clean_command[ansible_pkg_mgr] }}" args: - warn: "{{ False if ansible_version.full is version('2.10', '<=', strict=True) else omit }}" + warn: "{{ False if ansible_version_major_minor is version('2.10', '<=', strict=True) else omit }}" - name: Clean up apt package lists shell: rm -rf {{item}}/* diff --git a/tests/image_prep/group_vars/all.yml b/tests/image_prep/group_vars/all.yml index 91ff934d..6545e432 100644 --- a/tests/image_prep/group_vars/all.yml +++ b/tests/image_prep/group_vars/all.yml @@ -1,3 +1,5 @@ +ansible_version_major_minor: "{{ ansible_version.major }}.{{ ansible_version.minor }}" + common_packages: - openssh-server - rsync From 55b0ece0e79ee208e7872452d2830efbae66d9c0 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 19 Jun 2025 12:55:19 +0100 Subject: [PATCH 23/33] CI: Test SSH password authentication without sshpass command Ansible 12 (ansible-core 2.19) has gained support for specifying an SSH password, without requiring `sshpass`. It specifies the environment variable `SSH_ASKPASS` such that `ansible` itself is called. Mitogen is already able to support this. This change provides test coverage of the new feature by not installing `sshpass` on macOS runners. when Ansible 12 is under test. Ubuntu runners come with `sshpass` pre-installed. Required Ansible is also bumped to the latest pre-releases, for relevant fixes. --- .ci/install_sshpass | 18 ++++++++++++++++++ .ci/localhost_ansible_tests.py | 11 ----------- .github/workflows/tests.yml | 4 ++++ docs/changelog.rst | 2 ++ tests/ansible/integration/ssh/password.yml | 9 +++++++++ tox.ini | 6 ++---- 6 files changed, 35 insertions(+), 15 deletions(-) create mode 100755 .ci/install_sshpass diff --git a/.ci/install_sshpass b/.ci/install_sshpass new file mode 100755 index 00000000..05d7ebd6 --- /dev/null +++ b/.ci/install_sshpass @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +VERSION="$1" + +curl \ + --fail \ + --location \ + --no-progress-meter \ + --remote-name \ + "https://downloads.sourceforge.net/project/sshpass/sshpass/${VERSION}/sshpass-${VERSION}.tar.gz" +tar xvf "sshpass-${VERSION}.tar.gz" +cd "sshpass-${VERSION}" +./configure +sudo make install diff --git a/.ci/localhost_ansible_tests.py b/.ci/localhost_ansible_tests.py index 359dc195..9203f120 100755 --- a/.ci/localhost_ansible_tests.py +++ b/.ci/localhost_ansible_tests.py @@ -17,17 +17,6 @@ with ci_lib.Fold('unit_tests'): with ci_lib.Fold('job_setup'): os.chmod(ci_lib.TESTS_SSH_PRIVATE_KEY_FILE, int('0600', 8)) - # NOTE: sshpass v1.06 causes errors so pegging to 1.05 -> "msg": "Error when changing password","out": "passwd: DS error: eDSAuthFailed\n", - # there's a checksum error with "brew install http://git.io/sshpass.rb" though, so installing manually - if not ci_lib.exists_in_path('sshpass'): - subprocess.check_call( - "curl -O -L https://sourceforge.net/projects/sshpass/files/sshpass/1.05/sshpass-1.05.tar.gz && \ - tar xvf sshpass-1.05.tar.gz && \ - cd sshpass-1.05 && \ - ./configure && \ - sudo make install", - shell=True, - ) with ci_lib.Fold('machine_prep'): diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b48576ab..ac00d84b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -274,9 +274,11 @@ jobs: tox_env: py313-mode_mitogen - name: Loc_313_11 + sshpass_version: "1.10" tox_env: py313-mode_localhost-ansible11 - name: Van_313_11 + sshpass_version: "1.10" tox_env: py313-mode_localhost-ansible11-strategy_linear - name: Loc_313_12 @@ -317,6 +319,8 @@ jobs: # GitHub macOS 12 images: python2.7 is installed, but not on $PATH echo "/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7: sys.executable: $(/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 -c 'import sys; print(sys.executable)')" fi + - run: .ci/install_sshpass ${{ matrix.sshpass_version }} + if: ${{ matrix.sshpass_version }} - name: Install tooling run: | set -o errexit -o nounset -o pipefail diff --git a/docs/changelog.rst b/docs/changelog.rst index bd98a835..c7b7ae49 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -36,6 +36,8 @@ to strategy plugins under :gh:issue:`1278`. instead of deprecated `stdout_callback = yaml` * :gh:issue:`1293` CI: Fix ``ansible_version`` comparisons when an Ansible release candidate is under test +* :gh:issue:`1275` CI: Test ``ansible_ssh_password`` behaviour without + ``sshpass`` installed v0.3.25a2 (2025-06-21) diff --git a/tests/ansible/integration/ssh/password.yml b/tests/ansible/integration/ssh/password.yml index 21ab6f15..ca08fa5b 100644 --- a/tests/ansible/integration/ssh/password.yml +++ b/tests/ansible/integration/ssh/password.yml @@ -31,6 +31,11 @@ - assert: that: - ssh_no_password_result.unreachable == True + - >- + ssh_no_password_result.msg is search('SSH password was requested, but none specified') + or ssh_no_password_result.msg is search('SSH password is incorrect') + or ssh_no_password_result.msg is search('Invalid/incorrect password') + or ssh_no_password_result.msg is search('Permission denied \(publickey,password(,keyboard-interactive)?\)') fail_msg: | ssh_no_password_result={{ ssh_no_password_result }} @@ -64,5 +69,9 @@ - assert: that: - ssh_wrong_password_result.unreachable == True + - >- + ssh_wrong_password_result.msg is search('SSH password is incorrect') + or ssh_wrong_password_result.msg is search('Invalid/incorrect password') + or ssh_wrong_password_result.msg is search('Permission denied \(publickey,password(,keyboard-interactive)?\)') fail_msg: | ssh_wrong_password_result={{ ssh_wrong_password_result }} diff --git a/tox.ini b/tox.ini index 3cad99c0..e2714b5e 100644 --- a/tox.ini +++ b/tox.ini @@ -88,10 +88,8 @@ deps = ansible9: ansible~=9.0 ansible10: ansible~=10.0 ansible11: ansible~=11.0 - ansible12: ansible>=12.0a - # Avoid yaml callback bug, https://github.com/mitogen-hq/mitogen/issues/1284 - ansible12: ansible!=12.0a6 - ansible12: ansible-core!=2.19b6 + ansible12: ansible>=12.0a7 + ansible12: ansible-core>=2.19rc1 install_command = python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages} commands_pre = From c1296b5d75db3fb4654062518d12151af20c17ac Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 2 Jul 2025 11:29:37 +0100 Subject: [PATCH 24/33] ansible_mitogen: Support ANSIBLE_SSH_VERBOSITY with Ansible >= 12 In vanilla Ansible >= 12 (ansible-core 2.19) - ssh connection plugin `verbosity` controls `ssh [-v[v[v]]]` - config option `DEFAULT_VERBOSITY` controls whether that output is displayed In vanilla Ansible <= 11 (ansible-core <= 2.18) - `DEFAULT_VERBOSITY` controls both `ssh` verbosity & display verbositty As of this change - Mitogen + Ansible >= 12 behaviour matches vanilla Ansible >= 12. - Mitogen + Ansible <= 11 behaviour remains unchanged - `DEFAULT_VERBOSITY` only controls display verbosity. - Mitogen + Ansible respect the Ansible variable `mitogen_ssh_debug_level` I've chosen not to retroactively replicate the old vanilla Ansible behaviour in Mitogen + Ansible <= 11 cases. I'm pretty sure it was an oversight, rather than a design choice, but Ansible+Mitogen with `ANSIBLE_VERBOSITY=3` is already very verbose. fixes #1282 See - https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-verbosity - https://docs.ansible.com/ansible/devel/collections/ansible/builtin/ssh_connection.html#parameter-verbosity --- ansible_mitogen/connection.py | 2 +- ansible_mitogen/transport_config.py | 27 ++++++++++++ docs/changelog.rst | 2 + .../delegate_to_template.yml | 4 +- .../stack_construction.yml | 14 +++---- tests/ansible/integration/ssh/all.yml | 1 + tests/ansible/integration/ssh/verbosity.yml | 41 +++++++++++++++++++ 7 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 tests/ansible/integration/ssh/verbosity.yml diff --git a/ansible_mitogen/connection.py b/ansible_mitogen/connection.py index 3e02b971..03856f4d 100644 --- a/ansible_mitogen/connection.py +++ b/ansible_mitogen/connection.py @@ -147,7 +147,7 @@ def _connect_ssh(spec): 'ssh_path': spec.ssh_executable(), 'connect_timeout': spec.timeout(), 'ssh_args': spec.ssh_args(), - 'ssh_debug_level': spec.mitogen_ssh_debug_level(), + 'ssh_debug_level': spec.verbosity(), 'remote_name': get_remote_name(spec), 'keepalive_count': ( spec.mitogen_ssh_keepalive_count() or 10 diff --git a/ansible_mitogen/transport_config.py b/ansible_mitogen/transport_config.py index 22afd197..3d5fac3c 100644 --- a/ansible_mitogen/transport_config.py +++ b/ansible_mitogen/transport_config.py @@ -406,6 +406,12 @@ class Spec(with_metaclass(abc.ABCMeta, object)): Value of "ansible_doas_exe" variable. """ + @abc.abstractmethod + def verbosity(self): + """ + How verbose to make logging or diagnostics output. + """ + class PlayContextSpec(Spec): """ @@ -601,6 +607,17 @@ class PlayContextSpec(Spec): os.environ.get('ANSIBLE_DOAS_EXE') ) + def verbosity(self): + try: + verbosity = self._connection.get_option('verbosity', hostvars=self._task_vars) + except KeyError: + verbosity = self.mitogen_ssh_debug_level() + + if verbosity: + return int(verbosity) + + return 0 + class MitogenViaSpec(Spec): """ @@ -836,3 +853,13 @@ class MitogenViaSpec(Spec): self._host_vars.get('ansible_doas_exe') or os.environ.get('ANSIBLE_DOAS_EXE') ) + + def verbosity(self): + verbosity = self._host_vars.get('ansible_ssh_verbosity') + if verbosity is None: + verbosity = self.mitogen_ssh_debug_level() + + if verbosity: + return int(verbosity) + + return 0 diff --git a/docs/changelog.rst b/docs/changelog.rst index c7b7ae49..f2de5561 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -38,6 +38,8 @@ to strategy plugins under :gh:issue:`1278`. release candidate is under test * :gh:issue:`1275` CI: Test ``ansible_ssh_password`` behaviour without ``sshpass`` installed +* :gh:issue:`1282` :mod:`ansible_mitogen`: Support ``ANSIBLE_SSH_VERBOSITY`` + with Ansible 12 v0.3.25a2 (2025-06-21) diff --git a/tests/ansible/integration/connection_delegation/delegate_to_template.yml b/tests/ansible/integration/connection_delegation/delegate_to_template.yml index 4cff57e1..8cd50f98 100644 --- a/tests/ansible/integration/connection_delegation/delegate_to_template.yml +++ b/tests/ansible/integration/connection_delegation/delegate_to_template.yml @@ -50,7 +50,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'alias-user', }, @@ -78,7 +78,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'ansible-cfg-remote-user', }, diff --git a/tests/ansible/integration/connection_delegation/stack_construction.yml b/tests/ansible/integration/connection_delegation/stack_construction.yml index 1cfd34ef..58abac7b 100644 --- a/tests/ansible/integration/connection_delegation/stack_construction.yml +++ b/tests/ansible/integration/connection_delegation/stack_construction.yml @@ -87,7 +87,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'alias-user', }, @@ -131,7 +131,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'alias-user', }, @@ -186,7 +186,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'ansible-cfg-remote-user', }, @@ -230,7 +230,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'alias-user', }, @@ -258,7 +258,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'ansible-cfg-remote-user', }, @@ -312,7 +312,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'newuser-normal-normal-user', }, @@ -357,7 +357,7 @@ -o, PubkeyAcceptedKeyTypes=+ssh-rsa, -o, UserKnownHostsFile=/dev/null, ], - 'ssh_debug_level': null, + 'ssh_debug_level': 0, 'ssh_path': 'ssh', 'username': 'alias-user', }, diff --git a/tests/ansible/integration/ssh/all.yml b/tests/ansible/integration/ssh/all.yml index 20031704..6dbf945f 100644 --- a/tests/ansible/integration/ssh/all.yml +++ b/tests/ansible/integration/ssh/all.yml @@ -8,3 +8,4 @@ - import_playbook: templated_by_play_taskvar.yml - import_playbook: templated_by_task_keyword.yml - import_playbook: variables.yml +- import_playbook: verbosity.yml diff --git a/tests/ansible/integration/ssh/verbosity.yml b/tests/ansible/integration/ssh/verbosity.yml new file mode 100644 index 00000000..2bf1ed10 --- /dev/null +++ b/tests/ansible/integration/ssh/verbosity.yml @@ -0,0 +1,41 @@ +# Ansible >= 12 (ansible-core >= 2.19) adds SSH connection `verbosity` property. +# Ansible <= 11 (ansible-core <= 2.18) applies ANSIBLE_VERBOSITY -> ssh. + +- name: integration/ssh/verbosity.yml + hosts: test-targets + gather_facts: false + tasks: + - meta: end_play + when: + - ansible_version_major_minor is version('2.19', '<', strict=True) + + - name: Exercise ssh verbosity + connection: local + environment: + ANSIBLE_CALLBACK_RESULT_FORMAT: json + ANSIBLE_LOAD_CALLBACK_PLUGINS: "false" + ANSIBLE_SSH_VERBOSITY: 3 + ANSIBLE_STRATEGY: "{{ lookup('env', 'ANSIBLE_STRATEGY') | mandatory }}" + ANSIBLE_VERBOSITY: 3 + vars: + ansible_python_interpreter: "{{ ansible_playbook_python }}" + command: + cmd: + ansible + {% for inv in ansible_inventory_sources %} + -i "{{ inv }}" + {% endfor %} + "{{ inventory_hostname }}" + -m ping + chdir: ../.. + register: out + changed_when: false + check_mode: false + + - name: Verify ssh -vvv output is included + assert: + that: + - >- + out.stdout is search('debug1: Reading configuration data') + fail_msg: | + out={{ out }} From 945933854ab6525be492a6151354fe742422910c Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 2 Jul 2025 21:36:53 +0100 Subject: [PATCH 25/33] Prepare v0.3.25a3 --- docs/changelog.rst | 4 ++++ mitogen/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f2de5561..2593fbd2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,10 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. + +v0.3.25a3 (2025-07-02) +---------------------- + * :gh:issue:`1285` CI: use `result_format = yaml` for Ansible test output, instead of deprecated `stdout_callback = yaml` * :gh:issue:`1293` CI: Fix ``ansible_version`` comparisons when an Ansible diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..5e0bbe0e 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25, 'a3') #: This is :data:`False` in slave contexts. Previously it was used to prevent From 809094303116c399e1989aef1466b4c125483b27 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 2 Jul 2025 21:37:37 +0100 Subject: [PATCH 26/33] Resume 0.3.25dev --- mitogen/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 5e0bbe0e..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'a3') +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From 8ccaa48d2a10ef02ccc2ac883e05702378f52fa8 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 2 Jul 2025 22:25:11 +0100 Subject: [PATCH 27/33] Correct v0.3.25a3 __version__ tuple --- mitogen/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..042a0f12 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25, 'a', 3) #: This is :data:`False` in slave contexts. Previously it was used to prevent From d4adce5d7eceeb5fb1d719e5ca5a1103ee463df5 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Wed, 2 Jul 2025 22:25:31 +0100 Subject: [PATCH 28/33] Resume 0.3.25dev --- mitogen/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 042a0f12..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'a', 3) +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From d818b201b3e4126bc9d3a43748b6db24b178e971 Mon Sep 17 00:00:00 2001 From: Fabio Greco <29181278+feteu@users.noreply.github.com> Date: Sat, 5 Jul 2025 10:46:55 +0200 Subject: [PATCH 29/33] Update missing host key checking argument in docs/ansible_detailed.rst The arguments ansible_ssh_host_key_checking and ansible_host_key_checking were missing in the documentation, while being introduced with the commit "https://github.com/moreati/mitogen/commit/57498453249c4c938fb9c3e6c45b9051f7e5ed47" --- docs/ansible_detailed.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/ansible_detailed.rst b/docs/ansible_detailed.rst index 703e9b4b..06aa4955 100644 --- a/docs/ansible_detailed.rst +++ b/docs/ansible_detailed.rst @@ -1018,6 +1018,8 @@ Like the :ans:conn:`ssh` except connection delegation is supported. * ``ansible_ssh_private_key_file`` * ``ansible_ssh_pass``, ``ansible_ssh_password``, ``ansible_password`` (default: assume passwordless) +* ``ansible_ssh_host_key_checking``, ``ansible_host_key_checking`` (default: + :data:`True`) * ``ssh_args``, ``ssh_common_args``, ``ssh_extra_args`` * ``mitogen_mask_remote_name``: if :data:`True`, mask the identity of the Ansible controller process on remote machines. To simplify diagnostics, From 573303ac7336febb8e27edf253c507e998b66130 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Mon, 14 Jul 2025 23:13:25 +0100 Subject: [PATCH 30/33] CI: Switch to archived Debian 10 (buster) apt repository The Debian project recently removed this EOL version from the live mirrors. --- docs/changelog.rst | 2 ++ tests/ansible/hosts/group_vars/debian10.yml | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 tests/ansible/hosts/group_vars/debian10.yml diff --git a/docs/changelog.rst b/docs/changelog.rst index 2593fbd2..fbe95aab 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,8 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. +* :gh:issue:`1303` CI: Switch to archived Debian 10 (buster) apt repository + v0.3.25a3 (2025-07-02) ---------------------- diff --git a/tests/ansible/hosts/group_vars/debian10.yml b/tests/ansible/hosts/group_vars/debian10.yml new file mode 100644 index 00000000..c6c0a268 --- /dev/null +++ b/tests/ansible/hosts/group_vars/debian10.yml @@ -0,0 +1,4 @@ +package_manager_repos: + - dest: /etc/apt/sources.list + content: | + deb http://archive.debian.org/debian buster main contrib non-free From 2ae35c8a15d8f778510d47ef58f1f5b834eb1e2b Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Mon, 21 Jul 2025 21:45:24 +0100 Subject: [PATCH 31/33] Prepare v0.3.25b1 --- docs/changelog.rst | 4 ++++ mitogen/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index fbe95aab..3f475e60 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -32,6 +32,10 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. + +v0.3.25b1 (2025-07-21) +---------------------- + * :gh:issue:`1303` CI: Switch to archived Debian 10 (buster) apt repository diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..4c142e64 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25, 'b', 1) #: This is :data:`False` in slave contexts. Previously it was used to prevent From fa22aa1c8eedb410830f1815a7d77b47b9333c5a Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Mon, 21 Jul 2025 21:46:06 +0100 Subject: [PATCH 32/33] Resume 0.3.25dev --- mitogen/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitogen/__init__.py b/mitogen/__init__.py index 4c142e64..baa59b45 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'b', 1) +__version__ = (0, 3, 25, 'dev') #: This is :data:`False` in slave contexts. Previously it was used to prevent From dfafa1430ee88795db25d835bcd00e4276ef48e8 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Tue, 29 Jul 2025 17:06:23 +0100 Subject: [PATCH 33/33] Prepare v0.3.25 --- docs/changelog.rst | 6 ++++-- mitogen/__init__.py | 2 +- tox.ini | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 3f475e60..aa3d3634 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,8 +18,8 @@ To avail of fixes in an unreleased version, please download a ZIP file `directly from GitHub `_. -In progress (unreleased) ------------------------- +v0.3.25 (2025-07-29) +-------------------- Ansible 12 has deprecated third-party strategy plugins. This is currently how Mitogen integrates with Ansible (e.g. `ANSIBLE_STRATEGY=mitogen_linear`). @@ -32,6 +32,8 @@ Running Ansible 12 + Mitogen will currently print a deprecation warning Ansible + Mitogen will still work for now. Mitogen is considering alternatives to strategy plugins under :gh:issue:`1278`. +* :gh:issue:`1258` Ansible 12 (ansible-core 2.19) support + v0.3.25b1 (2025-07-21) ---------------------- diff --git a/mitogen/__init__.py b/mitogen/__init__.py index baa59b45..7133b66c 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -35,7 +35,7 @@ be expected. On the slave, it is built dynamically during startup. #: Library version as a tuple. -__version__ = (0, 3, 25, 'dev') +__version__ = (0, 3, 25) #: This is :data:`False` in slave contexts. Previously it was used to prevent diff --git a/tox.ini b/tox.ini index e2714b5e..569d9936 100644 --- a/tox.ini +++ b/tox.ini @@ -88,8 +88,7 @@ deps = ansible9: ansible~=9.0 ansible10: ansible~=10.0 ansible11: ansible~=11.0 - ansible12: ansible>=12.0a7 - ansible12: ansible-core>=2.19rc1 + ansible12: ansible>=12.0.0b2 install_command = python -m pip --no-python-version-warning --disable-pip-version-check install {opts} {packages} commands_pre =