[module_utils.distro] Fall back to bundled (#74229)

Change:
- When a "distro" package exists in PYTHONPATH but isn't what we expect,
  fall back to our own vendored one and use it. This prevents a
  traceback if someone has some random thing that provides "distro" but
  isn't actually the "distro" library we need.

Test Plan:
- new tests

Tickets:
- Fixes #74228

Signed-off-by: Rick Elrod <rick@elrod.me>

* nuke playbook test file

Signed-off-by: Rick Elrod <rick@elrod.me>

* test fixes

Signed-off-by: Rick Elrod <rick@elrod.me>
This commit is contained in:
Rick Elrod 2021-04-13 10:27:52 -05:00 committed by GitHub
parent aae5bc5b9e
commit fa0bccf6a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 0 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- module_utils distro - when a 'distro' package/module is in PYTHONPATH but isn't the real 'distro' package/module that we expect, gracefully fall back to our own bundled distro.

View file

@ -32,15 +32,25 @@ _BUNDLED_METADATA = {"pypi_name": "distro", "version": "1.5.0"}
import sys
import types
try:
import distro as _system_distro
except ImportError:
_system_distro = None
else:
# There could be a 'distro' package/module that isn't what we expect, on the
# PYTHONPATH. Rather than erroring out in this case, just fall back to ours.
# We require more functions than distro.id(), but this is probably a decent
# test that we have something we can reasonably use.
if not hasattr(_system_distro, 'id') or \
not isinstance(_system_distro.id, types.FunctionType):
_system_distro = None
if _system_distro:
distro = _system_distro
else:
# Our bundled copy
from ansible.module_utils.distro import _distro as distro
sys.modules['ansible.module_utils.distro'] = distro

View file

@ -0,0 +1 @@
shippable/posix/group3

View file

@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir

View file

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -eux
# Ensure that when a non-distro 'distro' package is in PYTHONPATH, we fallback
# to our bundled one.
new_pythonpath="$OUTPUT_DIR/pythonpath"
mkdir -p "$new_pythonpath/distro"
touch "$new_pythonpath/distro/__init__.py"
export PYTHONPATH="$new_pythonpath:$PYTHONPATH"
# Sanity test to make sure the above worked
set +e
distro_id_fail="$(python -c 'import distro; distro.id' 2>&1)"
set -e
grep -q "AttributeError:.*has no attribute 'id'" <<< "$distro_id_fail"
# ansible.module_utils.common.sys_info imports distro, and itself gets imported
# in DataLoader, so all we have to do to test the fallback is run `ansible`.
ansirun="$(ansible -i ../../inventory -a "echo \$PYTHONPATH" localhost)"
grep -q "$new_pythonpath" <<< "$ansirun"
rm -rf "$new_pythonpath"