From 134680151cb84cefcbeeb2d7baa3bcf30c07832d Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Fri, 19 Feb 2021 15:08:24 +0000 Subject: [PATCH] Rewrite ansible version checking - assure we check that ansible python module and ansible cli versions are the same - print ansible version alongside ansible-lint version - fix version version comparison from <= to < Fixes: #1378 --- src/ansiblelint/__main__.py | 15 +++++-- src/ansiblelint/_prerun.py | 78 ++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/ansiblelint/__main__.py b/src/ansiblelint/__main__.py index c9fc6888631..e9215ff1124 100755 --- a/src/ansiblelint/__main__.py +++ b/src/ansiblelint/__main__.py @@ -42,6 +42,7 @@ render_yaml, ) from ansiblelint.config import options, used_old_tags +from ansiblelint.constants import ANSIBLE_MISSING_RC from ansiblelint.file_utils import cwd from ansiblelint.skip_utils import normalize_tag from ansiblelint.version import __version__ @@ -75,9 +76,15 @@ def initialize_options(arguments: List[str]): new_options.cwd = pathlib.Path.cwd() if new_options.version: - print('ansible-lint {ver!s}'.format(ver=__version__)) - # assure we fail if ansible is missing, even for version printing - check_ansible_presence() + ansible_version, err = check_ansible_presence() + print( + 'ansible-lint {ver!s} using ansible {ansible_ver!s}'.format( + ver=__version__, ansible_ver=ansible_version + ) + ) + if err: + print(err, file=sys.stderr) + sys.exit(ANSIBLE_MISSING_RC) sys.exit(0) if new_options.colored is None: @@ -163,7 +170,7 @@ def main(argv: List[str] = None) -> int: app = App(options=options) prepare_environment() - check_ansible_presence() + check_ansible_presence(exit_on_error=True) # On purpose lazy-imports to avoid pre-loading Ansible # pylint: disable=import-outside-toplevel diff --git a/src/ansiblelint/_prerun.py b/src/ansiblelint/_prerun.py index 30c8bbe954a..5b2ddb5a34a 100644 --- a/src/ansiblelint/_prerun.py +++ b/src/ansiblelint/_prerun.py @@ -3,7 +3,7 @@ import re import subprocess import sys -from typing import List, Optional +from typing import List, Optional, Tuple from packaging import version @@ -29,30 +29,62 @@ """ -def check_ansible_presence() -> None: - """Assures we stop execution if Ansible is missing.""" +def check_ansible_presence(exit_on_error=False) -> Tuple[str, str]: + """Assures we stop execution if Ansible is missing or outdated. + + Returne found version and an optional exception if something wrong + was detected. + """ + err = "" failed = False - try: - # pylint: disable=import-outside-toplevel - from ansible import release - - if version.parse(release.__version__) <= version.parse(ANSIBLE_MIN_VERSION): - failed = True - except (ImportError, ModuleNotFoundError, UnboundLocalError) as e: - failed = True - __version__ = "none" - print(e, file=sys.stderr) - if failed: - print( - "FATAL: ansible-lint requires a version of Ansible package" - " >= %s, but %s was found. " - "Please install a compatible version using the same python interpreter. See " - "https://docs.ansible.com/ansible/latest/installation_guide" - "/intro_installation.html#installing-ansible-with-pip" - % (ANSIBLE_MIN_VERSION, __version__), - file=sys.stderr, - ) + ansible_cli_version = "" + result = subprocess.run( + args=["ansible", "--version"], + stdout=subprocess.PIPE, + universal_newlines=True, + check=False, + ) + if result.returncode != 0: + err = "FATAL: Unable to retrieve ansible cli version: %s" % result.stdout + else: + match = re.match(r"^ansible ([^\s]+)", result.stdout) + if not match: + err = "FATAL: Unable parse ansible cli version: %s" % result.stdout + else: + ansible_cli_version = match.group(1) + try: + # pylint: disable=import-outside-toplevel + from ansible.release import __version__ as ansible_module_version + + if version.parse(ansible_module_version) < version.parse( + ANSIBLE_MIN_VERSION + ): + failed = True + except (ImportError, ModuleNotFoundError) as e: + failed = True + ansible_module_version = "none" + err += f"{e}\n" + if failed: + err += ( + "FATAL: ansible-lint requires a version of Ansible package" + " >= %s, but %s was found. " + "Please install a compatible version using the same python interpreter. See " + "https://docs.ansible.com/ansible/latest/installation_guide" + "/intro_installation.html#installing-ansible-with-pip" + % (ANSIBLE_MIN_VERSION, ansible_module_version) + ) + + elif ansible_cli_version != ansible_module_version: + err = ( + f"FATAL: Ansible CLI ({ansible_cli_version}) and python module" + f" ({ansible_module_version}) versions do not match. This " + "indicates a broken execution environment." + ) + + if exit_on_error and err: + print(err, file=sys.stderr) sys.exit(ANSIBLE_MISSING_RC) + return ansible_cli_version, err def prepare_environment() -> None: