diff --git a/ansible_mitogen/loaders.py b/ansible_mitogen/loaders.py index b4b98962..85b6c0e5 100644 --- a/ansible_mitogen/loaders.py +++ b/ansible_mitogen/loaders.py @@ -31,7 +31,8 @@ Stable names for PluginLoader instances across Ansible versions. """ from __future__ import absolute_import -import distutils.version + +import ansible_mitogen.utils __all__ = [ 'action_loader', @@ -42,7 +43,6 @@ __all__ = [ 'strategy_loader', ] -import ansible ANSIBLE_VERSION_MIN = (2, 10) ANSIBLE_VERSION_MAX = (2, 11) @@ -68,10 +68,7 @@ def assert_supported_release(): Throw AnsibleError with a descriptive message in case of being loaded into an unsupported Ansible release. """ - v = ansible.__version__ - if not isinstance(v, tuple): - v = tuple(distutils.version.LooseVersion(v).version) - + v = ansible_mitogen.utils.ansible_version if v[:2] < ANSIBLE_VERSION_MIN: raise ansible.errors.AnsibleError( OLD_VERSION_MSG % (v, ANSIBLE_VERSION_MIN) diff --git a/ansible_mitogen/mixins.py b/ansible_mitogen/mixins.py index 7e7a3ff0..c4d793e8 100644 --- a/ansible_mitogen/mixins.py +++ b/ansible_mitogen/mixins.py @@ -53,6 +53,8 @@ import mitogen.utils import ansible_mitogen.connection import ansible_mitogen.planner import ansible_mitogen.target +import ansible_mitogen.utils + from ansible.module_utils._text import to_text try: @@ -226,7 +228,7 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): with a pipelined call to :func:`ansible_mitogen.target.prune_tree`. """ LOG.debug('_remove_tmp_path(%r)', tmp_path) - if tmp_path is None and ansible.__version__ > '2.6': + if tmp_path is None and ansible_mitogen.utils.ansible_version[:2] >= (2, 6): tmp_path = self._connection._shell.tmpdir # 06f73ad578d if tmp_path is not None: self._connection.get_chain().call_no_reply( @@ -335,7 +337,7 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): def _set_temp_file_args(self, module_args, wrap_async): # Ansible>2.5 module_utils reuses the action's temporary directory if # one exists. Older versions error if this key is present. - if ansible.__version__ > '2.5': + if ansible_mitogen.utils.ansible_version[:2] >= (2, 5): if wrap_async: # Sharing is not possible with async tasks, as in that case, # the directory must outlive the action plug-in. @@ -346,7 +348,7 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): # If _ansible_tmpdir is unset, Ansible>2.6 module_utils will use # _ansible_remote_tmp as the location to create the module's temporary # directory. Older versions error if this key is present. - if ansible.__version__ > '2.6': + if ansible_mitogen.utils.ansible_version[:2] >= (2, 6): module_args['_ansible_remote_tmp'] = ( self._connection.get_good_temp_dir() ) @@ -393,7 +395,7 @@ class ActionModuleMixin(ansible.plugins.action.ActionBase): ) ) - if tmp and ansible.__version__ < '2.5' and delete_remote_tmp: + if tmp and delete_remote_tmp and ansible_mitogen.utils.ansible_version[:2] < (2, 5): # Built-in actions expected tmpdir to be cleaned up automatically # on _execute_module(). self._remove_tmp_path(tmp) diff --git a/ansible_mitogen/plugins/connection/mitogen_kubectl.py b/ansible_mitogen/plugins/connection/mitogen_kubectl.py index 44d3b50a..7f99376d 100644 --- a/ansible_mitogen/plugins/connection/mitogen_kubectl.py +++ b/ansible_mitogen/plugins/connection/mitogen_kubectl.py @@ -45,17 +45,11 @@ import ansible_mitogen.connection import ansible_mitogen.loaders -_class = ansible_mitogen.loaders.connection_loader__get( +_get_result = ansible_mitogen.loaders.connection_loader__get( 'kubectl', class_only=True, ) -if _class: - kubectl = sys.modules[_class.__module__] - del _class -else: - kubectl = None - class Connection(ansible_mitogen.connection.Connection): transport = 'kubectl' @@ -66,13 +60,19 @@ class Connection(ansible_mitogen.connection.Connection): ) def __init__(self, *args, **kwargs): - if kubectl is None: + if not _get_result: raise AnsibleConnectionFailure(self.not_supported_msg) super(Connection, self).__init__(*args, **kwargs) def get_extra_args(self): + try: + # Ansible < 2.10, _get_result is the connection class + connection_options = _get_result.connection_options + except AttributeError: + # Ansible >= 2.10, _get_result is a get_with_context_result + connection_options = _get_result.object.connection_options parameters = [] - for key, option in iteritems(kubectl.CONNECTION_OPTIONS): + for key, option in iteritems(connection_options): if self.get_task_var('ansible_' + key) is not None: parameters += [ option, self.get_task_var('ansible_' + key) ] diff --git a/ansible_mitogen/target.py b/ansible_mitogen/target.py index 652b5adc..7b10e163 100644 --- a/ansible_mitogen/target.py +++ b/ansible_mitogen/target.py @@ -144,7 +144,7 @@ def subprocess__Popen__close_fds(self, but): if ( sys.platform.startswith(u'linux') and - sys.version < u'3.0' and + sys.version_info < (3,) and hasattr(subprocess.Popen, u'_close_fds') and not mitogen.is_master ): diff --git a/ansible_mitogen/utils.py b/ansible_mitogen/utils.py new file mode 100644 index 00000000..399c181a --- /dev/null +++ b/ansible_mitogen/utils.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import + +import distutils.version + +import ansible + +__all__ = [ + 'ansible_version', +] + +ansible_version = tuple(distutils.version.LooseVersion(ansible.__version__).version) +del distutils +del ansible diff --git a/docs/changelog.rst b/docs/changelog.rst index 0ac50758..787dd1c4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -27,6 +27,8 @@ v0.3.1.dev0 (unreleased) * :gh:issue:`860` Add initial support for podman connection (w/o Ansible support yet) * :gh:issue:`873` `python -c ...` first stage no longer uses :py:mod:`platform`` to detect the macOS release * :gh:issue:`876` `python -c ...` first stage no longer contains tab characters, to reduce size +* :gh:issue:`878` Continuous Integration tests now correctly perform comparisons of 2 digit versions +* :gh:issue:`878` Kubectl connector fixed with Ansible 2.10 and above v0.3.0 (2021-11-24) diff --git a/tests/ansible/integration/async/result_shell_echo_hi.yml b/tests/ansible/integration/async/result_shell_echo_hi.yml index c0cb283c..6eb31702 100644 --- a/tests/ansible/integration/async/result_shell_echo_hi.yml +++ b/tests/ansible/integration/async/result_shell_echo_hi.yml @@ -46,7 +46,8 @@ that: - async_out.invocation.module_args.stdin == None fail_msg: async_out={{async_out}} - when: ansible_version.full > '2.4' + when: + - ansible_version.full 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 cf33ae56..15e02efa 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', ">=") and + (ansible_version.full is version('2.8', ">=", strict=True) and result1.cmd == "echo alldone;\nsleep 1;\n") or - (ansible_version.full is version('2.8', '<') and + (ansible_version.full is version('2.8', '<', strict=True) and result1.cmd == "echo alldone;\n sleep 1;") - result1.delta|length == 14 - result1.start|length == 26 @@ -58,12 +58,14 @@ - result1.stdout == "alldone" - result1.stdout_lines == ["alldone"] fail_msg: result1={{result1}} - when: ansible_version.full is version('2.8', '>') # ansible#51393 + when: + - ansible_version.full is version('2.8', '>', strict=True) # ansible#51393 - assert: that: - result1.failed == False fail_msg: result1={{result1}} - when: ansible_version.full is version('2.4', '>') + when: + - ansible_version.full 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 af102f19..6eda88aa 100644 --- a/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml +++ b/tests/ansible/integration/async/runner_two_simultaneous_jobs.yml @@ -62,6 +62,7 @@ that: - result2.stdout == 'im_alive' fail_msg: result2={{result2}} - when: ansible_version.full > '2.8' # ansible#51393 + when: + - ansible_version.full 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 ccad928e..1ee38817 100644 --- a/tests/ansible/integration/connection/reset.yml +++ b/tests/ansible/integration/connection/reset.yml @@ -10,10 +10,12 @@ when: not is_mitogen - debug: msg="reset.yml skipped on Ansible<2.5.6" - when: ansible_version.full < '2.5.6' + when: + - ansible_version.full is version('2.5.6', '<', strict=True) - meta: end_play - when: ansible_version.full < '2.5.6' + when: + - ansible_version.full 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 fe29dfed..a36cbf1a 100644 --- a/tests/ansible/integration/connection/reset_become.yml +++ b/tests/ansible/integration/connection/reset_become.yml @@ -6,10 +6,12 @@ gather_facts: false tasks: - debug: msg="reset_become.yml skipped on Ansible<2.5.6" - when: ansible_version.full < '2.5.6' + when: + - ansible_version.full is version('2.5.6', '<', strict=True) - meta: end_play - when: ansible_version.full < '2.5.6' + when: + - ansible_version.full 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 8e048fa4..be083ff9 100644 --- a/tests/ansible/integration/connection_delegation/delegate_to_template.yml +++ b/tests/ansible/integration/connection_delegation/delegate_to_template.yml @@ -20,7 +20,8 @@ when: not is_mitogen - meta: end_play - when: ansible_version.full < '2.4' + when: + - ansible_version.full 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 4f846535..48304120 100644 --- a/tests/ansible/integration/context_service/disconnect_cleanup.yml +++ b/tests/ansible/integration/context_service/disconnect_cleanup.yml @@ -9,7 +9,8 @@ when: not is_mitogen - meta: end_play - when: ansible_version.full < '2.5.6' + when: + - ansible_version.full is version('2.5.6', '<', strict=True) # Start with a clean slate. - mitogen_shutdown_all: diff --git a/tests/ansible/integration/glibc_caches/resolv_conf.yml b/tests/ansible/integration/glibc_caches/resolv_conf.yml index e2894e58..e83ce38e 100644 --- a/tests/ansible/integration/glibc_caches/resolv_conf.yml +++ b/tests/ansible/integration/glibc_caches/resolv_conf.yml @@ -8,36 +8,35 @@ vars: ansible_become_pass: has_sudo_pubkey_password tasks: - - mitogen_test_gethostbyname: name: www.google.com register: out - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] - shell: cp /etc/resolv.conf /tmp/resolv.conf - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] - shell: echo > /etc/resolv.conf - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] - mitogen_test_gethostbyname: name: www.google.com register: out ignore_errors: true - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] - shell: cat /tmp/resolv.conf > /etc/resolv.conf - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] - assert: that: @@ -45,8 +44,8 @@ - '"Name or service not known" in out.msg or "Temporary failure in name resolution" in out.msg' fail_msg: out={{out}} - when: | - ansible_virtualization_type == "docker" and - ansible_python_version > "2.5" + when: + - ansible_facts.virtualization_type == "docker" + - ansible_facts.python.version_info[:2] >= [2, 5] tags: - resolv_conf 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 838b2d86..2dea4f8b 100644 --- a/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml +++ b/tests/ansible/integration/interpreter_discovery/ansible_2_8_tests.yml @@ -132,27 +132,45 @@ that: - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' fail_msg: auto_out={{auto_out}} - when: distro == 'fedora' and distro_version is version('23', '>=') + when: + - distro == 'fedora' + - distro_version is version('23.0', '>=', strict=True) - - name: rhel assertions + - name: rhel < 8 assertions assert: that: - # rhel 6/7 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and distro_version is version('8','<')) or distro_version is version('8','>=') - # rhel 8+ - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/libexec/platform-python' and distro_version is version('8','>=')) or distro_version is version('8','<') + - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' fail_msg: auto_out={{auto_out}} - when: distro in ('redhat', 'centos') + when: + - distro in ('redhat', 'centos') + - distro_version is version('8.0', '<', strict=true) - - name: ubuntu assertions + - name: rhel 8+ assertions assert: that: - # ubuntu < 16 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' and distro_version is version('16.04','<')) or distro_version is version('16.04','>=') - # ubuntu >= 16 - - (auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' and distro_version is version('16.04','>=')) or distro_version is version('16.04','<') + - auto_out.ansible_facts.discovered_interpreter_python == '/usr/libexec/platform-python' fail_msg: auto_out={{auto_out}} - when: distro == 'ubuntu' + when: + - distro in ('redhat', 'centos') + - distro_version is version('8.0', '>=', strict=true) + + - name: ubuntu < 16.04 assertions + assert: + that: + - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python' + fail_msg: auto_out={{auto_out}} + when: + - distro == 'ubuntu' + - distro_version is version('16.04', '<', strict=true) + + - name: ubuntu 16.04+ assertions + assert: + that: + - auto_out.ansible_facts.discovered_interpreter_python == '/usr/bin/python3' + fail_msg: auto_out={{auto_out}} + when: + - distro == 'ubuntu' + - distro_version is version('16.04', '>=', strict=True) - name: mac assertions assert: @@ -163,6 +181,7 @@ always: - meta: clear_facts - when: ansible_version.full is version_compare('2.8.0', '>=') + when: + - ansible_version.full is version_compare('2.8.0', '>=', strict=True) tags: - ansible_2_8_tests 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 6201318a..68230420 100644 --- a/tests/ansible/integration/runner/custom_perl_json_args_module.yml +++ b/tests/ansible/integration/runner/custom_perl_json_args_module.yml @@ -13,11 +13,12 @@ - out.results[0].message == 'I am a perl script! Here is my input.' fail_msg: out={{out}} - - when: ansible_version.full > '2.4' - assert: + - assert: that: - (not out.changed) - (not out.results[0].changed) fail_msg: out={{out}} + when: + - ansible_version.full 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 9c39b1b6..44c39e64 100644 --- a/tests/ansible/integration/runner/custom_perl_want_json_module.yml +++ b/tests/ansible/integration/runner/custom_perl_want_json_module.yml @@ -13,11 +13,12 @@ - out.results[0].message == 'I am a want JSON perl script! Here is my input.' fail_msg: out={{out}} - - when: ansible_version.full > '2.4' - assert: + - assert: that: - (not out.changed) - (not out.results[0].changed) fail_msg: out={{out}} + when: + - ansible_version.full is version('2.4', '>=', strict=True) tags: - custom_perl_want_json_module diff --git a/tests/ansible/integration/stub_connections/kubectl.yml b/tests/ansible/integration/stub_connections/kubectl.yml index e4b881f8..5303f7c7 100644 --- a/tests/ansible/integration/stub_connections/kubectl.yml +++ b/tests/ansible/integration/stub_connections/kubectl.yml @@ -8,7 +8,8 @@ when: not is_mitogen - meta: end_play - when: ansible_version.full < '2.5' + when: + - ansible_version.full is version('2.5', '<', strict=True) - custom_python_detect_environment: vars: diff --git a/tests/ansible/lib/modules/custom_python_detect_environment.py b/tests/ansible/lib/modules/custom_python_detect_environment.py index 9f628a03..3735007d 100644 --- a/tests/ansible/lib/modules/custom_python_detect_environment.py +++ b/tests/ansible/lib/modules/custom_python_detect_environment.py @@ -26,7 +26,15 @@ except NameError: def main(): module = AnsibleModule(argument_spec={}) module.exit_json( - python_version=sys.version[:3], + python={ + 'version': { + 'full': '%i.%i.%i' % sys.version_info[:3], + 'info': list(sys.version_info), + 'major': sys.version_info[0], + 'minor': sys.version_info[1], + 'patch': sys.version_info[2], + }, + }, argv=sys.argv, __file__=__file__, argv_types_correct=all(type(s) is str for s in sys.argv), diff --git a/tests/ansible/lib/modules/custom_python_uses_distro.py b/tests/ansible/lib/modules/custom_python_uses_distro.py index 1fc31b4e..6b3a356b 100644 --- a/tests/ansible/lib/modules/custom_python_uses_distro.py +++ b/tests/ansible/lib/modules/custom_python_uses_distro.py @@ -5,14 +5,22 @@ import ansible from ansible.module_utils.basic import AnsibleModule -if ansible.__version__ > '2.8': +def try_int(s): + try: + return int(s, 10) + except ValueError: + return s + +ansible_version = tuple(try_int(s) for s in ansible.__version__.split('.')) + +if ansible_version[:2] >= (2, 8): from ansible.module_utils import distro else: distro = None def main(): module = AnsibleModule(argument_spec={}) - if ansible.__version__ > '2.8': + if ansible_version[:2] >= (2, 8): module.exit_json(info=distro.info()) else: module.exit_json(info={'id': None}) 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 fdc61c05..1188b6ce 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,8 @@ gather_facts: true tasks: - meta: end_play - when: ansible_version.full < '2.6' + when: + - ansible_version.full is version('2.6', '<', strict=True) # Copy the naughty 'ansible' into place. - copy: diff --git a/tests/ansible/regression/issue_152__virtualenv_python_fails.yml b/tests/ansible/regression/issue_152__virtualenv_python_fails.yml index d3bda041..11f94edd 100644 --- a/tests/ansible/regression/issue_152__virtualenv_python_fails.yml +++ b/tests/ansible/regression/issue_152__virtualenv_python_fails.yml @@ -9,27 +9,31 @@ # Can't use pip module because it can't create virtualenvs, must call it # directly. - shell: virtualenv /tmp/issue_152_virtualenv - when: lout.python_version > '2.6' environment: https_proxy: "{{ lookup('env', 'https_proxy')|default('') }}" no_proxy: "{{ lookup('env', 'no_proxy')|default('') }}" PATH: "{{ lookup('env', 'PATH') }}" + when: + - lout.python.version.full is version('2.7', '>=', strict=True) - custom_python_detect_environment: vars: ansible_python_interpreter: /tmp/issue_152_virtualenv/bin/python register: out - when: lout.python_version > '2.6' + when: + - lout.python.version.full is version('2.7', '>=', strict=True) - assert: that: - out.sys_executable == "/tmp/issue_152_virtualenv/bin/python" fail_msg: out={{out}} - when: lout.python_version > '2.6' + when: + - lout.python.version.full is version('2.7', '>=', strict=True) - file: path: /tmp/issue_152_virtualenv state: absent - when: lout.python_version > '2.6' + when: + - lout.python.version.full is version('2.7', '>=', strict=True) tags: - issue_152 diff --git a/tests/ansible/regression/issue_590__sys_modules_crap.yml b/tests/ansible/regression/issue_590__sys_modules_crap.yml index 52b3ea97..81d9b4b2 100644 --- a/tests/ansible/regression/issue_590__sys_modules_crap.yml +++ b/tests/ansible/regression/issue_590__sys_modules_crap.yml @@ -2,7 +2,8 @@ - hosts: test-targets tasks: - meta: end_play - when: ansible_version.full < '2.8' + when: + - ansible_version.full is version('2.8', '<', strict=True) - custom_python_uses_distro: register: out