Ansible v2.21.3 - Galaxy Retry And rpm_key Parse Fix


Ansible published v2.21.3 on 10 August 2026 as a stable patch on the 2.21 controller line. The change most operators will feel is in ansible-galaxy: a truncated Galaxy response no longer fails collection install on the first hash mismatch. The CLI retries the download when the body is shorter than expected.

The full release notes and downloads are on the GitHub release page. The tag page itself is thin. It points at the v2.21.3 changelog and lists wheel and sdist hashes. This post covers only the v2.21.3 bug fixes in that file, not earlier 2.21.x entries.

Collection install is part of the data plane for a lot of batch jobs. Image bake, CI bootstrap, and playbook entry all call ansible-galaxy before any ETL role runs. A one shot HTTP failure at that step aborts the whole graph.

The previous behavior treated a short Galaxy body as a hard error. The on disk artifact hash did not match, so the first attempt died. Flaky proxies, short reads, and mid transfer resets all looked like a corrupt collection.

v2.21.3 retries the download when the response is shorter than expected (pull 86025). Hash verification stays in place. A payload that is still short or still wrong after retry should fail the same way it always did. A truncated first body is no longer a permanent fail.

This is a controller side change. Target hosts do not need a matching patch for the retry itself. Pin the controller to v2.21.3 if collection install is in the critical path.

Package trust is the other operator visible fix. rpm_key now forces a trailing newline on PGP armor before the blob goes to librpm.

Some stacks, through pgpParsePkts, reject armor that does not end in a newline (issue 87303). A key that parsed on one librpm build can fail on another. The symptom is a parse error, not a missing key in the rpm database.

That shows up in image bake and first boot when playbooks import vendor or internal signing keys, then install packages that those keys sign. The split is between librpm builds that require the trailing newline and those that do not. The module does not change trust policy. It only normalizes the armor framing so pgpParsePkts can read it.

If a playbook already appends a newline in Jinja, the extra byte is harmless. If a playbook stores armor without a final newline, this patch is the fix rather than a workaround in the role.

The collection loader now returns a real Python module from pkgutil.iter_modules when the package lives under a collection path and holds compiled extension modules. Collections that ship .so files were the broken case. Controller introspection that walks those packages could see an empty or wrong module list. Database, compression, and crypto collections that wrap C extensions are the ones to retest after upgrade.

The PowerShell exec_wrapper mishandled multiple pwsh binaries on PATH. It now selects the first match (issue 87228). Mixed Windows and POSIX controllers with more than one PowerShell 7 install no longer pick an arbitrary later hit. That matters when a host image ships a distro pwsh plus a newer user local copy.

ansible-test target filtering now keeps versions the user passed in even when they are absent from the completion configuration. Custom remotes and pinned platform versions in CI were getting dropped. That is a test contract fix, not a production runtime change, but it is how ansible-core itself is gated.

The tree and oneline callback DOCUMENTATION blocks now mark deprecation status (issue 87020). That is docs metadata in this tag, not a runtime switch. Callbacks still load. Operators who scrape plugin docs for allow lists will see the new deprecation flag.

None of these items is a breaking change in v2.21.3. This patch does not add new porting steps.

Wheel and sdist are on the GitHub release page and on PyPI. The built distribution is ansible_core-2.21.3-py3-none-any.whl (2446988 bytes), SHA256 9e7dd367f7dc5d5e9fc5ae1baf8af9c4edc09e916a73a40108a3f32e3ad93f10. The source distribution is ansible_core-2.21.3.tar.gz (3397615 bytes), SHA256 4194fbd82273cbacfd06d86d74d2d7168c3c4b8426c03e93562cd7217f811ae1. Confirm those hashes before promoting the artifact into an internal index.

This tag is not a prerelease. It is a normal maintenance release of ansible-core.