Skip to content

Commit

Permalink
Rewrite ansible version checking (#1383)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
ssbarnea committed Feb 20, 2021
1 parent 31663a6 commit d3ab2af
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 26 deletions.
15 changes: 11 additions & 4 deletions src/ansiblelint/__main__.py
Expand Up @@ -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__
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
85 changes: 63 additions & 22 deletions src/ansiblelint/_prerun.py
Expand Up @@ -3,7 +3,8 @@
import re
import subprocess
import sys
from typing import List, Optional
from functools import lru_cache
from typing import List, Optional, Tuple

from packaging import version

Expand All @@ -29,30 +30,70 @@
"""


def check_ansible_presence() -> None:
"""Assures we stop execution if Ansible is missing."""
failed = False
try:
# pylint: disable=import-outside-toplevel
from ansible import release
def check_ansible_presence(exit_on_error=False) -> Tuple[str, str]:
"""Assures we stop execution if Ansible is missing or outdated.
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,
Returne found version and an optional exception if something wrong
was detected.
"""

@lru_cache()
def _get_ver_err() -> Tuple[str, str]:

err = ""
failed = False
ver = ""
result = subprocess.run(
args=["ansible", "--version"],
stdout=subprocess.PIPE,
universal_newlines=True,
check=False,
)
if result.returncode != 0:
return (
ver,
"FATAL: Unable to retrieve ansible cli version: %s" % result.stdout,
)

match = re.match(r"^ansible ([^\s]+)", result.stdout)
if not match:
return ver, "FATAL: Unable parse ansible cli version: %s" % result.stdout
ver = 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 ver != ansible_module_version:
err = (
f"FATAL: Ansible CLI ({ver}) and python module"
f" ({ansible_module_version}) versions do not match. This "
"indicates a broken execution environment."
)
return ver, err

ver, err = _get_ver_err()
if exit_on_error and err:
print(err, file=sys.stderr)
sys.exit(ANSIBLE_MISSING_RC)
return ver, err


def prepare_environment() -> None:
Expand Down

0 comments on commit d3ab2af

Please sign in to comment.