Skip to content

Commit

Permalink
[module_utils.distro] Fall back to bundled (ansible#74229)
Browse files Browse the repository at this point in the history
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 ansible#74228

Signed-off-by: Rick Elrod <[email protected]>

* nuke playbook test file

Signed-off-by: Rick Elrod <[email protected]>

* test fixes

Signed-off-by: Rick Elrod <[email protected]>
  • Loading branch information
relrod authored Apr 13, 2021
1 parent aae5bc5 commit fa0bccf
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 0 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/nonstandard-distro-fallback.yml
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 10 additions & 0 deletions lib/ansible/module_utils/distro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,25 @@


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
1 change: 1 addition & 0 deletions test/integration/targets/module_utils_distro/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shippable/posix/group3
2 changes: 2 additions & 0 deletions test/integration/targets/module_utils_distro/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dependencies:
- setup_remote_tmp_dir
24 changes: 24 additions & 0 deletions test/integration/targets/module_utils_distro/runme.sh
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit fa0bccf

Please sign in to comment.