mirror of
https://github.com/ansible/ansible
synced 2026-06-19 07:35:52 +00:00
Drop Python 3.12 controller support (#87057)
* Drop Python 3.12 controller support * Remove obsolete code * Remove obsolete centos6 test code * Skip tests on unsupported platforms * Work around lack of Alpine controller support in tests
This commit is contained in:
@@ -99,8 +99,10 @@ stages:
|
|||||||
test: rhel/9.7@3.9
|
test: rhel/9.7@3.9
|
||||||
- name: RHEL 9.7 py312
|
- name: RHEL 9.7 py312
|
||||||
test: rhel/9.7@3.12
|
test: rhel/9.7@3.12
|
||||||
- name: RHEL 10.1
|
- name: RHEL 10.1 py312
|
||||||
test: rhel/10.1
|
test: rhel/10.1@3.12
|
||||||
|
- name: RHEL 10.1 py314
|
||||||
|
test: rhel/10.1@3.14
|
||||||
- name: FreeBSD 14.4
|
- name: FreeBSD 14.4
|
||||||
test: freebsd/14.4
|
test: freebsd/14.4
|
||||||
- name: FreeBSD 15.0
|
- name: FreeBSD 15.0
|
||||||
@@ -119,8 +121,6 @@ stages:
|
|||||||
test: rhel/10.1
|
test: rhel/10.1
|
||||||
- name: FreeBSD 14.4
|
- name: FreeBSD 14.4
|
||||||
test: freebsd/14.4
|
test: freebsd/14.4
|
||||||
- name: FreeBSD 15.0
|
|
||||||
test: freebsd/15.0
|
|
||||||
groups:
|
groups:
|
||||||
- 3
|
- 3
|
||||||
- 4
|
- 4
|
||||||
@@ -128,16 +128,10 @@ stages:
|
|||||||
- template: templates/matrix.yml # context/controller (ansible-test container management)
|
- template: templates/matrix.yml # context/controller (ansible-test container management)
|
||||||
parameters:
|
parameters:
|
||||||
targets:
|
targets:
|
||||||
- name: Alpine 3.23
|
|
||||||
test: alpine/3.23
|
|
||||||
- name: Fedora 44
|
- name: Fedora 44
|
||||||
test: fedora/44
|
test: fedora/44
|
||||||
- name: RHEL 9.7
|
|
||||||
test: rhel/9.7
|
|
||||||
- name: RHEL 10.1
|
- name: RHEL 10.1
|
||||||
test: rhel/10.1
|
test: rhel/10.1
|
||||||
- name: Ubuntu 24.04
|
|
||||||
test: ubuntu/24.04
|
|
||||||
- name: Ubuntu 26.04
|
- name: Ubuntu 26.04
|
||||||
test: ubuntu/26.04
|
test: ubuntu/26.04
|
||||||
groups:
|
groups:
|
||||||
@@ -174,8 +168,6 @@ stages:
|
|||||||
parameters:
|
parameters:
|
||||||
testFormat: linux/{0}
|
testFormat: linux/{0}
|
||||||
targets:
|
targets:
|
||||||
- name: Alpine 3.23
|
|
||||||
test: alpine323
|
|
||||||
- name: Fedora 44
|
- name: Fedora 44
|
||||||
test: fedora44
|
test: fedora44
|
||||||
- name: Ubuntu 24.04
|
- name: Ubuntu 24.04
|
||||||
@@ -211,7 +203,6 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: galaxy/{0}/1
|
testFormat: galaxy/{0}/1
|
||||||
targets:
|
targets:
|
||||||
- test: 3.12
|
|
||||||
- test: 3.13
|
- test: 3.13
|
||||||
- test: 3.14
|
- test: 3.14
|
||||||
- test: 3.15
|
- test: 3.15
|
||||||
@@ -223,7 +214,6 @@ stages:
|
|||||||
nameFormat: Python {0}
|
nameFormat: Python {0}
|
||||||
testFormat: generic/{0}/1
|
testFormat: generic/{0}/1
|
||||||
targets:
|
targets:
|
||||||
- test: 3.12
|
|
||||||
- test: 3.13
|
- test: 3.13
|
||||||
- test: 3.14
|
- test: 3.14
|
||||||
- test: 3.15
|
- test: 3.15
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
major_changes:
|
major_changes:
|
||||||
- ansible - Add support for Python 3.15.
|
- ansible - Add support for Python 3.15.
|
||||||
|
- ansible - Drop support for Python 3.12 on the controller.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ if 1 <= len(sys.argv) <= 2 and os.path.basename(sys.argv[0]) == "ansible" and os
|
|||||||
|
|
||||||
# Used for determining if the system is running a new enough python version
|
# Used for determining if the system is running a new enough python version
|
||||||
# and should only restrict on our documented minimum versions
|
# and should only restrict on our documented minimum versions
|
||||||
_PY_MIN = (3, 12)
|
_PY_MIN = (3, 13)
|
||||||
|
|
||||||
if sys.version_info < _PY_MIN:
|
if sys.version_info < _PY_MIN:
|
||||||
raise SystemExit(
|
raise SystemExit(
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import multiprocessing.resource_tracker
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
@@ -27,19 +26,10 @@ def handle_prompt(prompt: str) -> bool:
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# deprecated: description='Python 3.13 and later support track' python_version='3.12'
|
|
||||||
can_track = sys.version_info[:2] >= (3, 13)
|
|
||||||
kwargs = dict(track=False) if can_track else {}
|
|
||||||
|
|
||||||
# This SharedMemory instance is intentionally not closed or unlinked.
|
# This SharedMemory instance is intentionally not closed or unlinked.
|
||||||
# Closing will occur naturally in the SharedMemory finalizer.
|
# Closing will occur naturally in the SharedMemory finalizer.
|
||||||
# Unlinking is the responsibility of the process which created it.
|
# Unlinking is the responsibility of the process which created it.
|
||||||
shm = SharedMemory(name=os.environ['_ANSIBLE_SSH_ASKPASS_SHM'], **kwargs)
|
shm = SharedMemory(name=os.environ['_ANSIBLE_SSH_ASKPASS_SHM'], track=False)
|
||||||
|
|
||||||
if not can_track:
|
|
||||||
# When track=False is not available, we must unregister explicitly, since it otherwise only occurs during unlink.
|
|
||||||
# This avoids resource tracker noise on stderr during process exit.
|
|
||||||
multiprocessing.resource_tracker.unregister(shm._name, 'shared_memory')
|
|
||||||
|
|
||||||
cfg = json.loads(shm.buf.tobytes().rstrip(b'\x00'))
|
cfg = json.loads(shm.buf.tobytes().rstrip(b'\x00'))
|
||||||
|
|
||||||
|
|||||||
@@ -1672,6 +1672,7 @@ INTERPRETER_PYTHON:
|
|||||||
INTERPRETER_PYTHON_FALLBACK:
|
INTERPRETER_PYTHON_FALLBACK:
|
||||||
name: Ordered list of Python interpreters to check for in discovery
|
name: Ordered list of Python interpreters to check for in discovery
|
||||||
default:
|
default:
|
||||||
|
- python3.15
|
||||||
- python3.14
|
- python3.14
|
||||||
- python3.13
|
- python3.13
|
||||||
- python3.12
|
- python3.12
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ class Connection(ConnectionBase):
|
|||||||
self.cwd = None
|
self.cwd = None
|
||||||
try:
|
try:
|
||||||
self.default_user = getpass.getuser()
|
self.default_user = getpass.getuser()
|
||||||
except (ImportError, KeyError, OSError):
|
except OSError:
|
||||||
# deprecated: description='only OSError is required for Python 3.13+' python_version='3.12'
|
|
||||||
display.vv("Current user (uid=%s) does not seem to exist on this system, leaving user empty." % os.getuid())
|
display.vv("Current user (uid=%s) does not seem to exist on this system, leaving user empty." % os.getuid())
|
||||||
self.default_user = ""
|
self.default_user = ""
|
||||||
|
|
||||||
|
|||||||
@@ -472,8 +472,6 @@ b_NOT_SSH_ERRORS = (b'Traceback (most recent call last):', # Python-2.6 when th
|
|||||||
SSHPASS_AVAILABLE = None
|
SSHPASS_AVAILABLE = None
|
||||||
SSH_DEBUG = re.compile(r'^debug\d+: .*')
|
SSH_DEBUG = re.compile(r'^debug\d+: .*')
|
||||||
|
|
||||||
_HAS_RESOURCE_TRACK = sys.version_info[:2] >= (3, 13)
|
|
||||||
|
|
||||||
PKCS11_DEFAULT_PROMPT = 'Enter PIN for '
|
PKCS11_DEFAULT_PROMPT = 'Enter PIN for '
|
||||||
SSH_ASKPASS_DEFAULT_PROMPT = 'assword'
|
SSH_ASKPASS_DEFAULT_PROMPT = 'assword'
|
||||||
|
|
||||||
@@ -632,11 +630,6 @@ def _clean_resources(func):
|
|||||||
self.shm.close()
|
self.shm.close()
|
||||||
with contextlib.suppress(FileNotFoundError):
|
with contextlib.suppress(FileNotFoundError):
|
||||||
self.shm.unlink()
|
self.shm.unlink()
|
||||||
if not _HAS_RESOURCE_TRACK:
|
|
||||||
# deprecated: description='unneeded due to track argument for SharedMemory' python_version='3.12'
|
|
||||||
# There is a resource tracking issue where the resource is deleted, but tracking still has a record
|
|
||||||
# This will effectively overwrite the record and remove it
|
|
||||||
SharedMemory(name=self.shm.name, create=True, size=1).unlink()
|
|
||||||
return ret
|
return ret
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
@@ -1038,11 +1031,7 @@ class Connection(ConnectionBase):
|
|||||||
if not conn_password:
|
if not conn_password:
|
||||||
return popen_kwargs
|
return popen_kwargs
|
||||||
|
|
||||||
kwargs = {}
|
self.shm = shm = SharedMemory(create=True, size=16384, track=False)
|
||||||
if _HAS_RESOURCE_TRACK:
|
|
||||||
# deprecated: description='track argument for SharedMemory always available' python_version='3.12'
|
|
||||||
kwargs['track'] = False
|
|
||||||
self.shm = shm = SharedMemory(create=True, size=16384, **kwargs) # type: ignore[arg-type]
|
|
||||||
|
|
||||||
sshpass_prompt = self.get_option('sshpass_prompt')
|
sshpass_prompt = self.get_option('sshpass_prompt')
|
||||||
if not sshpass_prompt and pkcs11_provider:
|
if not sshpass_prompt and pkcs11_provider:
|
||||||
|
|||||||
@@ -174,8 +174,7 @@ class FilterUserInjector(logging.Filter):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
username = getpass.getuser()
|
username = getpass.getuser()
|
||||||
except (ImportError, KeyError, OSError):
|
except OSError:
|
||||||
# deprecated: description='only OSError is required for Python 3.13+' python_version='3.12'
|
|
||||||
# people like to make containers w/o actual valid passwd/shadow and use host uids
|
# people like to make containers w/o actual valid passwd/shadow and use host uids
|
||||||
username = 'uid=%s' % os.getuid()
|
username = 'uid=%s' % os.getuid()
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from __future__ import annotations
|
|||||||
import random
|
import random
|
||||||
import secrets
|
import secrets
|
||||||
import string
|
import string
|
||||||
import warnings
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
@@ -19,17 +18,13 @@ PASSLIB_E = None
|
|||||||
PASSLIB_AVAILABLE = False
|
PASSLIB_AVAILABLE = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# deprecated: description='warning suppression only required for Python 3.12 and earlier' python_version='3.12'
|
import passlib
|
||||||
with warnings.catch_warnings():
|
import passlib.hash
|
||||||
warnings.filterwarnings('ignore', message="'crypt' is deprecated and slated for removal in Python 3.13", category=DeprecationWarning)
|
from passlib.utils.handlers import HasRawSalt, PrefixWrapper
|
||||||
|
try:
|
||||||
import passlib
|
from passlib.utils.binary import bcrypt64
|
||||||
import passlib.hash
|
except ImportError:
|
||||||
from passlib.utils.handlers import HasRawSalt, PrefixWrapper
|
from passlib.utils import bcrypt64
|
||||||
try:
|
|
||||||
from passlib.utils.binary import bcrypt64
|
|
||||||
except ImportError:
|
|
||||||
from passlib.utils import bcrypt64
|
|
||||||
|
|
||||||
PASSLIB_AVAILABLE = True
|
PASSLIB_AVAILABLE = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@ requires = ["setuptools >= 77.0.3, <= 80.3.1"] # lower bound to support license
|
|||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.13"
|
||||||
name = "ansible-core"
|
name = "ansible-core"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Ansible Project"},
|
{name = "Ansible Project"},
|
||||||
@@ -24,9 +24,9 @@ classifiers = [
|
|||||||
"Natural Language :: English",
|
"Natural Language :: English",
|
||||||
"Operating System :: POSIX",
|
"Operating System :: POSIX",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
"Programming Language :: Python :: 3.14",
|
"Programming Language :: Python :: 3.14",
|
||||||
|
"Programming Language :: Python :: 3.15",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Topic :: System :: Installation/Setup",
|
"Topic :: System :: Installation/Setup",
|
||||||
"Topic :: System :: Systems Administration",
|
"Topic :: System :: Systems Administration",
|
||||||
|
|||||||
@@ -156,28 +156,13 @@ def get_test_scenarios() -> list[TestScenario]:
|
|||||||
image = settings['image']
|
image = settings['image']
|
||||||
cgroup = settings.get('cgroup', 'v1-v2')
|
cgroup = settings.get('cgroup', 'v1-v2')
|
||||||
|
|
||||||
if container_name == 'centos6' and os_release.id == 'alpine':
|
|
||||||
# Alpine kernels do not emulate vsyscall by default, which causes the centos6 container to fail during init.
|
|
||||||
# See: https://unix.stackexchange.com/questions/478387/running-a-centos-docker-image-on-arch-linux-exits-with-code-139
|
|
||||||
# Other distributions enable settings which trap vsyscall by default.
|
|
||||||
# See: https://www.kernelconfig.io/config_legacy_vsyscall_xonly
|
|
||||||
# See: https://www.kernelconfig.io/config_legacy_vsyscall_emulate
|
|
||||||
continue
|
|
||||||
|
|
||||||
for engine in available_engines:
|
for engine in available_engines:
|
||||||
# TODO: figure out how to get tests passing using docker without disabling selinux
|
# TODO: figure out how to get tests passing using docker without disabling selinux
|
||||||
disable_selinux = os_release.id == 'fedora' and engine == 'docker' and cgroup != 'none'
|
disable_selinux = os_release.id == 'fedora' and engine == 'docker' and cgroup != 'none'
|
||||||
debug_systemd = cgroup != 'none'
|
debug_systemd = cgroup != 'none'
|
||||||
|
|
||||||
# The sleep+pkill used to support the cgroup probe causes problems with the centos6 container.
|
if engine == 'docker' and container_name.startswith('alpine'):
|
||||||
# It results in sshd connections being refused or reset for many, but not all, container instances.
|
continue # TODO: restore Docker testing of Alpine once it's able to be used as a controller again (probably Alpine 3.24)
|
||||||
# The underlying cause of this issue is unknown.
|
|
||||||
probe_cgroups = container_name != 'centos6'
|
|
||||||
|
|
||||||
# The default RHEL 9 crypto policy prevents use of SHA-1.
|
|
||||||
# This results in SSH errors with centos6 containers: ssh_dispatch_run_fatal: Connection to 1.2.3.4 port 22: error in libcrypto
|
|
||||||
# See: https://access.redhat.com/solutions/6816771
|
|
||||||
enable_sha1 = os_release.id == 'rhel' and os_release.version_id.startswith('9.') and container_name == 'centos6'
|
|
||||||
|
|
||||||
# The AppArmor policy for pasta on Ubuntu 26.04 prevents podman from stopping containers.
|
# The AppArmor policy for pasta on Ubuntu 26.04 prevents podman from stopping containers.
|
||||||
# Attempting to do so fails with an error like:
|
# Attempting to do so fails with an error like:
|
||||||
@@ -237,9 +222,7 @@ def get_test_scenarios() -> list[TestScenario]:
|
|||||||
image=image,
|
image=image,
|
||||||
disable_selinux=disable_selinux,
|
disable_selinux=disable_selinux,
|
||||||
expose_cgroup_version=expose_cgroup_version,
|
expose_cgroup_version=expose_cgroup_version,
|
||||||
enable_sha1=enable_sha1,
|
|
||||||
debug_systemd=debug_systemd,
|
debug_systemd=debug_systemd,
|
||||||
probe_cgroups=probe_cgroups,
|
|
||||||
disable_apparmor_profile_pasta=disable_apparmor_profile_pasta,
|
disable_apparmor_profile_pasta=disable_apparmor_profile_pasta,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -255,16 +238,19 @@ def run_test(scenario: TestScenario) -> TestResult:
|
|||||||
|
|
||||||
integration = ['ansible-test', 'integration', 'split']
|
integration = ['ansible-test', 'integration', 'split']
|
||||||
integration_options = ['--target', f'docker:{scenario.container_name}', '--color', '--truncate', '0', '-v']
|
integration_options = ['--target', f'docker:{scenario.container_name}', '--color', '--truncate', '0', '-v']
|
||||||
target_only_options = []
|
|
||||||
|
|
||||||
if scenario.debug_systemd:
|
if scenario.debug_systemd:
|
||||||
integration_options.append('--dev-systemd-debug')
|
integration_options.append('--dev-systemd-debug')
|
||||||
|
|
||||||
if scenario.probe_cgroups:
|
target_only_options = ['--dev-probe-cgroups', str(LOG_PATH)]
|
||||||
target_only_options = ['--dev-probe-cgroups', str(LOG_PATH)]
|
|
||||||
|
|
||||||
entries = get_container_completion_entries()
|
entries = get_container_completion_entries()
|
||||||
alpine_container = [name for name in entries if name.startswith('alpine')][0]
|
|
||||||
|
# For the split test, Alpine Linux is preferred as the controller. There are two reasons for this:
|
||||||
|
# 1) It doesn't require the cgroup v1 hack, so we can test a target that doesn't need that.
|
||||||
|
# 2) It doesn't require disabling selinux, so we can test a target that doesn't need that.
|
||||||
|
# Unfortunately, this isn't always possible, such as when an Alpine release isn't available with support for controller Python versions.
|
||||||
|
controller_container = [name for name in entries if name.startswith('base')][0]
|
||||||
|
|
||||||
commands = [
|
commands = [
|
||||||
# The cgroup probe is only performed for the first test of the target.
|
# The cgroup probe is only performed for the first test of the target.
|
||||||
@@ -272,10 +258,7 @@ def run_test(scenario: TestScenario) -> TestResult:
|
|||||||
# The controller will be tested separately as a target.
|
# The controller will be tested separately as a target.
|
||||||
# This ensures that both the probe and no-probe code paths are functional.
|
# This ensures that both the probe and no-probe code paths are functional.
|
||||||
[*integration, *integration_options, *target_only_options],
|
[*integration, *integration_options, *target_only_options],
|
||||||
# For the split test we'll use Alpine Linux as the controller. There are two reasons for this:
|
[*integration, '--controller', f'docker:{controller_container}', *integration_options],
|
||||||
# 1) It doesn't require the cgroup v1 hack, so we can test a target that doesn't need that.
|
|
||||||
# 2) It doesn't require disabling selinux, so we can test a target that doesn't need that.
|
|
||||||
[*integration, '--controller', f'docker:{alpine_container}', *integration_options],
|
|
||||||
]
|
]
|
||||||
|
|
||||||
common_env: dict[str, str] = {}
|
common_env: dict[str, str] = {}
|
||||||
@@ -332,9 +315,6 @@ def run_test(scenario: TestScenario) -> TestResult:
|
|||||||
if scenario.disable_selinux:
|
if scenario.disable_selinux:
|
||||||
run_command('setenforce', 'permissive')
|
run_command('setenforce', 'permissive')
|
||||||
|
|
||||||
if scenario.enable_sha1:
|
|
||||||
run_command('update-crypto-policies', '--set', 'DEFAULT:SHA1')
|
|
||||||
|
|
||||||
if scenario.disable_apparmor_profile_pasta:
|
if scenario.disable_apparmor_profile_pasta:
|
||||||
os.symlink('/etc/apparmor.d/usr.bin.pasta', '/etc/apparmor.d/disable/usr.bin.pasta')
|
os.symlink('/etc/apparmor.d/usr.bin.pasta', '/etc/apparmor.d/disable/usr.bin.pasta')
|
||||||
run_command('apparmor_parser', '-R', '/etc/apparmor.d/usr.bin.pasta')
|
run_command('apparmor_parser', '-R', '/etc/apparmor.d/usr.bin.pasta')
|
||||||
@@ -365,9 +345,6 @@ def run_test(scenario: TestScenario) -> TestResult:
|
|||||||
os.unlink('/etc/apparmor.d/disable/usr.bin.pasta')
|
os.unlink('/etc/apparmor.d/disable/usr.bin.pasta')
|
||||||
run_command('apparmor_parser', '/etc/apparmor.d/usr.bin.pasta')
|
run_command('apparmor_parser', '/etc/apparmor.d/usr.bin.pasta')
|
||||||
|
|
||||||
if scenario.enable_sha1:
|
|
||||||
run_command('update-crypto-policies', '--set', 'DEFAULT')
|
|
||||||
|
|
||||||
if scenario.disable_selinux:
|
if scenario.disable_selinux:
|
||||||
run_command('setenforce', 'enforcing')
|
run_command('setenforce', 'enforcing')
|
||||||
|
|
||||||
@@ -621,9 +598,7 @@ class TestScenario:
|
|||||||
image: str
|
image: str
|
||||||
disable_selinux: bool
|
disable_selinux: bool
|
||||||
expose_cgroup_version: int | None
|
expose_cgroup_version: int | None
|
||||||
enable_sha1: bool
|
|
||||||
debug_systemd: bool
|
debug_systemd: bool
|
||||||
probe_cgroups: bool
|
|
||||||
disable_apparmor_profile_pasta: bool
|
disable_apparmor_profile_pasta: bool
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -642,9 +617,6 @@ class TestScenario:
|
|||||||
if self.expose_cgroup_version is not None:
|
if self.expose_cgroup_version is not None:
|
||||||
tags.append(f'cgroup: {self.expose_cgroup_version}')
|
tags.append(f'cgroup: {self.expose_cgroup_version}')
|
||||||
|
|
||||||
if self.enable_sha1:
|
|
||||||
tags.append('sha1: enabled')
|
|
||||||
|
|
||||||
if self.disable_apparmor_profile_pasta:
|
if self.disable_apparmor_profile_pasta:
|
||||||
tags.append('apparmor(pasta): disabled')
|
tags.append('apparmor(pasta): disabled')
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ macos/26.3 python=3.14 python_dir=/usr/local/bin become=sudo provider=mac arch=a
|
|||||||
macos python_dir=/usr/local/bin become=sudo provider=mac arch=aarch64
|
macos python_dir=/usr/local/bin become=sudo provider=mac arch=aarch64
|
||||||
rhel/8.10 python=3.12 become=sudo provider=aws arch=x86_64 alias=rhel/8
|
rhel/8.10 python=3.12 become=sudo provider=aws arch=x86_64 alias=rhel/8
|
||||||
rhel/9.7 python=3.9,3.12 become=sudo provider=aws arch=x86_64 alias=rhel/9
|
rhel/9.7 python=3.9,3.12 become=sudo provider=aws arch=x86_64 alias=rhel/9
|
||||||
rhel/10.1 python=3.12 become=sudo provider=aws arch=x86_64 alias=rhel/10,rhel/latest
|
rhel/10.1 python=3.12,3.14 become=sudo provider=aws arch=x86_64 alias=rhel/10,rhel/latest
|
||||||
rhel become=sudo provider=aws arch=x86_64
|
rhel become=sudo provider=aws arch=x86_64
|
||||||
ubuntu/24.04 python=3.12 become=sudo provider=aws arch=x86_64
|
ubuntu/24.04 python=3.12 become=sudo provider=aws arch=x86_64
|
||||||
ubuntu/26.04 python=3.14 become=sudo provider=aws arch=x86_64 alias=ubuntu/latest
|
ubuntu/26.04 python=3.14 become=sudo provider=aws arch=x86_64 alias=ubuntu/latest
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ REMOTE_ONLY_PYTHON_VERSIONS = (
|
|||||||
'3.9',
|
'3.9',
|
||||||
'3.10',
|
'3.10',
|
||||||
'3.11',
|
'3.11',
|
||||||
|
'3.12',
|
||||||
)
|
)
|
||||||
|
|
||||||
CONTROLLER_PYTHON_VERSIONS = (
|
CONTROLLER_PYTHON_VERSIONS = (
|
||||||
'3.12',
|
|
||||||
'3.13',
|
'3.13',
|
||||||
'3.14',
|
'3.14',
|
||||||
'3.15',
|
'3.15',
|
||||||
|
|||||||
@@ -305,11 +305,6 @@ bootstrap_remote_freebsd()
|
|||||||
cryptography_pkg="" # not available
|
cryptography_pkg="" # not available
|
||||||
pyyaml_pkg="" # not available
|
pyyaml_pkg="" # not available
|
||||||
;;
|
;;
|
||||||
"15.0/3.12")
|
|
||||||
jinja2_pkg="" # not available
|
|
||||||
cryptography_pkg="" # not available
|
|
||||||
pyyaml_pkg="" # not available
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
# just assume nothing is available
|
# just assume nothing is available
|
||||||
jinja2_pkg="" # not available
|
jinja2_pkg="" # not available
|
||||||
@@ -429,7 +424,11 @@ bootstrap_remote_rhel_10()
|
|||||||
{
|
{
|
||||||
optimize_dnf
|
optimize_dnf
|
||||||
|
|
||||||
py_pkg_prefix="python3"
|
if [ "${python_version}" = "3.12" ]; then
|
||||||
|
py_pkg_prefix="python3"
|
||||||
|
else
|
||||||
|
py_pkg_prefix="python${python_version}"
|
||||||
|
fi
|
||||||
|
|
||||||
packages="
|
packages="
|
||||||
gcc
|
gcc
|
||||||
@@ -437,14 +436,13 @@ bootstrap_remote_rhel_10()
|
|||||||
${py_pkg_prefix}-pip
|
${py_pkg_prefix}-pip
|
||||||
"
|
"
|
||||||
|
|
||||||
|
# Jinja2, packaging and resolvelib are missing for controller supported Python versions, so we just
|
||||||
|
# skip them and let ansible-test install them from PyPI.
|
||||||
if [ "${controller}" ]; then
|
if [ "${controller}" ]; then
|
||||||
packages="
|
packages="
|
||||||
${packages}
|
${packages}
|
||||||
${py_pkg_prefix}-cryptography
|
${py_pkg_prefix}-cryptography
|
||||||
${py_pkg_prefix}-jinja2
|
|
||||||
${py_pkg_prefix}-packaging
|
|
||||||
${py_pkg_prefix}-pyyaml
|
${py_pkg_prefix}-pyyaml
|
||||||
${py_pkg_prefix}-resolvelib
|
|
||||||
"
|
"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ lib/ansible/plugins/cache/base.py ansible-doc!skip # not a plugin, but a stub f
|
|||||||
lib/ansible/plugins/callback/__init__.py pylint:arguments-renamed
|
lib/ansible/plugins/callback/__init__.py pylint:arguments-renamed
|
||||||
lib/ansible/plugins/inventory/advanced_host_list.py pylint:arguments-renamed
|
lib/ansible/plugins/inventory/advanced_host_list.py pylint:arguments-renamed
|
||||||
lib/ansible/plugins/inventory/host_list.py pylint:arguments-renamed
|
lib/ansible/plugins/inventory/host_list.py pylint:arguments-renamed
|
||||||
lib/ansible/_internal/_wrapt.py mypy-3.12!skip # vendored code
|
|
||||||
lib/ansible/_internal/_wrapt.py mypy-3.13!skip # vendored code
|
lib/ansible/_internal/_wrapt.py mypy-3.13!skip # vendored code
|
||||||
lib/ansible/_internal/_wrapt.py mypy-3.14!skip # vendored code
|
lib/ansible/_internal/_wrapt.py mypy-3.14!skip # vendored code
|
||||||
lib/ansible/_internal/_wrapt.py mypy-3.15!skip # vendored code
|
lib/ansible/_internal/_wrapt.py mypy-3.15!skip # vendored code
|
||||||
|
|||||||
@@ -18,15 +18,9 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# deprecated: description='warning suppression only required for Python 3.12 and earlier' python_version='3.12'
|
import passlib
|
||||||
with warnings.catch_warnings():
|
from passlib.handlers import pbkdf2
|
||||||
warnings.filterwarnings('ignore', message="'crypt' is deprecated and slated for removal in Python 3.13", category=DeprecationWarning)
|
|
||||||
|
|
||||||
import passlib
|
|
||||||
from passlib.handlers import pbkdf2
|
|
||||||
except ImportError: # pragma: nocover
|
except ImportError: # pragma: nocover
|
||||||
passlib = None
|
passlib = None
|
||||||
pbkdf2 = None
|
pbkdf2 = None
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
bcrypt < 5 ; python_version >= '3.12' # controller only, bcrypt 5+ not compatible with passlib
|
bcrypt < 5 ; python_version >= '3.13' # controller only, bcrypt 5+ not compatible with passlib
|
||||||
passlib ; python_version >= '3.12' # controller only
|
passlib ; python_version >= '3.13' # controller only
|
||||||
pexpect ; python_version >= '3.12' # controller only
|
pexpect ; python_version >= '3.13' # controller only
|
||||||
pywinrm ; python_version >= '3.12' # controller only
|
pywinrm ; python_version >= '3.13' # controller only
|
||||||
typing_extensions; python_version < '3.11' # some unit tests need Annotated and get_type_hints(include_extras=True)
|
typing_extensions; python_version < '3.11' # some unit tests need Annotated and get_type_hints(include_extras=True)
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
@@ -228,11 +226,7 @@ def test_random_salt():
|
|||||||
|
|
||||||
|
|
||||||
def test_passlib_bcrypt_salt(recwarn):
|
def test_passlib_bcrypt_salt(recwarn):
|
||||||
# deprecated: description='warning suppression only required for Python 3.12 and earlier' python_version='3.12'
|
passlib_exc = pytest.importorskip("passlib.exc")
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.filterwarnings('ignore', message="'crypt' is deprecated and slated for removal in Python 3.13", category=DeprecationWarning)
|
|
||||||
|
|
||||||
passlib_exc = pytest.importorskip("passlib.exc")
|
|
||||||
|
|
||||||
secret = 'foo'
|
secret = 'foo'
|
||||||
salt = '1234567890123456789012'
|
salt = '1234567890123456789012'
|
||||||
|
|||||||
Reference in New Issue
Block a user