Compare commits

...

151 Commits

Author SHA1 Message Date
patchback[bot]
743591cedc [PR #11926/c0d3464f backport][stable-12] crypttab: fix option parsing when value contains multiple equal signs (#11929)
crypttab: fix option parsing when value contains multiple equal signs (#11926)

* fix(crypttab): preserve option values containing multiple equal signs

Fixes #4963



* fix(crypttab): add changelog fragment for PR 11926



---------


(cherry picked from commit c0d3464fa7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:27:44 +02:00
patchback[bot]
412a348738 [PR #11918/89d82ab9 backport][stable-12] scaleway: fix NoneType error in get_resources() (#11924)
scaleway: fix NoneType error in get_resources() (#11918)

* scaleway: fix NoneType error in get_resources() when API returns empty or non-JSON response

* add changelog fragment for #11918

* Update changelogs/fragments/11361-scaleway-get-resources-none-type.yml



---------



(cherry picked from commit 89d82ab9df)

Co-authored-by: RealCharlesChia <161665317+RealCharlesChia@users.noreply.github.com>
Co-authored-by: RealCharlesChia <RealCharlesChia@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-27 21:13:47 +02:00
Felix Fontein
020fcb251f Prepare 12.6.1. 2026-04-22 20:51:30 +02:00
patchback[bot]
1ea0904e69 [PR #11912/7db237aa backport][stable-12] Add Python 3.15 to CI (#11915)
Add Python 3.15 to CI (#11912)

Add Python 3.15 to CI.

(cherry picked from commit 7db237aaa4)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-22 20:50:32 +02:00
patchback[bot]
90aa3ec24d [PR #11909/d57a6672 backport][stable-12] Replace default favicon URL again (#11913)
Replace default favicon URL again (#11909)

* replace default favicon URL

* add changelog fragment for PR 11909

* fix syntax for change fragment



* use higher res favicon by default

---------



(cherry picked from commit d57a667274)

Co-authored-by: Lars Krahl <57526005+mmslkr@users.noreply.github.com>
Co-authored-by: Lars Krahl <lars.krahl@telekom.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-22 20:17:17 +02:00
patchback[bot]
2b64eb69be [PR #11901/9ef1dbb6 backport][stable-12] Move ansible-core 2.18 to EOL CI (#11904)
Move ansible-core 2.18 to EOL CI (#11901)

Move ansible-core 2.18 to EOL CI.

(cherry picked from commit 9ef1dbb6d5)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-20 17:03:32 +02:00
patchback[bot]
9233243c13 [PR #11898/6b5bf0a0 backport][stable-12] Fix FQCNs in examples (#11902)
Fix FQCNs in examples (#11898)

Fix FQCNs in examples.

(cherry picked from commit 6b5bf0a0bc)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-20 15:20:24 +02:00
Felix Fontein
6407d59323 The next release will be 12.6.1. 2026-04-20 13:56:57 +02:00
Felix Fontein
25b09239f6 Release 12.6.0. 2026-04-20 12:34:53 +02:00
patchback[bot]
524aa8bab4 [PR #11840/7ce198f0 backport][stable-12] keycloak modules: add missing author credit (#11895)
keycloak modules: add missing author credit (#11840)

keycloak modules: add missing author credit for contributions

Added myself (@koke1997) to the author list of three modules
I contributed to in PRs #11468, #11470, #11471, and #11473 but forgot
to include at the time. Also signing up as maintainer for these modules
in .github/BOTMETA.yml so the bot can route related issues and PRs.

(cherry picked from commit 7ce198f0e7)

Co-authored-by: Ivan Kokalovic <67540157+koke1997@users.noreply.github.com>
2026-04-20 12:17:16 +02:00
patchback[bot]
09bea0031d [PR #11892/3325b854 backport][stable-12] Fix typo (#11894)
Fix typo (#11892)

(cherry picked from commit 3325b854ee)

Co-authored-by: Matt Williams <matt@milliams.com>
2026-04-20 12:17:03 +02:00
patchback[bot]
be4cf3ba4d [PR #11735/3e9689b1 backport][stable-12] jira - resolve Cloud assignee email to account ID via user search (#11891)
jira - resolve Cloud assignee email to account ID via user search (#11735)

* jira - resolve Cloud assignee email to account ID via user search

When cloud=true and assignee contains '@', look up a unique user with
GET /rest/api/2/user/search and use accountId for create, transition,
and edit. Document Jira Cloud vs Server/Data Center assignee behavior.

Fixes https://github.com/ansible-collections/community.general/issues/11734

Assisted-by AI: Claude 4.6 Opus (Anthropic) via Cursor IDE



* * Using urllib.parse.quote for URL encoding
* Adding "added in version" note for assignee when resolving account_id from email



* * Added cached variable 'user_email'
* Changed comparison to handle missing email safely
* Updated error message formatting to use repr-style values



* jira - adjust assignee and cloud descriptions (#11734)



* jira - resolve user-type field emails to account IDs on Jira Cloud (#11734)

When cloud=true, user-type fields (assignee, reporter, and any listed
in the new custom_user_fields parameter) that contain '@' are resolved
from email to Jira Cloud account ID via the user search API. Strings
without '@' are assumed to be account IDs. Add custom_user_fields
parameter for user to declare additional custom fields of user type.



* jira - address PR 11735 review (docs, assignee path, errors, naming)

- Clarify O(custom_user_fields): built-ins stay automatic; list extra
  user-typed fields without implying they are only custom-field IDs.
- On Jira Cloud, set assignee from the module param as a plain string and
  let resolve_user_fields() map it to accountId (including email lookup).
- Drop redundant ``or []`` when merging O(custom_user_fields) with the
  built-in user field list.
- Use public names USER_FIELDS, resolve_user_fields, and resolve_account_id
  (no leading underscore) per reviewer preference.
- Quote field name and email in resolution errors with explicit "…" text
  instead of repr-style !r, keeping values readable in failure messages.

Refs: https://github.com/ansible-collections/community.general/pull/11735

AI-assisted: Composer 2 (Anthropic) via Cursor IDE



* Changing fail_json formatting



* formatting fixes



* jira - fixing assignee as module option in description



---------


(cherry picked from commit 3e9689b13d)

Signed-off-by: Vladimir Vasilev <vvasilev@redhat.com>
Co-authored-by: vladi-k <53343355+vladi-k@users.noreply.github.com>
2026-04-20 09:36:05 +02:00
patchback[bot]
03da9164d1 [PR #11888/5b409fac backport][stable-12] filesystem - migrate LVM.get_fs_size() to use CmdRunner (#11889)
filesystem - migrate LVM.get_fs_size() to use CmdRunner (#11888)

* filesystem - migrate LVM.get_fs_size() to use CmdRunner



* filesystem - add changelog fragment for #11888



---------


(cherry picked from commit 5b409facbe)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 09:35:55 +02:00
patchback[bot]
d99b778fa1 [PR #11887/9f80d89f backport][stable-12] lvol - migrate to CmdRunner (#11890)
lvol - migrate to CmdRunner (#11887)

* lvol - migrate to CmdRunner



* lvol - add changelog fragment for #11887



* adjust the changelog fragment

---------


(cherry picked from commit 9f80d89fc3)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 09:35:47 +02:00
patchback[bot]
fa179e6d0c [PR #11694/180da98a backport][stable-12] ipa_dnsrecord: add exclusive parameter for append-without-replace semantics (#11885)
ipa_dnsrecord: add `exclusive` parameter for append-without-replace semantics (#11694)

* ipa_dnsrecord: add solo parameter for append-without-replace semantics

Fixes #682

Adds O(solo) boolean parameter (default true, preserving current
replace behaviour) consistent with other DNS modules such as
community.general.dnsimple. When solo=false, only values not
already present in IPA are added, leaving existing values untouched.



* ipa_dnsrecord: rename solo parameter to exclusive

Rename O(solo) to O(exclusive) following reviewer feedback.
'exclusive' is the established Ansible convention for this semantic
(e.g. community.general.ini_file), while 'solo' implies single-value
DNS records.



* ipa_dnsrecord: fix changelog fragment symbol markup

Use double backticks per RST convention in changelog fragments,
not the O() macro (which is for module docstrings).



* Update plugins/modules/ipa_dnsrecord.py



* ipa_dnsrecord: implement exclusive semantics for state=absent

- exclusive=true + state=absent: remove all existing values of that
  record type and name, ignoring the specified record_value(s)
- exclusive=false + state=absent: remove only the specified values
  that actually exist in IPA, preserving all others

Also updates the exclusive parameter documentation to cover both
state=present and state=absent behaviour.



---------



(cherry picked from commit 180da98a7c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-19 23:07:11 +02:00
patchback[bot]
dc79f4a170 [PR #11860/25b21183 backport][stable-12] udm_user, homectl - replace crypt/legacycrypt with passlib (#11884)
udm_user, homectl - replace crypt/legacycrypt with passlib (#11860)

* udm_user - replace crypt/legacycrypt with passlib

The stdlib crypt module was removed in Python 3.13. Replace the
crypt/legacycrypt import chain with passlib (already used elsewhere
in the collection) and use CryptContext.verify() for password
comparison.

Fixes #4690



* Add changelog fragment for PR 11860



* remove redundant ignore file entries

* udm_user, homectl - replace crypt/legacycrypt with _crypt module utils

Add a new _crypt module_utils that abstracts password hashing and
verification. It uses passlib when available, falling back to the
stdlib crypt or legacycrypt, and raises ImportError if none of them
can be imported. Both udm_user and homectl now use this shared
utility, fixing compatibility with Python 3.13+.

Fixes #4690



* Add BOTMETA entry for _crypt module utils



* _crypt - fix mypy errors and handle complete unavailability

Replace CryptContext = object fallback (rejected by mypy) with a
proper dummy class definition. Add has_crypt_context flag so modules
can detect when no backend is available. Update both modules to
import and check has_crypt_context instead of testing for None.



* adjsutments from review

* Update plugins/modules/homectl.py



* Update plugins/modules/udm_user.py



---------



(cherry picked from commit 25b21183bb)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-19 22:51:20 +02:00
patchback[bot]
748882dfa8 [PR #11879/77509be2 backport][stable-12] Replace .format() calls with f-strings across multiple plugins (#11881)
Replace .format() calls with f-strings across multiple plugins (#11879)

* Replace .format() calls with f-strings across multiple plugins



* Add changelog fragment for PR 11879



---------


(cherry picked from commit 77509be2aa)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 12:49:29 +02:00
patchback[bot]
6458abb9c1 [PR #11838/d0d213a4 backport][stable-12] homebrew_cask: fix false failure on upgrade of latest-versioned casks (#11880)
homebrew_cask: fix false failure on upgrade of latest-versioned casks (#11838)

* homebrew_cask: fix false failure on upgrade of latest-versioned casks

Use rc == 0 to determine upgrade success, consistent with _upgrade_all().
The previous check (_current_cask_is_installed() and not _current_cask_is_outdated())
was unreliable: for `latest`-versioned casks under --greedy, brew may still
list the cask as outdated after a successful upgrade, causing the task to fail
with a harmless warning from stderr as the error message.

Fixes #1647



* homebrew_cask: add changelog fragment for #11838



* Fix changelog fragment

---------


(cherry picked from commit d0d213a41d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:49:23 +02:00
patchback[bot]
09201bf49e [PR #11878/1b0b8d5c backport][stable-12] gitlab_project_variable - use find_project() for graceful error handling (#11882)
gitlab_project_variable - use find_project() for graceful error handling (#11878)

* gitlab_project_variable - use find_project() for consistent error handling

Replace the bare projects.get() call in GitlabProjectVariables.get_project()
with find_project() from module_utils/gitlab, which all other GitLab modules
already use. This ensures a graceful fail_json (with a clear error message)
when the project is not found, rather than an unhandled GitlabGetError
propagating as a module traceback.



* Add changelog fragment for PR 11878



* minor adjustment in f-string

---------


(cherry picked from commit 1b0b8d5cc1)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 12:49:16 +02:00
patchback[bot]
973b5be063 [PR #11824/39f4cda6 backport][stable-12] locale_gen: support locales not yet listed in /etc/locale.gen (#11883)
locale_gen: support locales not yet listed in /etc/locale.gen (#11824)

* locale_gen: support locales not yet listed in /etc/locale.gen

On systems like Gentoo where /etc/locale.gen starts with only a handful
of commented examples, set_locale_glibc() now appends missing locale
entries sourced from /usr/share/i18n/SUPPORTED instead of silently
doing nothing. Also extracts the shared locale-entry regex into a
module-level constant RE_LOCALE_ENTRY.



* locale_gen: add changelog fragment for issue 2399



---------


(cherry picked from commit 39f4cda6b5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 12:49:10 +02:00
patchback[bot]
449a179d8f [PR #11750/6c809dd9 backport][stable-12] pacemaker: fix race condition on resource creation (#11877)
pacemaker: fix race condition on resource creation (#11750)

* remove pacemaker wait arg and fix race condition

* fix up pacemaker resource and stonith polling

* add changelog for pacemaker timeout bug

* remove env from test case and fix changelog file name

* Update changelogs/fragments/11750-pacemaker-wait-race-condition.yml



---------


(cherry picked from commit 6c809dd9db)

Co-authored-by: munchtoast <45038532+munchtoast@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-18 22:55:56 +02:00
patchback[bot]
27ca6be10a [PR #11813/edf8f249 backport][stable-12] parted: add unit_preserve_case option to fix unit case in return value (#11875)
parted: add unit_preserve_case option to fix unit case in return value (#11813)

* parted: add unit_preserve_case option to fix unit case in return value

Adds O(unit_preserve_case) feature flag (bool, default None) to control
the case of the ``unit`` field in the module return value.

Previously the unit was always lowercased (e.g. ``kib``), making it
impossible to feed ``disk.unit`` back as the ``unit`` parameter without
a validation error. With O(unit_preserve_case=true) the unit is returned
in its original mixed case (e.g. ``KiB``), matching the accepted input
values.

The default (None) emits a deprecation notice; the default will become
V(true) in community.general 14.0.0.

Fixes #1860



* parted: add changelog fragment for PR #11813



* adjustments from review

* Comment 15.0.0 deprecation in option decription.

* parted: fix unit test calls to parse_partition_info after signature change



* parted: fix unit_preserve_case - parted outputs lowercase units in machine mode

Parted's machine-parseable output always uses lowercase unit suffixes
(e.g. ``kib``, ``mib``) regardless of what was passed to the ``unit``
parameter. Removing the explicit ``.lower()`` call was therefore not
enough to preserve case.

Add a ``canonical_unit()`` helper that maps a unit string to its canonical
mixed-case form using ``parted_units`` as the reference, and use it
instead of a bare identity when ``unit_preserve_case=true``.

Also fix a yamllint violation in the DOCUMENTATION block (missing space
after ``#`` in inline comments).



* Update plugins/modules/parted.py



* Update plugins/modules/parted.py



---------



(cherry picked from commit edf8f24959)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-18 22:55:45 +02:00
patchback[bot]
3867300eca [PR #11839/afe9de75 backport][stable-12] homebrew_service: remove redundant code (#11876)
homebrew_service: remove redundant code (#11839)

* homebrew_service: remove redundant code

* homebrew_services: add changelog fragment for #11839



---------


(cherry picked from commit afe9de7562)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 22:55:25 +02:00
patchback[bot]
ae05131a54 [PR #11702/314863e3 backport][stable-12] xenserver_guest: changed cdrom handling for userdevice != 3, fixes #11624 (#11872)
xenserver_guest: changed cdrom handling for userdevice != 3, fixes #11624 (#11702)

* xenserver_guest: changed cdrom handling for userdevice != 3, fixes #11624

  - CD-ROM handling code has been moved before disk handling code. This more
    closely mimics XenCenter/XCP-ng Center behavior. CD-ROM device, if added,
    will now grab position 3 before any disk grabs it.
  - Position 3 is now skipped when adding disks to leave it reserved for
    CD-ROM device. If any disk ends up occupying position 3 and CD-ROM
    device ends up pushed to position above 3, booting from ISO is not
    possible (#11624).

* Added changelog fragment for #11702

* Added missing issue and PR URLs to changelog fragment for #11702

* Fixed changelog fragment for #11702

(cherry picked from commit 314863e3a7)

Co-authored-by: Bojan Vitnik <bvitnik@yahoo.com>
2026-04-17 18:55:33 +02:00
patchback[bot]
f67003cf3a [PR #11835/3416efa5 backport][stable-12] lvg - migrate to CmdRunner (#11858)
lvg - migrate to CmdRunner (#11835)


(cherry picked from commit 3416efa5bf)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:33:10 +02:00
patchback[bot]
2bd64a891c [PR #11817/175808d9 backport][stable-12] consul_kv: add ca_path option for custom CA certificate (#11852)
consul_kv: add ca_path option for custom CA certificate (#11817)

* consul_kv: add ca_path option for custom CA certificate

Adds ca_path parameter to both the consul_kv module and consul_kv lookup
plugin, allowing users to specify a CA bundle for HTTPS connections instead
of being limited to toggling certificate validation on/off.



* consul_kv: add changelog fragment for PR #11817



* consul_kv: address review comments from felixfontein

- Fix verify logic: ca_path is ignored when validate_certs=false
- Improve validate_certs description to nudge users toward ca_path



---------


(cherry picked from commit 175808d997)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:33:02 +02:00
patchback[bot]
6e226f4588 [PR #11812/e2a7dc46 backport][stable-12] sefcontext: flush in-process matchpathcon cache (#11854)
sefcontext: flush in-process matchpathcon cache (#11812)

* fix sefcontext: flush in-process matchpathcon cache after changes

Fixes https://github.com/ansible-collections/community.general/issues/888



* update changelog fragment with PR number and URL



---------


(cherry picked from commit e2a7dc467d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:32:53 +02:00
patchback[bot]
d82bf01128 [PR #11849/74c096b0 backport][stable-12] homebrew_cask: handle placeholder version from brew --version (#11855)
homebrew_cask: handle placeholder version from brew --version (#11849)

* homebrew_cask: handle placeholder version from brew --version

When brew is run as the wrong user, git repositories may be owned by
a different user, causing brew --version to output a placeholder like
"Homebrew >= 4.3.0 (shallow or no git repository)" instead of the real
version. The parsed version would then be lower than the 2.6.0 threshold,
causing _brew_cask_command_is_deprecated() to return False and the module
to use the disabled "brew cask" command syntax.

Detect the ">=" prefix in the parsed version and treat it as a modern
installation.

Fixes #4708



* homebrew_cask: add changelog fragment for #11849



---------


(cherry picked from commit 74c096b00c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:32:45 +02:00
patchback[bot]
2873d439c3 [PR #11764/e9110811 backport][stable-12] logrotate: fix parameter and config file validation and more (#11856)
logrotate: fix parameter and config file validation and more (#11764)

* fix(logrotate): add missing defaults and parameter validation declarations

- Add default="present" to state parameter
- Add default="/etc/logrotate.d" to config_dir parameter
- Add required_by declarations for shred and compression parameters

* fix(logrotate): fix runtime validation bugs, remove duplicate checks

- Fix shred_cycles TypeError when value is None
- Fix enabled=None handling in get_config_path
- Remove duplicate runtime mutually_exclusive checks
- Add runtime boolean truthiness checks
- Add 'create' parameter format validation
- Remove stale test method

* fix(logrotate): restructure file operations, validate before write

- Write content to tmpdir temp file, validate, then atomic move to destination.
- Wrap all os.remove() calls in try/except with fail_json on error
- Wrap all module.atomic_move() calls in try/except with fail_json on error
- Also add self.mock_module.tmpdir = self.test_dir to test setUp for new code path

* docs(logrotate): update DOCUMENTATION block

- Add 'default: present' to state option
- Add 'default: /etc/logrotate.d' to config_dir option

* feat(logrotate): add optional backup parameter

* chore: add logrotate fixes changelog fragment

* chore(changelog/logrotate): use present tense singular

* fix(logrotate): handle trailing spaces in create param



* refactor(logrotate): remove redundant checks

These are already handled by `required_if` statements in the module spec

* refactor(logrotate): use tempfile to create temporary file

* refactor(logrotate): remove redundant `bool()` casts on `target_enabled`

`target_enabled` is guaranteed to be bool by this point. It's either the module param (typed bool) or falls back to `current_enabled` (also bool). The `bool()` wraps are no-ops.

* refactor(logrotate): remove unused `self.config_file` attribute

* refactor(logrotate): remove dead `any_state` parameter from `read_existing_config`

* fix(logrotate): raise error instead of falling through on enabled-state rename failures

* refactor(logrotate): tighten `get_config_path` sig to bool

`None` callers are removed now so this is safe

* test(logrotate): remove stale open mock assertion after tempfile refactor

* style(logrotate): format file

* chore(logrotate): add missing `version_added` attribute



* fix(logrotate): clean up temp file



* fix(logrotate): remove redundant temp file cleanup



* refactor(logrotate): Use dict subscript to access required backup param



* fix(logrotate): fix: only remove old config file when path differs from target



* fix(logrotate): update logrotate_bin type hint to str

* feat(logrotate): add backup file handling when removing old config

* style(logrotate): format file

* test(logrotate): add missing backup default to `_setup_module_params`

* test(logrotate): fix incorrect `os.remove` assertion in update test

* refactor(logrotate): remove unnecessary `to_native()` call



* refactor(logrotate): replace str quotes with !r



* fix(logrotate): change backup default back to true

* fix(logrotate): raise error when `shred_cycle`s is set with `shred=false`

* docs(logrotate): clarify `shred_cycles` behaviour

* fix(logrotate): remove to_native calls for exception messages

* docs(logrotate): improve `config_dir` param description

* refactor(logrotate): simplify backup file assignment logic

* style(logrotate): format file

* docs(logrotate): improve config_map description

---------



(cherry picked from commit e911081102)

Co-authored-by: tigattack <10629864+tigattack@users.noreply.github.com>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-17 18:32:36 +02:00
patchback[bot]
956fc075ef [PR #11837/87ecfa34 backport][stable-12] iso_extract: retry umount on busy filesystem before cleanup (#11857)
iso_extract: retry umount on busy filesystem before cleanup (#11837)

* iso_extract: retry umount on busy filesystem before cleanup

Fixes #5333



* iso_extract: add changelog fragment for #11837



* make chglog more concise

---------


(cherry picked from commit 87ecfa3432)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:32:27 +02:00
patchback[bot]
7b82e694a2 [PR #11859/dad84dd3 backport][stable-12] udm_user - fix alias-to-canonical param name mismatch (#11863)
udm_user - fix alias-to-canonical param name mismatch (#11859)

* udm_user - fix alias-to-canonical param name mismatch

The loop that maps UDM object properties to module params iterated
over UDM keys (camelCase, e.g. displayName, primaryGroup) and looked
them up directly in module.params, which is keyed by canonical names
(snake_case, e.g. display_name, primary_group). This caused all
aliased params to be silently ignored.

Build an alias-to-canonical mapping from argument_spec and use it
to resolve UDM keys to the correct module.params entries.

Also fix the direct module.params["displayName"] access which raised
KeyError when the user did not explicitly use the alias form.

Fixes #2950
Fixes #3691



* Add changelog fragment for PR 11859



---------


(cherry picked from commit dad84dd36d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 18:32:17 +02:00
patchback[bot]
119623952d [PR #11848/c4ed3467 backport][stable-12] homebrew_tap: fix None in command, redundant brew tap calls, format strings, and drop no-op locale vars (#11865)
homebrew_tap: fix None in command, redundant brew tap calls, format strings, and drop no-op locale vars (#11848)

* homebrew_tap: fix None in command list, redundant brew tap calls, and bad format strings

- Fix None being injected into the run_command list when url is not
  provided to add_tap (filter with [opt for opt in [...] if opt])
- Reduce redundant `brew tap` calls: add_taps and remove_taps now
  fetch the tap list once upfront and pass it to the per-tap functions;
  already_tapped accepts an optional pre-fetched list to avoid re-running
  brew for every tap in a batch
- Fix mixed f-string/%-formatting in error messages in add_taps and
  remove_taps, replaced with plain f-strings



* homebrew_tap: simplify command construction in add_tap

Replace the opaque list comprehension filter with an explicit conditional
append — only url is ever optional, so testing the known-present items
was misleading.



* homebrew_tap: remove unnecessary locale env vars

Homebrew has no i18n/l10n support — all output is hardcoded English.
LANGUAGE=C and LC_ALL=C have no effect on brew output.



* homebrew_tap: add changelog fragment for #11848



* remove hombrew_tap from PR #11783 changelog - change reverted here

---------


(cherry picked from commit c4ed3467b6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:32:10 +02:00
patchback[bot]
644d362228 [PR #11851/1db3d4f4 backport][stable-12] gitlab_project_members: fail when multiple projects match by name (#11864)
gitlab_project_members: fail when multiple projects match by name (#11851)

* gitlab_project_members: fail when multiple projects match by name

When the project parameter is a bare name (not a full path), and the
search returns more than one match, the module now fails with a clear
error asking the user to provide the full path (group/project) to
disambiguate, instead of silently operating on the first result.

Fixes #2767



* gitlab_project_members: improve code formatting



* gitlab_project_members: add changelog fragment for #11851



---------


(cherry picked from commit 1db3d4f441)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 18:32:02 +02:00
patchback[bot]
8def5bf46e [PR #11850/f8869af6 backport][stable-12] homebrew_cask: fix sudo_password failing with special characters (#11867)
homebrew_cask: fix sudo_password failing with special characters (#11850)

* homebrew_cask: fix sudo_password with special characters in password

The SUDO_ASKPASS script embedded the password inside single quotes, which
breaks shell parsing whenever the password contains a single quote. Use a
quoted heredoc (cat <<'SUDO_PASS') instead, which treats the content
completely literally regardless of special characters.

Also replace .file.close() with .flush() (correct semantics — flushes
the write buffer without leaving the NamedTemporaryFile in a half-closed
state) and remove the redundant add_cleanup_file() call (the context
manager already deletes the file on exit).

Fixes #4957



* homebrew_cask: add changelog fragment for #11850



* homebrew_cask: fix sudo_password example and clarify ansible_become_password



* homebrew_cask: use shlex.quote() for sudo_password instead of heredoc

shlex.quote() is the standard Python approach for shell-safe quoting
and handles all special characters without the edge cases of heredocs.



---------


(cherry picked from commit f8869af65f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:31:52 +02:00
patchback[bot]
057fd16cc0 [PR #11861/076bc4e0 backport][stable-12] etcd3 lookup - improve HTTPS connection handling and docs (#11871)
etcd3 lookup - improve HTTPS connection handling and docs (#11861)

* etcd3 lookup - improve HTTPS connection handling and documentation

Improve user experience when connecting to HTTPS etcd3 endpoints:
- Strip URL scheme from host option when present, with a warning
- Warn when HTTPS endpoint is specified but ca_cert is not provided
- Document that ca_cert is required to enable TLS
- Add HTTPS connection example
- Fix minor doc markup issue in notes section

Fixes #1664



* Add changelog fragment for PR 11861



---------


(cherry picked from commit 076bc4e03b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 18:31:39 +02:00
patchback[bot]
3a56f19656 [PR #11862/342a76d5 backport][stable-12] Remove unstable CI target (#11870)
Remove unstable CI target (#11862)

Remove unstable CI target.

(cherry picked from commit 342a76d5dd)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-17 18:31:21 +02:00
patchback[bot]
729eb996e8 [PR #11836/ef656cb9 backport][stable-12] CI: Replace Fedora 43 with 44 for devel (#11846)
CI: Replace Fedora 43 with 44 for devel (#11836)

* Replace Fedora 43 with 44 for devel in CI.

* Adjust tests.

* Adjust flatpak module to Fedora 44.

(cherry picked from commit ef656cb9b6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-16 22:00:37 +02:00
patchback[bot]
3e721f9572 [PR #11842/7884a3f2 backport][stable-12] CI: Temporarily skip failing callback unit tests for ansible-core 2.21+ (#11844)
CI: Temporarily skip failing callback unit tests for ansible-core 2.21+ (#11842)

Temporarily skip failing unit tests.

(cherry picked from commit 7884a3f2a2)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-16 21:39:55 +02:00
patchback[bot]
4d30704615 [PR #11826/7dcd3c1c backport][stable-12] lxd_container: document that config values must be strings (#11829)
lxd_container: document that config values must be strings (#11826)

Fixes #8307


(cherry picked from commit 7dcd3c1c45)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 22:01:36 +02:00
patchback[bot]
308a5d7e06 [PR #11823/71723268 backport][stable-12] lvol: fix LVM version regex to handle date formats without dashes (#11831)
lvol: fix LVM version regex to handle date formats without dashes (#11823)

* lvol: fix LVM version regex to handle date formats without dashes

Fixes #5445



* lvol: add changelog fragment for issue 5445



---------


(cherry picked from commit 7172326868)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 22:01:28 +02:00
patchback[bot]
f78a44c6a3 [PR #11825/d1448b76 backport][stable-12] iso_extract: strip leading path separator from file entries (#11832)
iso_extract: strip leading path separator from file entries (#11825)

* iso_extract: strip leading path separator from file entries

Fixes #5283



* iso_extract: add changelog fragment for issue 5283



---------


(cherry picked from commit d1448b76c1)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 22:01:19 +02:00
patchback[bot]
1b4e58bbbf [PR #11811/ff5c34c4 backport][stable-12] lvm_pv - use CmdRunner (#11833)
lvm_pv - use CmdRunner (#11811)

* lvm_pv - migrate to CmdRunner using shared runners from module_utils/_lvm



* lvm_pv - add changelog fragment for #11811



* Update changelogs/fragments/11811-lvm_pv-use-cmdrunner.yml



---------



(cherry picked from commit ff5c34c4a7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-15 22:01:11 +02:00
patchback[bot]
705ffc564d [PR #11771/df252e5f backport][stable-12] incus, machinectl, run0 - fix become over pty connections (#11827)
incus, machinectl, run0 - fix become over pty connections (#11771)

* incus, machinectl, run0 - fix become over pty connections

Four small fixes across three plugins, all discovered while trying to
use community.general.machinectl (and later community.general.run0)
as become methods over the community.general.incus connection.

Core bug: machinectl and run0 both set require_tty = True, but the
incus connection plugin was ignoring that hint and invoking
'incus exec' without -t. Honor require_tty by passing -t, mirroring
what the OpenSSH plugin does with -tt.

Once the pty is in place, both become plugins emit terminal control
sequences (window-title OSC, ANSI reset) around the child command
that land in captured stdout alongside the module JSON and trip the
result parser with "Module invocation had junk after the JSON data".
Suppress that decoration at the source by prefixing the constructed
shell command with SYSTEMD_COLORS=0. TERM=dumb would work too but
has a wider blast radius (it also affects interactive tools inside
the become-user session); SYSTEMD_COLORS is the documented
systemd-scoped knob.

run0 was also missing pipelining = False. When run0 is used over a
connection that honors require_tty, ansible's pipelining sends the
module source on stdin to remote python3, which cannot be forwarded
cleanly through the pty chain and hangs indefinitely. Disable
pipelining the same way community.general.machinectl already does.

Also add tests/unit/plugins/become/test_machinectl.py mirroring the
existing test_run0.py. machinectl had no unit test coverage before,
which is why CI did not catch the SYSTEMD_COLORS=0 prefix change
when the equivalent run0 change broke test_run0_basic/test_run0_flags.



* Update changelogs/fragments/11771-incus-machinectl-run0-become-pty.yml



---------



(cherry picked from commit df252e5fab)

Co-authored-by: Martin Schürrer <martin@schuerrer.org>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-15 22:01:06 +02:00
patchback[bot]
86dc3c8816 [PR #11815/78d004d9 backport][stable-12] lvg: clarify desired-state semantics of pvs parameter in docs (#11821)
lvg: clarify desired-state semantics of pvs parameter in docs (#11815)

lvg: doc adjustment
(cherry picked from commit 78d004d96e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-14 22:03:13 +02:00
patchback[bot]
1b1746896d [PR #11772/24ca7965 backport][stable-12] dconf: add dbus-broker support by improving D-Bus session discovery (#11820)
dconf: add dbus-broker support by improving D-Bus session discovery (#11772)

* dconf: add dbus-broker support by improving D-Bus session discovery

Extend DBusWrapper._get_existing_dbus_session() to check:
1. DBUS_SESSION_BUS_ADDRESS in the current process environment
2. /run/user/<uid>/bus (canonical socket for systemd and dbus-broker)
3. Process scan (legacy fallback, as before)

Also add _validate_address() to support both dbus-send and busctl,
making the module work on systems using dbus-broker (e.g. Fedora Silverblue)
where no process exposes DBUS_SESSION_BUS_ADDRESS in its environment.

Fixes: https://github.com/ansible-collections/community.general/issues/495



* dconf: add changelog fragment for dbus-broker support



* dconf: restore dbus validator requirement and example usage

Restore fail_json when neither dbus-send nor busctl is available,
preserving the original hard requirement for a validator binary.
Restore the example invocation in DBusWrapper docstring.



---------


(cherry picked from commit 24ca79658a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:02:54 +02:00
patchback[bot]
32c4bbea30 [PR #11748/972bed66 backport][stable-12] flatpak: add from_url parameter, deprecate URLs in name (#11814)
flatpak: add from_url parameter, deprecate URLs in name (#11748)

* flatpak: add from_url parameter, deprecate URLs in name

Adds a new `from_url` parameter for installing flatpaks from a
.flatpakref URL, using `flatpak install --from <url>`. The `name`
parameter then carries the reverse DNS application ID, enabling
reliable idempotency checks.

Passing URLs directly in `name` is now deprecated and will be
removed in community.general 14.0.0.

Fixes #4000



* flatpak: add changelog fragment for PR #11748



* flatpak: remove deprecation, adjust docs tone



* flatpak: add integration tests for from_url parameter



---------


(cherry picked from commit 972bed66f4)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-13 21:30:31 +02:00
patchback[bot]
e278490fe7 [PR #11746/61060532 backport][stable-12] feat: use CmdRunner for LVM commands (#11794)
feat: use CmdRunner for LVM commands (#11746)

* feat: use CmdRunner for LVM commands

* Update plugins/module_utils/lvm.py



* rename module util to _lvm

---------


(cherry picked from commit 61060532f9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-12 22:29:22 +02:00
patchback[bot]
d01187d03b [PR #11768/b40608a3 backport][stable-12] Ensure standard locale in run_command (group5-batch1) (#11795)
Ensure standard locale in run_command (group5-batch1) (#11768)

* ensure standard locale in run_command (group5-batch1)

Adds ``LANGUAGE=C`` and ``LC_ALL=C`` to ``run_command()`` calls in modules
that parse command output, to prevent locale-dependent parsing failures on
non-C-locale systems.

Modules updated: apache2_module, composer, facter_facts, known_hosts module
utils, lvg_rename, macports, modprobe, monit, open_iscsi, pacman_key,
rhsm_release, rpm_ostree_pkg, sysupgrade.



* add changelog fragment for group5-batch1



* Remove lvg_rename from locale fix — superseded by PR #11746

PR #11746 (feat: use CmdRunner for LVM commands) takes priority and
will handle lvg_rename.py via CmdRunner refactor. Removing our
run_command_environ_update change to avoid conflict.



---------


(cherry picked from commit b40608a39d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:29:14 +02:00
patchback[bot]
3ef5b36066 [PR #11773/8fbb43e6 backport][stable-12] Ensure standard locale in run_command (group5-batch2) (#11806)
Ensure standard locale in run_command (group5-batch2) (#11773)

* ensure standard locale in run_command (group5-batch2)

Adds ``LANGUAGE=C`` and ``LC_ALL=C`` to ``run_command()`` calls in modules
that parse command output, to prevent locale-dependent parsing failures on
non-C-locale systems.

Modules updated: cronvar, dnf_versionlock, dpkg_divert, flatpak_remote, hg.



* add changelog fragment for group5-batch2



---------


(cherry picked from commit 8fbb43e660)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:29:04 +02:00
patchback[bot]
150f63b36b [PR #11779/d6909578 backport][stable-12] Ensure standard locale in run_command (group5-batch8) (#11804)
Ensure standard locale in run_command (group5-batch8) (#11779)

* Fix locale env vars in run_command() calls for group5 batch8 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in lxc_container, ip_netns,
and capabilities.



* Add changelog fragment for PR #11779



---------


(cherry picked from commit d6909578b9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:52 +02:00
patchback[bot]
582807ea3a [PR #11780/5c6a5999 backport][stable-12] Ensure standard locale in run_command (group5-batch9) (#11803)
Ensure standard locale in run_command (group5-batch9) (#11780)

* Fix locale env vars in run_command() calls for group5 batch9 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in beadm, pkg5, pkg5_publisher,
and swdepot.



* Add changelog fragment for PR #11780



---------


(cherry picked from commit 5c6a599940)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:44 +02:00
patchback[bot]
bdcd10ca2c [PR #11781/5f0a9bba backport][stable-12] Ensure standard locale in run_command (group5-batch10) (#11802)
Ensure standard locale in run_command (group5-batch10) (#11781)

* Fix locale env vars in run_command() calls for group5 batch10 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in imgadm, smartos_image_info,
syspatch, portage, portinstall, xbps, and lbu.



* Add changelog fragment for PR #11781



---------


(cherry picked from commit 5f0a9bba01)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:35 +02:00
patchback[bot]
42e88c56b6 [PR #11782/fe9e7284 backport][stable-12] Ensure standard locale in run_command (group5-batch11) (#11801)
Ensure standard locale in run_command (group5-batch11) (#11782)

* Fix locale env vars in run_command() calls for group5 batch11 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in apt_repo, easy_install, pear,
and zypper_repository_info.



* Add changelog fragment for PR #11782



---------


(cherry picked from commit fe9e728401)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:26 +02:00
patchback[bot]
d858cfa8a8 [PR #11783/9cadc947 backport][stable-12] Ensure standard locale in run_command (group5-batch12) (#11800)
Ensure standard locale in run_command (group5-batch12) (#11783)

* Fix locale env vars in run_command() calls for group5 batch12 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in bower, bundler, homebrew_tap,
and kibana_plugin.



* Add changelog fragment for PR #11783



---------


(cherry picked from commit 9cadc94793)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:19 +02:00
patchback[bot]
15d5670065 [PR #11784/3f7ae199 backport][stable-12] Ensure standard locale in run_command (group5-batch13) (#11799)
Ensure standard locale in run_command (group5-batch13) (#11784)

* Fix locale env vars in run_command() calls for group5 batch13 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in awall, openwrt_init, and
pip_package_info.



* Add changelog fragment for PR #11784



---------


(cherry picked from commit 3f7ae1999e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:12 +02:00
patchback[bot]
e5f55149c6 [PR #11785/269a5ed8 backport][stable-12] Ensure standard locale in run_command (group5-batch14) (#11797)
Ensure standard locale in run_command (group5-batch14) (#11785)

* Fix locale env vars in run_command() calls for group5 batch14 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in bzr, lldp, and ohai.



* Add changelog fragment for PR #11785



---------


(cherry picked from commit 269a5ed85e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:00 +02:00
patchback[bot]
50d22c9f70 [PR #11786/37653bc7 backport][stable-12] Ensure standard locale in run_command (group5-batch15) (#11796)
Ensure standard locale in run_command (group5-batch15) (#11786)

* Fix locale env vars in run_command() calls for group5 batch15 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in keyring_info, onepassword_info,
and riak.



* Add changelog fragment for PR #11786



---------


(cherry picked from commit 37653bc7f9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:47 +02:00
patchback[bot]
671ce86565 [PR #11787/95e2b771 backport][stable-12] Ensure standard locale in run_command (group5-batch16) (#11798)
Ensure standard locale in run_command (group5-batch16) (#11787)

* Fix locale env vars in run_command() calls for group5 batch16 (btrfs module_utils)



* Add changelog fragment for PR #11787



---------


(cherry picked from commit 95e2b7716a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:35 +02:00
patchback[bot]
0fc99ae2d8 [PR #11774/6d5644ac backport][stable-12] Ensure standard locale in run_command (group5-batch3) (#11807)
Ensure standard locale in run_command (group5-batch3) (#11774)

* Fix locale env vars in run_command() calls for group5 batch3 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in homectl, java_cert, keyring,
launchd, and listen_ports_facts.



* Add changelog fragment for PR #11774



---------


(cherry picked from commit 6d5644ac34)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:28 +02:00
patchback[bot]
dfa9f77b7a [PR #11775/7c52f1c4 backport][stable-12] Ensure standard locale in run_command (group5-batch4) (#11808)
Ensure standard locale in run_command (group5-batch4) (#11775)

* Fix locale env vars in run_command() calls for group5 batch4 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in logstash_plugin, lvg, mas,
osx_defaults, and pkgutil.



* Add changelog fragment for PR #11775



---------


(cherry picked from commit 7c52f1c41d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:16 +02:00
patchback[bot]
cfa712f30e [PR #11776/e45e6cbb backport][stable-12] Ensure standard locale in run_command (group5-batch5) (#11809)
Ensure standard locale in run_command (group5-batch5) (#11776)

* Fix locale env vars in run_command() calls for group5 batch5 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in pnpm, sysrc, timezone, xattr,
and yarn.



* Add changelog fragment for PR #11776



---------


(cherry picked from commit e45e6cbb5d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:07 +02:00
patchback[bot]
c65a675a52 [PR #11777/a9d6bb2a backport][stable-12] Ensure standard locale in run_command (group5-batch6) (#11810)
Ensure standard locale in run_command (group5-batch6) (#11777)

* Fix locale env vars in run_command() calls for group5 batch6 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in yum_versionlock and zypper_repository.



* Add changelog fragment for PR #11777



---------


(cherry picked from commit a9d6bb2a15)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:27:00 +02:00
patchback[bot]
e757ff30b3 [PR #11778/42a1998b backport][stable-12] Ensure standard locale in run_command (group5-batch7) (#11805)
Ensure standard locale in run_command (group5-batch7) (#11778)

* Fix locale env vars in run_command() calls for group5 batch7 modules

Set LANGUAGE=C and LC_ALL=C via run_command_environ_update to ensure
locale-independent output parsing in zfs, zfs_delegate_admin,
zfs_facts, and zpool_facts.



* Add changelog fragment for PR #11778



---------


(cherry picked from commit 42a1998bde)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:26:47 +02:00
patchback[bot]
d74e553f4b [PR #11767/f4f2bfe8 backport][stable-12] openbsd_pkg, sorcery: ensure standard locale in run_command (group4-batch2) (#11793)
openbsd_pkg, sorcery: ensure standard locale in run_command (group4-batch2) (#11767)

* ensure standard locale in run_command (group4-batch2)

Adds ``LANGUAGE=C`` and ``LC_ALL=C`` to the ``environ_update`` passed to
``run_command()`` calls in modules that parse command output, to prevent
locale-dependent parsing failures on non-C-locale systems.

Modules updated: openbsd_pkg, sorcery.



* add changelog fragment for group4-batch2



* add changelog fragment for group4-batch2



---------


(cherry picked from commit f4f2bfe847)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 13:43:30 +02:00
patchback[bot]
d5a759b2e3 [PR #11765/2297a5c8 backport][stable-12] Ensure standard locale in run_command (group4-batch1) (#11792)
Ensure standard locale in run_command (group4-batch1) (#11765)

* ensure standard locale in run_command (group4)

Adds ``LANGUAGE=C`` and ``LC_ALL=C`` to the ``environ_update`` passed to
``run_command()`` calls in modules that parse command output, to prevent
locale-dependent parsing failures on non-C-locale systems.

Modules updated: dconf, pkgng, terraform.



* add changelog fragment for group4



* add PR link to group4 changelog fragment



* fix changelog fragment: rename with PR prefix, fix URL order



---------


(cherry picked from commit 2297a5c876)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 13:38:43 +02:00
patchback[bot]
c8f2219fb0 [PR #11733/6f12d930 backport][stable-12] gem: use CmdRunner (#11791)
gem: use `CmdRunner` (#11733)

* gem: use `CmdRunner`

* add changelog frag

* gem: restore get_rubygems_path() helper to preserve executable splitting



---------


(cherry picked from commit 6f12d93057)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 13:38:08 +02:00
patchback[bot]
8fe227d456 [PR #11487/5eaa22b0 backport][stable-12] ipa_host: fix errors when disabling host (#11789)
ipa_host: fix errors when disabling host (#11487)

* fix errors when disabling host

- Fix the logic to actually allow disabling hosts
- Fix the dict != string error when error does happen
- Add has_keytab to returned dicts to allow users see if host is disabled or not

* Add changelog-fragments

* Run formatters

* More formatting

* Remove feature, only fix the logic

* Update changelogs/fragments/11487-ipa-host-fix-disable.yml



* Update changelogs/fragments/11487-ipa-host-fix-disable.yml



* Back to fstring

* Update plugins/modules/ipa_host.py



* Use more Pythonic way to for if

* Nox

* Revert back to working if

* Simplify if

* Remove extra get

---------




(cherry picked from commit 5eaa22b067)

Co-authored-by: quasd <quasd@users.noreply.github.com>
Co-authored-by: quasd <1747330+quasd@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-12 13:37:56 +02:00
patchback[bot]
59fe80ef94 [PR #11712/bd7b361d backport][stable-12] nsupdate: fix GSS-TSIG support (#11790)
nsupdate: fix GSS-TSIG support (#11712)

The fix for missing keyring initialization without TSIG auth in
PR #11461 put the initialization of "self.keyring" and "self.keyname"
in an else clause after checking if "key_name" is set.

The problem is that for "key_algorithm" == "gss-tsig":
a) "key_name" isn't set
b) self.keyring and self.keyname have already been initialized and
   will be discarded

This means that gss-tsig support is broken. Fix it by moving the
initialization of "self.keyring" and "self.keyname" to the top.

(cherry picked from commit bd7b361db1)

Co-authored-by: David Härdeman <david@hardeman.nu>
2026-04-12 13:37:47 +02:00
patchback[bot]
d9a2fa9bd9 [PR #11753/c7deda2e backport][stable-12] java_cert: support proxy authentication from https_proxy env var (#11761)
java_cert: support proxy authentication from https_proxy env var (#11753)

* java_cert: support proxy authentication from https_proxy env var

When https_proxy is set with credentials (USER:PASSWORD@HOST:PORT),
pass the corresponding JVM proxy auth flags to keytool and clear the
JDK 8u111+ Basic auth tunneling restriction.

Fixes https://github.com/ansible-collections/community.general/issues/4126



* java_cert: add changelog fragment for PR #11753



* java_cert: fix changelog fragment type to minor_changes



---------


(cherry picked from commit c7deda2ec7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 06:35:16 +02:00
Felix Fontein
a046ae812e Prepare 12.6.0. 2026-04-08 20:13:58 +02:00
patchback[bot]
953d70611b [PR #11754/b780224d backport][stable-12] mssql_script: only pass params to cursor.execute() when provided (#11758)
mssql_script: only pass params to cursor.execute() when provided (#11754)

* mssql_script: only pass params to cursor.execute() when provided

Fixes #11699



* mssql_script: add changelog fragment for PR #11754



---------


(cherry picked from commit b780224d6d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 20:06:07 +02:00
patchback[bot]
04367d8b9c [PR #11742/bdd31745 backport][stable-12] nmcli: use get_best_parsable_locale() to support UTF-8 connection names (#11757)
nmcli: use get_best_parsable_locale() to support UTF-8 connection names (#11742)

* nmcli: start locale fix - normalize run_command environ to LANGUAGE=C, LC_ALL=C

Work in progress - issue #10384 (UTF-8 conn_name support) requires deeper
investigation beyond simple locale variable normalization.



* nmcli: use get_best_parsable_locale() to support UTF-8 connection names

Fixes issue where UTF-8 connection names (e.g. Chinese characters) were
corrupted to '????' when LC_ALL=C forced ASCII encoding, causing
connection_exists() to always return False for non-ASCII names.



* add changelog fragment for PR #11742



---------


(cherry picked from commit bdd3174563)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:46:30 +02:00
patchback[bot]
e5f9516335 [PR #11741/e59888dd backport][stable-12] Ensure standard locale in run_command (group3-batch3) (#11756)
Ensure standard locale in run_command (group3-batch3) (#11741)

* run_command locale group3 batch3: normalise to LANGUAGE=C, LC_ALL=C



* fix changelog fragment: bugfixes, American English, separate code spans



* fix changelog fragment: correct PR number (11741)



---------


(cherry picked from commit e59888dd7e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:34:34 +02:00
patchback[bot]
b4f09831b0 [PR #11740/936ab2ea backport][stable-12] Ensure standard locale in run_command (group3-batch2) (#11755)
Ensure standard locale in run_command (group3-batch2) (#11740)

* run_command locale group3 batch2: normalise to LANGUAGE=C, LC_ALL=C



* fix changelog fragment: bugfixes, American English, separate code spans



* fix changelog fragment: correct PR number (11740)



* remove nmcli from batch2 - moved to dedicated branch



---------


(cherry picked from commit 936ab2ea56)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 15:34:23 +02:00
patchback[bot]
5f5043d4b8 [PR #11743/849a7ee8 backport][stable-12] Add stable-2.21 to CI (#11745)
Add stable-2.21 to CI (#11743)

Add stable-2.21 to CI.

(cherry picked from commit 849a7ee899)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-06 22:13:07 +02:00
patchback[bot]
ea465e21c3 [PR #11738/c90b5046 backport][stable-12] Ensure standard locale in run_command (group3-batch1) (#11739)
Ensure standard locale in run_command (group3-batch1) (#11738)

* ensure standard locale in run_command (group3-batch1)

* add changelog frag

* fix changelog fragment: bugfixes, not minor_changes



* fix changelog fragment: American English, separate code spans per variable



---------


(cherry picked from commit c90b504626)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 10:05:05 +02:00
patchback[bot]
f00f70f849 [PR #11717/b2cd1b55 backport][stable-12] Fix KeyError for 'dnsttl' (#11736)
Fix KeyError for 'dnsttl' (#11717)

* Fix KeyError for 'dnsttl'

I did not further dig into the code. However, since upgrading to the latest version of `community.general`, ansible fails with a weird error message "dnsttl" at a task where `community.general.ipa_dnsrecord` is called. After digging into the code a bit, I found out that it is a KeyError and caused by this line of code. I'm not sure, if it is safe to skip that line and not to set `result["dnsttl"]`.

* Add changelog fragment

* Adopt suggestion for changelogs/fragments/11717-fix-error-dnsttl.yml



---------


(cherry picked from commit b2cd1b555e)

Co-authored-by: sedrubal <sedrubal@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-04 18:44:05 +00:00
patchback[bot]
6020893160 [PR #11729/bdb82c72 backport][stable-12] chore: devcontainer/pre-commit (#11732)
chore: devcontainer/pre-commit (#11729)

(cherry picked from commit bdb82c7248)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-04 11:00:27 +02:00
patchback[bot]
1eecf281bc [PR #11728/2acb20be backport][stable-12] opendj_backendprop: use CmdRunner (#11731)
opendj_backendprop: use CmdRunner (#11728)

* opendj_backendprop: use CmdRunner

* add changelog frag

(cherry picked from commit 2acb20bec2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-03 15:21:16 +02:00
patchback[bot]
fa9ac2b3a9 [PR #11719/66886d08 backport][stable-12] integration tests: remove CentOS conditionals - part 2 (#11730)
integration tests: remove CentOS conditionals - part 2 (#11719)

* test(integration): remove CentOS references - part 2

* adjustments from review

(cherry picked from commit 66886d08f5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-03 12:34:15 +00:00
patchback[bot]
f77d731faf [PR #11715/79431c36 backport][stable-12] integration tests: remove CentOS conditionals (#11726)
integration tests: remove CentOS conditionals (#11715)

* test(integration): remove CentOS references

* further simplification

* more removals

* rollback systemd_info for now

* ufw: not trivially used with RHEL9 and RHEL10, simplifying tests

* remove tasks for setup_epel where unused

* adjustments from review

(cherry picked from commit 79431c36b5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-03 10:41:10 +02:00
patchback[bot]
56bcb0c32b [PR #11697/8b114e99 backport][stable-12] consul integration tests: re-enable on macOS (#11727)
consul integration tests: re-enable on macOS (#11697)

* consul integration tests: re-enable on macOS

- Update consul version to 1.22.6
- Add arm64/aarch64 architecture support
- Fix macOS Gatekeeper quarantine on downloaded binary
- Add wait_for before ACL bootstrap (race condition fix)
- Update HCL config to use tls stanza (required in 1.22)
- Disable gRPC port (conflicts with tls stanza when not configured)
- Remove skip/macos from aliases

Fixes: https://github.com/ansible-collections/community.general/issues/1016



* changelogs/fragments: add PR number for consul tests fix



* remove changelog fragment (test-only PR)



---------


(cherry picked from commit 8b114e999e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 08:03:09 +02:00
patchback[bot]
83aa142331 [PR #11682/b79a4575 backport][stable-12] snap_connect: new module to manage snap interface connections (#11722)
snap_connect: new module to manage snap interface connections (#11682)

* snap_connect: new module to manage snap interface connections

Fixes #7722



* simplify _get_connections()

---------


(cherry picked from commit b79a45753f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 07:35:13 +02:00
patchback[bot]
cac85a5480 [PR #11720/982f9472 backport][stable-12] test(integration): fix for ansible-core devel changes in register (#11724)
test(integration): fix for ansible-core devel changes in register (#11720)

(cherry picked from commit 982f9472c5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-03 07:35:02 +02:00
patchback[bot]
3bca7e1ad4 [PR #11721/08442186 backport][stable-12] xenserver_guest: fix code style caught by codeqa (#11725)
xenserver_guest: fix code style caught by codeqa (#11721)

* xenserver_guest: fix code style caught by codeqa

* add changelog frag

(cherry picked from commit 08442186e6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-03 07:34:32 +02:00
patchback[bot]
b41916285e [PR #11701/d956fb81 backport][stable-12] jira - add cloud option to support Jira Cloud search endpoint (#11716)
jira - add cloud option to support Jira Cloud search endpoint (#11701)

* jira - add cloud option to support Jira Cloud search endpoint

Jira Cloud has removed the legacy GET /rest/api/2/search endpoint
(see https://developer.atlassian.com/changelog/#CHANGE-2046).

Add a new boolean `cloud` option (default false). When set to true,
the search operation uses the replacement /rest/api/2/search/jql
endpoint. The default remains false to preserve backward compatibility
for Jira Data Center / Server users.

Fixes: https://github.com/ansible-collections/community.general/issues/10786

Assisted-by AI: Claude 4.6 Opus (Anthropic) via Cursor IDE



* Adding PR link to changelogs/fragments/10786-jira-cloud-search.yml



* Adding note about future usage of cloud parameter



---------



(cherry picked from commit d956fb8197)

Signed-off-by: Vladimir Vasilev <vvasilev@redhat.com>
Co-authored-by: vladi-k <53343355+vladi-k@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-04-01 07:06:25 +02:00
patchback[bot]
1df4b3ee74 [PR #11690/f4e5fc09 backport][stable-12] monit: re-enable tests in RHEL (#11714)
monit: re-enable tests in RHEL (#11690)

* re-enable monit tests in rhel

* enable EPEL for RHEL<11

* rollback EPEL setup, skip only specific versions

* remove skip entirely

* change download URL in setup_epel, adjusted code to use it

* claude tries to install virtualenv, round 1

* claude tries python3 -m venv instead

* remove outdated centos6 file

(cherry picked from commit f4e5fc09d7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-04-01 07:06:16 +02:00
patchback[bot]
ae089aefad [PR #11688/85685944 backport][stable-12] flatpak: fix removal of runtimes (#11713)
flatpak: fix removal of runtimes (#11688)

* flatpak: fix removal of runtimes (issue #553)

The module was using `--app` when listing installed flatpaks for name
matching, which excluded runtimes from the results. This caused removal
of runtimes to fail even though `flatpak_exists()` correctly detected
them as installed (it lists both apps and runtimes).

Fix by dropping `--app` from the three matching functions so that both
apps and runtimes are searchable.



* flatpak: add changelog fragment for PR #11688



---------


(cherry picked from commit 8568594453)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 08:06:46 +02:00
patchback[bot]
f92fedcfa0 [PR #11683/5a27cbde backport][stable-12] snmp_facts: update to pysnmp >= 7.1 async API (#11711)
snmp_facts: update to pysnmp >= 7.1 async API (#11683)

* snmp_facts: update to pysnmp >= 7.1 async API

Migrate snmp_facts module from the removed pysnmp oneliner API
(pysnmp.entity.rfc3413.oneliner.cmdgen) to the current async API
(pysnmp.hlapi.v3arch.asyncio).

This fixes compatibility with Python 3.12+ and pysnmp >= 7.1.

Closes #8852

* Continue to support pysnmp 6.2.4

* Correct PR number

* sort imports

* shorter changelog

* move `SNMP_DEFAULT_PORT`

* Add `notes:`

* Become an author

* use `deps.declare`

* add lalten to BOTMETA

(cherry picked from commit 5a27cbdec6)

Co-authored-by: Laurenz <lalten@users.noreply.github.com>
2026-03-30 22:33:30 +02:00
patchback[bot]
9d269ee8ca [PR #11698/47ef322a backport][stable-12] ipa module utils: detect and fail on errors in API response failed field (#11710)
ipa module utils: detect and fail on errors in API response `failed` field (#11698)

* ipa_* modules: detect and fail on errors in API response ``failed`` field

Fixes: https://github.com/ansible-collections/community.general/issues/1239



* fix chglog frag

* adjust chglog frag

---------


(cherry picked from commit 47ef322a5f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 21:43:39 +02:00
patchback[bot]
66d394dc81 [PR #11686/68ae04a9 backport][stable-12] Cleanup of aliases skip statements (#11709)
Cleanup of `aliases` skip statements (#11686)

* add scripts to clean aliases' skips

* remove legacy skips

* code cosmetics

* add license to ALIASES.md

* Fix typos in ALIASES.md documentation

* rolling back freebsd14.2 and 14.3 in iso_extract

* fix versions and re-run

(cherry picked from commit 68ae04a95a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-30 19:58:13 +02:00
patchback[bot]
de180d01e0 [PR #11689/a4bba992 backport][stable-12] composer - make create-project idempotent, add force parameter (#11700)
composer - make `create-project` idempotent, add `force` parameter (#11689)

* composer - make create-project idempotent, add force parameter

Adds a check for an existing composer.json in working_dir before running
create-project, so the task is skipped rather than failing on second run.
A new force parameter allows bypassing this check when needed.

Fixes #725.



* changelog fragment: rename to PR number, add PR URL



---------


(cherry picked from commit a4bba99203)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 21:34:35 +01:00
patchback[bot]
1a1056099c [PR #11685/909458a6 backport][stable-12] docs: improve timezone module examples and add hwclock usage (#11696)
docs: improve timezone module examples and add hwclock usage (#11685)

* docs: add variable-based example for timezone module

### Summary
Added a variable-based example to the EXAMPLES section of the timezone module.

### Changes
- Added an example demonstrating how to set timezone dynamically using a variable

### Motivation
Using variables is a common practice in Ansible playbooks. This example helps users understand how to make the module usage more flexible and reusable.

* docs: improve timezone module examples with hwclock usage

### Summary
Improved the EXAMPLES section of the timezone module by adding a more meaningful, module-specific example.

### Changes
- Added an example demonstrating usage of the `hwclock` parameter
- Simplified examples to avoid redundancy
- Fixed formatting issues causing CI failures (invalid YAML, lint errors)

### Motivation
The previous examples were minimal and did not demonstrate module-specific features. This update adds a more practical use case and ensures the examples follow proper formatting and validation rules.

(cherry picked from commit 909458a661)

Co-authored-by: Anshjeet Mahir <anshjeetmahir123@gmail.com>
2026-03-27 12:45:03 +01:00
patchback[bot]
300f525ff9 [PR #11673/12af50cf backport][stable-12] docs: add Execution Environment guide (#11693)
docs: add Execution Environment guide (#11673)

* docs: add Execution Environment guide

Closes #2968
Closes #4512



* add to botmeta

* fix code block language

* Apply suggestions from code review



* Update section title for community.general EE metadata

* Apply suggestion from felixfontein



* Remove extraneous paragraph

* Apply suggestions from code review




* remove link to legacy documentation

* Update docs/docsite/rst/guide_ee.rst



---------




(cherry picked from commit 12af50cfb7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Don Naro <dnaro@redhat.com>
2026-03-26 22:20:21 +01:00
patchback[bot]
03a639e809 [PR #11677/ef700b11 backport][stable-12] nsupdate: add unit tests (#11692)
nsupdate: add unit tests (#11677)

* nsupdate: add unit tests



* fix var name to regain sanity

* remove unneeded typing from test file

* formatting

---------


(cherry picked from commit ef700b116a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 21:47:56 +01:00
patchback[bot]
f739035d1f [PR #11681/e2c06f2d backport][stable-12] pacman: add root, cachedir, and config options (#11684)
pacman: add root, cachedir, and config options (#11681)

* pacman: add root, cachedir, and config options

Add three dedicated options -- O(root), O(cachedir), and O(config) --
so that all pacman commands get the corresponding global flags
(--root, --cachedir, --config) prepended, enabling use cases such as
installing packages into a chroot or alternative root directory
(similar to pacstrap).



* add changelog frag

---------


(cherry picked from commit e2c06f2d12)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 06:47:20 +01:00
patchback[bot]
17e02f87c9 [PR #11678/d06c83eb backport][stable-12] etcd3: re-enable and fix tests, add unit tests (#11680)
etcd3: re-enable and fix tests, add unit tests (#11678)

* etcd3: re-enable and fix tests, add unit tests

- Add unit tests for community.general.etcd3 module (12 tests covering
  state=present/absent, idempotency, check mode, and error paths)
- Fix integration test setup: update etcd binary to v3.6.9 (from v3.2.14),
  download from GitHub releases, add health-check retry loop after start
- Work around etcd3 Python library incompatibility with protobuf >= 4.x
  by setting PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
- Update to FQCNs throughout integration tests
- Re-enable both etcd3 and lookup_etcd3 integration targets

Fixes https://github.com/ansible-collections/community.general/issues/322



* improve use of multiple context managers

---------


(cherry picked from commit d06c83eb68)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 07:05:05 +01:00
patchback[bot]
becbd2d80f [PR #11674/cc59f7eb backport][stable-12] botmeta: fix sorting (#11676)
botmeta: fix sorting (#11674)

(cherry picked from commit cc59f7ebeb)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-24 22:12:26 +01:00
patchback[bot]
aa352ccf45 [PR #11664/d48a0668 backport][stable-12] mssql_*: named instances (#11672)
mssql_*: named instances (#11664)

* mssql_*: named instances

* add changelog frag

* fix changelog

* Update plugins/modules/mssql_db.py

* Update plugins/modules/mssql_db.py

* Update plugins/modules/mssql_script.py

* Update plugins/modules/mssql_script.py

* fix backslashes

* Update plugins/modules/mssql_db.py



* Update plugins/modules/mssql_script.py



---------


(cherry picked from commit d48a066821)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-24 07:00:36 +01:00
Felix Fontein
e5b01dfc01 The next expected release is 12.6.0. 2026-03-23 21:47:25 +01:00
Felix Fontein
a5d830bbf4 Release 12.5.0. 2026-03-23 21:24:48 +01:00
patchback[bot]
02b25fb096 [PR #11655/6d3ab1a8 backport][stable-12] passwordstore lookup: update code meant for Python2 (#11669)
passwordstore lookup: update code meant for Python2 (#11655)

* passwordstore lookup: update code meant for Python2

* add changelog frag

* add check param to subprocess.run() to reinstate sanity

(cherry picked from commit 6d3ab1a80c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 20:35:20 +01:00
patchback[bot]
555d7b9038 [PR #11658/25a4f568 backport][stable-12] puppet: deprecate param timeout (#11665)
puppet: deprecate param timeout (#11658)

* puppet: deprecate param timeout

* add changelog frag

* Update changelogs/fragments/11658-puppet-timeout-deprecation.yml



---------


(cherry picked from commit 25a4f568f9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-23 20:35:09 +01:00
patchback[bot]
4dfe6816a8 [PR #11622/7c039918 backport][stable-12] keycloak_realm: Add support for setting first broker login flow (#11670)
keycloak_realm: Add support for setting first broker login flow (#11622)

* keycloak_realm: Add support for setting first broker login flow

* Update plugins/modules/keycloak_realm.py



* Add changelog fragment

---------


(cherry picked from commit 7c039918e0)

Co-authored-by: Nils Bergmann <Nils1794@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-23 20:34:51 +01:00
patchback[bot]
a12ac59223 [PR #11656/4dad53ab backport][stable-12] counter_enabled callback: honor display_ok_hosts setting (#11667)
counter_enabled callback: honor display_ok_hosts setting (#11656)

* fix(callback/counter_enabled): honor display_ok_hosts setting

* add changelog frag

* Update changelogs/fragments/11656-counter_enabled-display_ok_hosts.yml

(cherry picked from commit 4dad53abac)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 20:34:43 +01:00
patchback[bot]
9d7097ef4d [PR #11635/3c21ac96 backport][stable-12] nmcli: fix setting_types() to properly handle routing_rules as a list type (#11668)
nmcli: fix setting_types() to properly handle routing_rules as a list type (#11635)

* Fix setting_types() to properly handle routing_rules as a list type

* Add changelog fragment for ipv6.routing-rules bugfix

* Update changelogs/fragments/11630-nmcli-ipv6-routing-rules.yml



* Add PR URL to changelog fragment

---------


(cherry picked from commit 3c21ac961b)

Co-authored-by: Ted W. <ted.l.wood@gmail.com>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 20:34:36 +01:00
patchback[bot]
8e4581c0e6 [PR #11659/d6cb56c0 backport][stable-12] osx_defaults: add dict support (#11671)
osx_defaults: add dict support (#11659)

* osx_defaults: add dict support

* add changelog frag

* osx_defaults: fix dict idempotency by using plutil -extract for type-preserving read

The previous approach piped `defaults read` output (old-style plist text)
through `plutil -convert json`. Old-style plist loses boolean type info
(booleans appear as 1/0, indistinguishable from integers), causing the
comparison to fail and reporting changed=True on every run.

Fix by exporting the domain binary plist to a temp file and using
`plutil -extract key json` which correctly preserves all plist types
(booleans stay true/false, integers stay integers, etc.).



* change param from bool to str

* Apply suggestion from review

* Update plugins/modules/osx_defaults.py



---------



(cherry picked from commit d6cb56c022)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-23 20:34:28 +01:00
patchback[bot]
28b50a1e45 [PR #11657/d48e767e backport][stable-12] open_iscsi: support IPv6 portals (#11663)
open_iscsi: support IPv6 portals (#11657)

* fix(modules/open_iscsi): support IPv6 portals

* add changelog frag

(cherry picked from commit d48e767e1e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 07:04:44 +01:00
patchback[bot]
414f0541a5 [PR #11654/b85a1687 backport][stable-12] test: remove redundant unit test requirements (#11662)
test: remove redundant unit test requirements (#11654)

(cherry picked from commit b85a168716)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 07:04:31 +01:00
patchback[bot]
c4da6e4202 [PR #11660/b1ac989c backport][stable-12] remove skip/aix from aliases files (#11661)
remove skip/aix from aliases files (#11660)

(cherry picked from commit b1ac989c70)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-23 07:04:20 +01:00
Felix Fontein
05f3052937 Prepare 12.5.0. 2026-03-22 20:35:05 +01:00
patchback[bot]
919d27676c [PR #11632/69b9a3f8 backport][stable-12] supervisorctl: skip no such process for all (#11652)
supervisorctl: skip no such process for all (#11632)

* feat(supervisorctl): skip no such process for all

Do not fail, if there are no matching processes for name=all

* feat(supervisorctl): add changelog

* Update 11621-skip-no_such_process-for-name-all.yml



* fix(supervisorctl): replace single quotes to double

---------



(cherry picked from commit 69b9a3f8e2)

Co-authored-by: zr0dy <58261587+zr0dy@users.noreply.github.com>
Co-authored-by: zr0dy <zr0dy@mail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-22 20:33:58 +01:00
patchback[bot]
a425d16e7c [PR #11646/8d403dde backport][stable-12] ansible_galaxy_install: new param executable (#11651)
ansible_galaxy_install: new param executable (#11646)

* ansible_galaxy_install: new param executable

* add changelog frag

(cherry picked from commit 8d403dde5b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 20:33:41 +01:00
patchback[bot]
12808f67d5 [PR #11645/a09e879f backport][stable-12] xfconf: fix boolean return values (#11650)
xfconf: fix boolean return values (#11645)

* xfconf: fix boolean return values

* add changelog frag

(cherry picked from commit a09e879ff2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 20:33:31 +01:00
patchback[bot]
268b31b53d [PR #11639/758a445d backport][stable-12] npm: use uthelper for tests (#11644)
npm: use uthelper for tests (#11639)

(cherry picked from commit 758a445d97)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 11:17:30 +01:00
patchback[bot]
fa682e8b40 [PR #11638/4f5e5c9b backport][stable-12] python_runner: add integration tests (#11643)
test(python_runner): add integration tests (#11638)

* test(python_runner): add integration tests

* simplify the test

* add missing quotes

* use setup_remote_tmp_dir

* build venv manually first

(cherry picked from commit 4f5e5c9bb6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 11:17:12 +01:00
patchback[bot]
0f7d508344 [PR #11637/3aa4a298 backport][stable-12] cmd_runner_fmt tests: assert that unpack_* functions can handle _ArgFormat objects (#11642)
test(cmd_runner_fmt): assert that `unpack_*` functions can handle `_ArgFormat` objects (#11637)

test(cmd_runner_fmt): assert that unpack functions can handle _ArgFormat objects

(cherry picked from commit 3aa4a29842)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 11:13:50 +01:00
patchback[bot]
ac771079db [PR #11636/1dfc4fed backport][stable-12] test: uthelper now generates one test function per test case (#11641)
test: uthelper now generates one test function per test case (#11636)

(cherry picked from commit 1dfc4fed40)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-22 11:05:28 +01:00
patchback[bot]
96852b7032 [PR #11631/b4336659 backport][stable-12] CI: Remove FreeBSD 14.3 for devel, and replace macOS 15.3 with 26.3 (#11634)
CI: Remove FreeBSD 14.3 for devel, and replace macOS 15.3 with 26.3 (#11631)

* Replace FreeBSD 14.3 with 14.4, and macOS 15.3 with 26.3.

* FreeBSD 14.4 seems to have the same problem as FreeBSD 15.0, disabling for now.

(cherry picked from commit b4336659f6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-21 21:13:57 +01:00
patchback[bot]
08bb917d59 [PR #11625/bc22fbca backport][stable-12] CI: Replace apt_repository and apt_key with deb822_repository (#11627)
CI: Replace apt_repository and apt_key with deb822_repository (#11625)

Replace apt_repository and apt_key with deb822_repository.

(cherry picked from commit bc22fbcaa0)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-20 08:06:18 +01:00
patchback[bot]
e7e9cf97e5 [PR #11536/dae2157b backport][stable-12] merge_variables: extended merge capabilities added (#11626)
merge_variables: extended merge capabilities added (#11536)

* merge_variables: extended merge capabilities added

This extension gives you more control over the variable merging process of the lookup plugin `merge_variables`. It closes the gap between Puppet's Hiera merging capabilities and the limitations of Ansible's default variable plugin `host_group_vars` regarding fragment-based value definition. You can now decide which merge strategy should be applied to dicts, lists, and other types. Furthermore, you can specify a merge strategy that should be applied in case of type conflicts.

The default behavior of the plugin has been preserved so that it is fully backward-compatible with the already implemented state.



* Update changelogs/fragments/11536-merge-variables-extended-merging-capabilities.yml



* Update plugins/lookup/merge_variables.py



* Periods added at the end of each choice description



* Update plugins/lookup/merge_variables.py



* ref: follow project standard for choice descriptions



* ref: more examples added and refactoring



* Update plugins/lookup/merge_variables.py



* ref: some more comments to examples added



* fix: unused import removed



* ref: re-add "merge" to strategy map



* Update comments



* Specification of transformations solely as string



* Comments updated



* ref: `append_rp` and `prepend_rp` removed
feat: options dict for list transformations re-added
feat: allow setting `keep` for dedup transformation with possible values: `first` (default) and `last`



* ref: improve options documentation



* ref: documentation improved, avoiding words like newer or older in merge description



* Update plugins/lookup/merge_variables.py



* ref: "prio" replaced by "dict"



* feat: two integration tests added



---------





(cherry picked from commit dae2157bb7)

Signed-off-by: Fiehe Christoph  <c.fiehe@eurodata.de>
Co-authored-by: Christoph Fiehe <cfiehe@users.noreply.github.com>
Co-authored-by: Fiehe Christoph <c.fiehe@eurodata.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Mark <40321020+m-a-r-k-e@users.noreply.github.com>
2026-03-19 22:59:56 +01:00
patchback[bot]
deb9d63783 [PR #11585/25b5655b backport][stable-12] keycloak_authentication_v2: verify providerIds (fix 11583) (#11619)
keycloak_authentication_v2: verify providerIds (fix 11583) (#11585)

* 11583 verify providerIds in keycloak_authentication_v2

* 11583 code cleanup

---------


(cherry picked from commit 25b5655be7)

Co-authored-by: thomasbargetz <thomas.bargetz@gmail.com>
Co-authored-by: Thomas Bargetz <thomas.bargetz@rise-world.com>
2026-03-18 18:14:37 +01:00
patchback[bot]
a882022280 [PR #11589/d8bb637c backport][stable-12] nictagadm: don't call is_valid_mac when etherstub is true (#11618)
nictagadm: don't call is_valid_mac when etherstub is true (#11589)

* nictagadm: don't call is_valid_mac when etherstub is true

* Add changelog fragment

* update changelog fragment

* Shorten changelog fragement

* Update changelogs/fragments/nictagadm-etherstub-nonetype-bugfix.yml



---------


(cherry picked from commit d8bb637cba)

Co-authored-by: Adam D <44533090+emptyDir@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-18 07:05:16 +01:00
patchback[bot]
f06bcabeed [PR #11601/e7a253b4 backport][stable-12] keycloak_authentication_v2: covers idp flow overrides in safe swap (fix 11582) (#11617)
keycloak_authentication_v2: covers idp flow overrides in safe swap (fix 11582) (#11601)

* 11582 keycloak_authentication_v2 covers idp flow overrides in safe swap

* 11583 update documentation and comments

(cherry picked from commit e7a253b4c9)

Co-authored-by: thomasbargetz <thomas.bargetz@gmail.com>
2026-03-18 07:05:10 +01:00
patchback[bot]
19462b72ca [PR #11612/5e4fbfee backport][stable-12] Update BOTMETA.yml (#11616)
Update BOTMETA.yml (#11612)

remove myself from teams

(cherry picked from commit 5e4fbfeee0)

Co-authored-by: Anatoly Pugachev <matorola@gmail.com>
2026-03-18 07:04:59 +01:00
patchback[bot]
a8bd4c750b [PR #11586/df9b3044 backport][stable-12] github_secrets_info: new module (#11610)
github_secrets_info: new module (#11586)

* github_secrets_info: new module



* clean tests



* remove pynacl dep



* fqcn



* remove excess output



* just return result as sample



* only print secrets, adapt tests



* Update plugins/modules/github_secrets_info.py



* Update plugins/modules/github_secrets_info.py



* Update plugins/modules/github_secrets_info.py



* t is for typing, and typing is what we did



* add info_module attributes



---------



(cherry picked from commit df9b30448a)

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
Co-authored-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-16 20:28:22 +01:00
patchback[bot]
000b92a425 [PR #11254/cc24e573 backport][stable-12] monit: deprecate support for monit <= 5.18 (#11609)
monit: deprecate support for monit <= 5.18 (#11254)

* monit: deprecate support for monit <= 5.18

* add additional runs for checking version

* add changelog frag

* bump deprecation for 14.0.0

(cherry picked from commit cc24e57307)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-16 20:16:41 +01:00
patchback[bot]
7784fbdf17 [PR #11603/c8fe1e57 backport][stable-12] Fix typing imports (#11607)
Fix typing imports (#11603)

Fix typing imports.

(cherry picked from commit c8fe1e571f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-15 19:53:36 +01:00
patchback[bot]
292bb400eb [PR #11605/f642dac9 backport][stable-12] sssd_info: fix attributes (#11606)
sssd_info: fix attributes (#11605)

Fix attributes.

(cherry picked from commit f642dac900)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-15 19:53:27 +01:00
patchback[bot]
c6ddff0dad [PR #11514/46ffec6f backport][stable-12] github_secrets: new module (#11602)
github_secrets: new module (#11514)

* add support for managing GitHub secrets



* fix tab



* update for sanity



* more sanity fixes



* update botmeta



* formating



* remove list function



* remove docstring, format text strings and return codes



* switch to deps



* black and ruff doesnt get along



* initial unit tests



* update non-existing secret test



* update description and details



* handle when a secret cant be deleted



* fail if not acceptable error codes



* add test for non-acceptable status codes



* remove local ruff config



* allow empty strings



* set required_



* extend tests



* cleanup



* cover all, got a git urlopen error



* cover all, got a git urlopen error



* ensure value cant be None



* check_mode



* bump to 12.5.0



* Update plugins/modules/github_secrets.py



* extend check_mode and related tests



* split constants and return dict when checking secret



* switch to HTTPStatus



* replace DELETE and UPDATE with NO_CONTENT



* Update plugins/modules/github_secrets.py



* Update plugins/modules/github_secrets.py



* update tests



* Update plugins/modules/github_secrets.py



* Update plugins/modules/github_secrets.py



* Update plugins/modules/github_secrets.py



* Update plugins/modules/github_secrets.py



* Update plugins/modules/github_secrets.py



---------



(cherry picked from commit 46ffec6f0e)

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
Co-authored-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-15 16:38:30 +01:00
patchback[bot]
86616b1559 [PR #11592/2d685e7a backport][stable-12] test(monit): use uthelper (#11593)
test(monit): use uthelper (#11592)

(cherry picked from commit 2d685e7a85)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-14 22:34:22 +01:00
patchback[bot]
99ebbbdf49 [PR #11590/ce5d5622 backport][stable-12] replace list(map(...)) with comprehension (#11591)
replace `list(map(...))` with comprehension (#11590)

* replace `list(map(...))` with comprehension

* add changelog frag

(cherry picked from commit ce5d5622b9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-14 17:14:18 +01:00
patchback[bot]
c853dfb1a8 [PR #11559/3194ed9d backport][stable-12] ipa_dnsrecord fix error when using dnsttl and nothing to change (#11587)
ipa_dnsrecord fix error when using dnsttl and nothing to change (#11559)

* ipa_dnsrecord fix error when using dnsttl and nothing to change

* Add changelog and bump version

* ipa_dnsrecord list comp in dnsrecord_find



* 11559 changelog fragment fix capitalization

* ipa_dnsrecord dnsrecord_find ttl transform to integer always

* ipa_dnsrecord dnsrecord_find method refactor

---------


(cherry picked from commit 3194ed9d36)

Co-authored-by: Dor Breger <75537576+DorBreger@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-13 21:14:48 +01:00
patchback[bot]
79d8c9bd6e [PR #11424/f0e3edc8 backport][stable-12] New module: logrotate (#11581)
New module: `logrotate` (#11424)

* add module logrotate

* add values for start

* fix docs

* version 12.5.0 and fix test

---------


(cherry picked from commit f0e3edc892)

Co-authored-by: Aleksandr Gabidullin <101321307+a-gabidullin@users.noreply.github.com>
Co-authored-by: Александр Габидуллин <agabidullin@astralinux.ru>
2026-03-13 08:01:39 +01:00
patchback[bot]
e631648ef6 [PR #11576/ccc974e2 backport][stable-12] Consolidate changelog fragments (#11580)
Consolidate changelog fragments (#11576)

Consolidate changelog fragments.

(cherry picked from commit ccc974e2fa)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-13 07:58:25 +01:00
patchback[bot]
5106aa8065 [PR #11557/a69f7e60 backport][stable-12] add module keycloak_authentication_v2 (#11579)
add module keycloak_authentication_v2 (#11557)

* add module keycloak_authentication_v2

* skip sanity checks, because the run into a recursion

* 11556 fix documentation

* 11556 limit the depth of nested flows to 4

* 11556 code cleanup

* 11556 code cleanup - add type hints

* 11556 add keycloak_authentication_v2 to meta/runtime.yml

* 11556 code cleanup - remove custom type hints

* 11556 code cleanup - none checks

* Update plugins/modules/keycloak_authentication_v2.py



* Update plugins/modules/keycloak_authentication_v2.py



* 11556 code cleanup - remove document starts

* 11556 cleanup

* 11556 cleanup

---------




(cherry picked from commit a69f7e60b4)

Co-authored-by: thomasbargetz <thomas.bargetz@gmail.com>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Thomas Bargetz <thomas.bargetz@rise-world.com>
2026-03-13 07:41:56 +01:00
patchback[bot]
25e35bdda7 [PR #11481/55dae7c2 backport][stable-12] doas: allow to explicitly enable pipelining (#11577)
doas: allow to explicitly enable pipelining (#11481)

* Allow to explicitly enable pipelining.

* Add markup.

(cherry picked from commit 55dae7c2a6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-12 21:44:11 +01:00
patchback[bot]
74bc10b8fc [PR #11558/0e4783dc backport][stable-12] Binary attribute support for ldap_attrs and ldap_entry (#11578)
Binary attribute support for `ldap_attrs` and `ldap_entry` (#11558)

* Binary attribute support for `ldap_attrs` and `ldap_entry`

This commit implements binary attribute support for the `ldap_attrs` and
`ldap_entry` plugins. This used to be "supported" before, because it was
possible to simply load arbitrary binary data into the attributes, but
no longer functions on recent Ansible versions.

In order to support binary attributes, this commit introduces two new
options to both plugins:

  * `binary_attributes`, a list of attribute names which will be
    considered as being binary,
  * `honor_binary_option`, a flag which is true by default and will
    handle all attributes that include the binary option (see RFC 4522)
    as binary automatically.

When an attribute is determined to be binary through either of these
means, the plugin will assume that the attribute's value is in fact
base64-encoded. It will proceed to decode it and handle it accordingly.

While changes to `ldap_entry` are pretty straightforward, more work was
required on `ldap_attrs`.

  * First, because both `present` and `absent` state require checking
    the attribute's current values and normally do that using LDAP search
    queries for each value, a specific path for binary attributes was
    added that loads and caches all values for the attribute and compares
    the values in the Python code.
  * In addition, generating both the modlist and the diff output require
    re-encoding binary attributes' values into base64 so it can be
    transmitted back to Ansible.

* Various fixes on `ldap_attrs`/`ldap_entry` from PR 11558 discussion

* Rename `honor_binary_option` to `honor_binary`

* Add some general documentation about binary attributes

* Fix changelog fragment after renaming one of the new options

* Add examples of `honor_binary` and `binary_attributes`

* Add note that indicates that binary values are supported from 12.5.0+

* Fix punctuation

* Add links to RFC 4522 to `ldap_attrs` and `ldap_entry`

* Catch base64 decoding errors

* Rephrase changelog fragment

* Use f-string to format the encoding error message

(cherry picked from commit 0e4783dcc3)

Co-authored-by: Emmanuel Benoît <tseeker@nocternity.net>
2026-03-12 21:39:01 +01:00
patchback[bot]
7415220cad [PR #11573/f9e583da backport][stable-12] fix: remove HTTPStatus constructs introduced in Python 3.11 (#11575)
fix: remove HTTPStatus constructs introduced in Python 3.11 (#11573)

* fix: remove HTTPStatus constructs introduced in Python 3.11

* add changelog frag

(cherry picked from commit f9e583dae2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-12 20:59:26 +01:00
patchback[bot]
7f8bc6f99d [PR #11541/4cd91ba4 backport][stable-12] Fix templating bug in iptables_state tests (#11572)
Fix templating bug in iptables_state tests (#11541)

* Fix templating bug in iptables_state tests.

* Try to install older packages on RHEL.

(cherry picked from commit 4cd91ba4d4)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-11 22:15:52 +01:00
patchback[bot]
b5846a3d05 [PR #11567/9b72d954 backport][stable-12] Add missing __future__ imports (#11569)
Add missing __future__ imports (#11567)

Add missing __future__ imports.

(cherry picked from commit 9b72d95452)

Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-11 07:10:34 +01:00
patchback[bot]
25c475a7ef [PR #11561/7436c0c9 backport][stable-12] replace literal HTTP codes with http.HTTPStatus (#11568)
replace literal HTTP codes with `http.HTTPStatus` (#11561)

* replace literal HTTP codes with http.HTTPStatus

* add changelog frag

(cherry picked from commit 7436c0c9ba)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-10 22:14:27 +01:00
patchback[bot]
b3782a76e0 [PR #11551/1554f23b backport][stable-12] nmcli: fix idempotency issue with macvlan (#11566)
nmcli: fix idempotency issue with macvlan (#11551)

* nmcli: fix idempotency issue with macvlan

The nmcli module is not idempotent for macvlan interfaces.

Ansible running in diff mode for a case where the interface in question
already exists:

```
TASK [nm_macvlan : Check macvlan connection] *********************************************************************************
--- before
+++ after
@@ -11,5 +11,5 @@
     "ipv6.method": "disabled",
     "macvlan.mode": "2",
     "macvlan.parent": "eth0",
-    "macvlan.tap": "no"
+    "macvlan.tap": "False"
 }
```
The problem is that `macvlan.tap` isn't treated as boolean option. Fix it.

* Update changelogs/fragments/11551-fix-nmcli-idempotency-for-macvlan.yml



---------


(cherry picked from commit 1554f23bfb)

Co-authored-by: Martin Wilck <mwilck@suse.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-10 22:00:44 +01:00
patchback[bot]
fc5de1a194 [PR #11548/2f33ff10 backport][stable-12] keycloak_authentication: fix TypeError when flow has no authenticationExecutions (#11565)
keycloak_authentication: fix TypeError when flow has no authenticationExecutions (#11548)

* TIAAS-12174: fix(keycloak_authentication): handle None authenticationExecutions

When a flow is defined without authenticationExecutions, module.params.get()
returns None but the key still exists in the config dict. The 'in' check
passes but iterating over None raises TypeError.

Guard the iteration with an explicit None check.

* keycloak_authentication: add changelog fragment for NoneType fix

* keycloak_authentication: update changelog fragment with PR link

* Update plugins/modules/keycloak_authentication.py



* Changelog polishing

---------



(cherry picked from commit 2f33ff1041)

Co-authored-by: Ivan Kokalovic <67540157+koke1997@users.noreply.github.com>
Co-authored-by: Ivan Kokalovic <ivan.kokalovic@example.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2026-03-10 06:57:51 +01:00
patchback[bot]
80184b6fd4 [PR #11562/93112d23 backport][stable-12] monit: remove unstable tag from integration tests (#11563)
monit: remove unstable tag from integration tests (#11562)

(cherry picked from commit 93112d23e5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-10 06:57:40 +01:00
patchback[bot]
be7dc5f37d [PR #11555/71f8c15d backport][stable-12] Allow setting of independent custom domain for incus inventory (#11560)
Allow setting of independent custom domain for incus inventory (#11555)

Allowing the domain suffix to be appended independent of the `host_fqdn`
setting enables the inventory plugin to construct proper FQDNs if a
network has the `dns.domain` property set. Otherwise you would always
end up with something like `host01.project.local.example.net` despite
`host01.example.net` being the expected result.

(cherry picked from commit 71f8c15d2e)

Co-authored-by: Roland Sommer <rol@ndsommer.de>
2026-03-07 19:12:30 +01:00
patchback[bot]
fc7bcccc9d [PR #11552/aaef821f backport][stable-12] Update links to iocage. Current iocage documentation is at freebsd.gi… (#11554)
Update links to iocage. Current iocage documentation is at freebsd.gi… (#11552)

Update links to iocage. Current iocage documentation is at freebsd.github.io/iocage/

(cherry picked from commit aaef821f60)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2026-03-06 05:53:33 +00:00
patchback[bot]
5cb4632c15 [PR #11540/137f5444 backport][stable-12] aix_*: deprecation (#11550)
aix_*: deprecation (#11540)

* aix_*: deprecation

* add changelog frag

* update chglog

* adjustments from review

* typo

* wordsmithing from review

(cherry picked from commit 137f5444e3)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2026-03-04 21:59:38 +01:00
patchback[bot]
eae5987be1 [PR #11544/9b9d8eac backport][stable-12] Update tests to pass on macOS arm64 (#11545)
Update tests to pass on macOS arm64 (#11544)

(cherry picked from commit 9b9d8eac09)

Co-authored-by: Matt Clay <matt@mystile.com>
2026-02-27 19:29:47 +01:00
patchback[bot]
d45044790a [PR #11538/8929caec backport][stable-12] Fix description error in CONTRIBUTING.md (#11539)
Fix description error in CONTRIBUTING.md (#11538)

Fix text error in CONTRIBUTING.md.

Updated instructions for running format tests.

(cherry picked from commit 8929caece6)

Co-authored-by: IamLunchbox <56757745+IamLunchbox@users.noreply.github.com>
2026-02-25 06:53:14 +01:00
Felix Fontein
434f7ce55b The next expected release will be 12.5.0. 2026-02-23 18:38:55 +01:00
449 changed files with 14536 additions and 2739 deletions

View File

@@ -70,6 +70,19 @@ stages:
- test: 2
- test: 3
- test: 4
- stage: Sanity_2_21
displayName: Sanity 2.21
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
testFormat: 2.21/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- stage: Sanity_2_20
displayName: Sanity 2.20
dependsOn: []
@@ -96,19 +109,6 @@ stages:
- test: 2
- test: 3
- test: 4
- stage: Sanity_2_18
displayName: Sanity 2.18
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
testFormat: 2.18/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
### Units
- stage: Units_devel
displayName: Units devel
@@ -125,6 +125,19 @@ stages:
- test: '3.12'
- test: '3.13'
- test: '3.14'
- test: '3.15'
- stage: Units_2_21
displayName: Units 2.21
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.21/units/{0}/1
targets:
- test: 3.9
- test: "3.12"
- test: "3.14"
- stage: Units_2_20
displayName: Units 2.20
dependsOn: []
@@ -149,18 +162,6 @@ stages:
- test: 3.8
- test: "3.11"
- test: "3.13"
- stage: Units_2_18
displayName: Units 2.18
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.18/units/{0}/1
targets:
- test: 3.8
- test: "3.11"
- test: "3.13"
## Remote
- stage: Remote_devel_extra_vms
@@ -173,8 +174,8 @@ stages:
targets:
- name: Alpine 3.23
test: alpine/3.23
# - name: Fedora 43
# test: fedora/43
# - name: Fedora 44
# test: fedora/44
- name: Ubuntu 22.04
test: ubuntu/22.04
- name: Ubuntu 24.04
@@ -189,8 +190,8 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- name: macOS 15.3
test: macos/15.3
- name: macOS 26.3
test: macos/26.3
- name: RHEL 10.1
test: rhel/10.1
- name: RHEL 9.7
@@ -198,8 +199,27 @@ stages:
# TODO: enable this ASAP!
# - name: FreeBSD 15.0
# test: freebsd/15.0
- name: FreeBSD 14.3
test: freebsd/14.3
# TODO: enable this ASAP!
# - name: FreeBSD 14.4
# test: freebsd/14.4
groups:
- 1
- 2
- 3
- stage: Remote_2_21
displayName: Remote 2.21
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.21/{0}
targets:
# - name: macOS 26.3
# test: macos/26.3
- name: RHEL 10.1
test: rhel/10.1
# - name: RHEL 9.7
# test: rhel/9.7
groups:
- 1
- 2
@@ -212,6 +232,8 @@ stages:
parameters:
testFormat: 2.20/{0}
targets:
- name: macOS 15.3
test: macos/15.3
- name: RHEL 10.1
test: rhel/10.1
- name: FreeBSD 14.3
@@ -236,22 +258,6 @@ stages:
- 1
- 2
- 3
- stage: Remote_2_18
displayName: Remote 2.18
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.18/{0}
targets:
- name: macOS 14.3
test: macos/14.3
- name: FreeBSD 14.1
test: freebsd/14.1
groups:
- 1
- 2
- 3
### Docker
- stage: Docker_devel
@@ -262,8 +268,8 @@ stages:
parameters:
testFormat: devel/linux/{0}
targets:
- name: Fedora 43
test: fedora43
- name: Fedora 44
test: fedora44
- name: Alpine 3.23
test: alpine323
- name: Ubuntu 22.04
@@ -274,6 +280,26 @@ stages:
- 1
- 2
- 3
- stage: Docker_2_21
displayName: Docker 2.21
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.21/linux/{0}
targets:
- name: Fedora 43
test: fedora43
# - name: Alpine 3.23
# test: alpine323
# - name: Ubuntu 22.04
# test: ubuntu2204
- name: Ubuntu 24.04
test: ubuntu2404
groups:
- 1
- 2
- 3
- stage: Docker_2_20
displayName: Docker 2.20
dependsOn: []
@@ -306,24 +332,6 @@ stages:
- 1
- 2
- 3
- stage: Docker_2_18
displayName: Docker 2.18
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.18/linux/{0}
targets:
- name: Fedora 40
test: fedora40
- name: Alpine 3.20
test: alpine320
- name: Ubuntu 24.04
test: ubuntu2404
groups:
- 1
- 2
- 3
### Community Docker
- stage: Docker_community_devel
@@ -359,6 +367,18 @@ stages:
# testFormat: devel/generic/{0}/1
# targets:
# - test: '3.9'
# - test: '3.13'
# - test: '3.15'
# - stage: Generic_2_21
# displayName: Generic 2.21
# dependsOn: []
# jobs:
# - template: templates/matrix.yml
# parameters:
# nameFormat: Python {0}
# testFormat: 2.21/generic/{0}/1
# targets:
# - test: '3.9'
# - test: '3.12'
# - test: '3.14'
# - stage: Generic_2_20
@@ -382,44 +402,33 @@ stages:
# testFormat: 2.19/generic/{0}/1
# targets:
# - test: '3.9'
# - test: '3.13'
# - stage: Generic_2_18
# displayName: Generic 2.18
# dependsOn: []
# jobs:
# - template: templates/matrix.yml
# parameters:
# nameFormat: Python {0}
# testFormat: 2.18/generic/{0}/1
# targets:
# - test: '3.8'
# - test: '3.13'
- stage: Summary
condition: succeededOrFailed()
dependsOn:
- Sanity_devel
- Sanity_2_21
- Sanity_2_20
- Sanity_2_19
- Sanity_2_18
- Units_devel
- Units_2_21
- Units_2_20
- Units_2_19
- Units_2_18
- Remote_devel_extra_vms
- Remote_devel
- Remote_2_21
- Remote_2_20
- Remote_2_19
- Remote_2_18
- Docker_devel
- Docker_2_21
- Docker_2_20
- Docker_2_19
- Docker_2_18
- Docker_community_devel
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
# - Generic_devel
# - Generic_2_21
# - Generic_2_20
# - Generic_2_19
# - Generic_2_18
jobs:
- template: templates/coverage.yml

View File

@@ -23,7 +23,7 @@
"ms-python.vscode-pylance",
"redhat.ansible",
"redhat.vscode-yaml",
"trond-snekvik.simple-rst",
"trond-snekvik.simple-rst"
]
}
},

View File

@@ -3,6 +3,7 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -x
sudo chown -R vscode:vscode /workspace/
pip install -U pip

70
.github/BOTMETA.yml vendored
View File

@@ -312,7 +312,7 @@ files:
$lookups/lmdb_kv.py:
maintainers: jpmens
$lookups/merge_variables.py:
maintainers: rlenferink m-a-r-k-e alpex8
maintainers: rlenferink m-a-r-k-e alpex8 cfiehe
$lookups/onepass:
labels: onepassword
maintainers: samdoran
@@ -379,8 +379,13 @@ files:
$module_utils/jenkins.py:
labels: jenkins
maintainers: russoz
$module_utils/_crypt.py:
maintainers: russoz
$module_utils/_lxc.py:
maintainers: russoz
$module_utils/_lvm.py:
labels: lvm
maintainers: russoz
$module_utils/manageiq.py:
labels: manageiq
maintainers: $team_manageiq
@@ -642,6 +647,10 @@ files:
maintainers: adrianmoisey
$modules/github_repo.py:
maintainers: atorrescogollo
$modules/github_secrets.py:
maintainers: konstruktoid
$modules/github_secrets_info.py:
maintainers: konstruktoid
$modules/gitlab_:
keywords: gitlab source_control
maintainers: $team_gitlab
@@ -657,10 +666,10 @@ files:
maintainers: zvaraondrej
$modules/gitlab_milestone.py:
maintainers: gpongelli
$modules/gitlab_project_variable.py:
maintainers: markuman
$modules/gitlab_instance_variable.py:
maintainers: benibr
$modules/gitlab_project_variable.py:
maintainers: markuman
$modules/gitlab_runner.py:
maintainers: SamyCoenen
$modules/gitlab_user.py:
@@ -769,14 +778,14 @@ files:
maintainers: abakanovskii
$modules/ipa_dnsrecord.py:
maintainers: $team_ipa jwbernin
$modules/ipbase_info.py:
maintainers: dominikkukacka
$modules/ipa_pwpolicy.py:
maintainers: adralioh
$modules/ipa_service.py:
maintainers: cprh
$modules/ipa_vault.py:
maintainers: jparrill
$modules/ipbase_info.py:
maintainers: dominikkukacka
$modules/ipify_facts.py:
maintainers: resmo
$modules/ipinfoio_facts.py:
@@ -836,16 +845,22 @@ files:
maintainers: elfelip Gaetan2907
$modules/keycloak_authentication_required_actions.py:
maintainers: Skrekulko
$modules/keycloak_authentication_v2.py:
maintainers: thomasbargetz
$modules/keycloak_authz_authorization_scope.py:
maintainers: mattock
$modules/keycloak_authz_permission.py:
maintainers: mattock
$modules/keycloak_authz_custom_policy.py:
maintainers: mattock
$modules/keycloak_authz_permission.py:
maintainers: mattock
$modules/keycloak_authz_permission_info.py:
maintainers: mattock
$modules/keycloak_client.py:
maintainers: koke1997
$modules/keycloak_client_rolemapping.py:
maintainers: Gaetan2907
$modules/keycloak_client_rolescope.py:
maintainers: desand01
$modules/keycloak_clientscope.py:
maintainers: Gaetan2907
$modules/keycloak_clientscope_type.py:
@@ -856,6 +871,8 @@ files:
maintainers: fynncfchen johncant
$modules/keycloak_component.py:
maintainers: fivetide
$modules/keycloak_component_info.py:
maintainers: desand01
$modules/keycloak_group.py:
maintainers: adamgoossens
$modules/keycloak_identity_provider.py:
@@ -865,27 +882,23 @@ files:
$modules/keycloak_realm_info.py:
maintainers: fynncfchen
$modules/keycloak_realm_key.py:
maintainers: mattock
maintainers: mattock koke1997
$modules/keycloak_realm_localization.py:
maintainers: danekja
$modules/keycloak_realm_rolemapping.py:
maintainers: agross mhuysamen Gaetan2907
$modules/keycloak_role.py:
maintainers: laurpaum
$modules/keycloak_user.py:
maintainers: elfelip
$modules/keycloak_user_federation.py:
maintainers: laurpaum
$modules/keycloak_userprofile.py:
maintainers: yeoldegrove
$modules/keycloak_component_info.py:
maintainers: desand01
$modules/keycloak_client_rolescope.py:
maintainers: desand01
$modules/keycloak_user_rolemapping.py:
maintainers: bratwurzt
$modules/keycloak_realm_rolemapping.py:
maintainers: agross mhuysamen Gaetan2907
$modules/keycloak_user_execute_actions_email.py:
maintainers: mariusbertram
$modules/keycloak_user_federation.py:
maintainers: laurpaum
$modules/keycloak_user_rolemapping.py:
maintainers: bratwurzt koke1997
$modules/keycloak_userprofile.py:
maintainers: yeoldegrove
$modules/keyring.py:
maintainers: ahussey-redhat
$modules/keyring_info.py:
@@ -928,6 +941,8 @@ files:
labels: logentries
$modules/logentries_msg.py:
maintainers: jcftang
$modules/logrotate.py:
maintainers: a-gabidullin
$modules/logstash_plugin.py:
maintainers: nerzhul
$modules/lvg.py:
@@ -1330,8 +1345,11 @@ files:
$modules/snap_alias.py:
labels: snap
maintainers: russoz
$modules/snap_connect.py:
labels: snap
maintainers: russoz
$modules/snmp_facts.py:
maintainers: ogenstad ujwalkomarla
maintainers: ogenstad ujwalkomarla lalten
$modules/solaris_zone.py:
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
labels: solaris
@@ -1506,11 +1524,11 @@ files:
ignore: matze
labels: zypper
maintainers: $team_suse
$plugin_utils/ansible_type.py:
maintainers: vbotka
$modules/zypper_repository_info.py:
labels: zypper
maintainers: $team_suse TobiasZeuch181
$plugin_utils/ansible_type.py:
maintainers: vbotka
$plugin_utils/keys_filter.py:
maintainers: vbotka
$plugin_utils/unsafe.py:
@@ -1562,6 +1580,8 @@ files:
maintainers: russoz
docs/docsite/rst/guide_deps.rst:
maintainers: russoz
docs/docsite/rst/guide_ee.rst:
maintainers: russoz
docs/docsite/rst/guide_iocage.rst:
maintainers: russoz felixfontein
docs/docsite/rst/guide_iocage_inventory.rst:
@@ -1619,7 +1639,7 @@ macros:
plugin_utils: plugins/plugin_utils
tests: plugins/test
team_ansible_core:
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister molekuul ramooncamacho wtcross
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
team_consul: sgargan apollo13 Ilgmi
team_cyberark_conjur: jvanderhoof ryanprior
@@ -1640,7 +1660,7 @@ macros:
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
team_rhsm: cnsnyder ptoscano
team_scaleway: remyleone abarbare
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
team_solaris: bcoca fishman jasperla jpdasma scathatheworm troy2914 xen0l
team_suse: commel evrardjp lrupp AnderEnder alxgu andytom sealor
team_virt: joshainglis karmab Thulium-Drake Ajpantuso
team_wdc: mikemoerk

View File

@@ -30,6 +30,7 @@ jobs:
matrix:
ansible:
- '2.17'
- '2.18'
runs-on: ubuntu-latest
steps:
- name: Perform sanity testing
@@ -63,6 +64,12 @@ jobs:
python: '3.10'
- ansible: '2.17'
python: '3.12'
- ansible: '2.18'
python: '3.8'
- ansible: '2.18'
python: '3.11'
- ansible: '2.18'
python: '3.13'
steps:
- name: >-
@@ -144,6 +151,52 @@ jobs:
# docker: default
# python: '3.12'
# target: azp/generic/1/
# 2.18
- ansible: '2.18'
docker: fedora40
python: ''
target: azp/posix/1/
- ansible: '2.18'
docker: fedora40
python: ''
target: azp/posix/2/
- ansible: '2.18'
docker: fedora40
python: ''
target: azp/posix/3/
- ansible: '2.18'
docker: ubuntu2404
python: ''
target: azp/posix/1/
- ansible: '2.18'
docker: ubuntu2404
python: ''
target: azp/posix/2/
- ansible: '2.18'
docker: ubuntu2404
python: ''
target: azp/posix/3/
- ansible: '2.18'
docker: alpine320
python: ''
target: azp/posix/1/
- ansible: '2.18'
docker: alpine320
python: ''
target: azp/posix/2/
- ansible: '2.18'
docker: alpine320
python: ''
target: azp/posix/3/
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
# - ansible: '2.18'
# docker: default
# python: '3.8'
# target: azp/generic/1/
# - ansible: '2.18'
# docker: default
# python: '3.13'
# target: azp/generic/1/
steps:
- name: >-

View File

@@ -5,7 +5,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.10
rev: v0.15.9
hooks:
# Run the linter.
- id: ruff-check

File diff suppressed because one or more lines are too long

View File

@@ -6,6 +6,263 @@ Community General Release Notes
This changelog describes changes after version 11.0.0.
v12.6.0
=======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
- cobbler_sync - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- cobbler_system - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- composer - add ``force`` parameter; when ``command=create-project``, the module now checks whether a ``composer.json`` already exists in ``working_dir`` and skips the command if so, making the task idempotent. Set ``force=true`` to always run the command regardless (https://github.com/ansible-collections/community.general/issues/725, https://github.com/ansible-collections/community.general/pull/11689).
- consul_kv - add ``ca_path`` option to specify a CA bundle for HTTPS connections (https://github.com/ansible-collections/community.general/pull/11817).
- consul_kv lookup plugin - add ``ca_path`` option to specify a CA bundle for HTTPS connections (https://github.com/ansible-collections/community.general/issues/2876, https://github.com/ansible-collections/community.general/pull/11817).
- dconf - add support for C(dbus-broker) (https://github.com/ansible-collections/community.general/issues/495, https://github.com/ansible-collections/community.general/pull/11772).
- filesystem - migrate ``LVM.get_fs_size()`` to use ``CmdRunner``, ensuring locale-independent output parsing (https://github.com/ansible-collections/community.general/pull/11888).
- flatpak - add new parameter ``from_url`` to install a flatpak from a ``.flatpakref`` URL (https://github.com/ansible-collections/community.general/issues/4000, https://github.com/ansible-collections/community.general/pull/11748).
- gem - refactor module to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11733).
- homebrew_services - remove various redundancies including dead state validation, unused return values, and unnecessary locale environment variables (https://github.com/ansible-collections/community.general/pull/11839).
- homebrew_tap - avoid redundant ``brew tap`` calls when processing multiple taps by fetching the tap list once upfront (https://github.com/ansible-collections/community.general/pull/11848).
- ipa_dnsrecord - add ``exclusive`` parameter to allow appending values to existing records without replacing them (https://github.com/ansible-collections/community.general/issues/682, https://github.com/ansible-collections/community.general/pull/11694).
- java_cert - support proxy authentication when ``https_proxy`` environment variable includes credentials (https://github.com/ansible-collections/community.general/issues/4126, https://github.com/ansible-collections/community.general/pull/11753).
- jira - add ``cloud`` option to support Jira Cloud's new search endpoint ``/rest/api/2/search/jql``, since the legacy ``/rest/api/2/search`` endpoint has been removed on Jira Cloud (https://github.com/ansible-collections/community.general/issues/10786, https://github.com/ansible-collections/community.general/pull/11701).
- jira - when ``cloud=true``, user-type fields (``assignee``, ``reporter``, and any listed in the new ``custom_user_fields`` parameter) containing an email address are automatically resolved to Jira Cloud account IDs (https://github.com/ansible-collections/community.general/issues/11734, https://github.com/ansible-collections/community.general/pull/11735).
- logrotate - adds optional ``backup`` parameter to create a backup of the existing configuration file before writing changes (https://github.com/ansible-collections/community.general/pull/11764).
- lvg - migrate to ``CmdRunner``, removing direct ``run_command`` calls and ``run_command_environ_update`` (https://github.com/ansible-collections/community.general/pull/11835).
- lvm_pv - migrate to ``CmdRunner`` using shared runners from ``module_utils/_lvm`` (https://github.com/ansible-collections/community.general/pull/11811).
- lvol - migrate to ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11887).
- manageiq module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- manageiq_alert_profiles - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- manageiq_alerts - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- oneview module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- oneview_san_manager - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- opendj_backendprop - refactor to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11728).
- packet_device - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- packet_ip_subnet - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- pacman - add ``root``, ``cachedir``, and ``config`` options to support installing packages into an alternative root directory (https://github.com/ansible-collections/community.general/issues/438, https://github.com/ansible-collections/community.general/pull/11681).
- parted - add ``unit_preserve_case`` option to control the case of the ``unit`` field in the return value, fixing the round-trip use case where the returned unit is fed back as input (https://github.com/ansible-collections/community.general/issues/1860, https://github.com/ansible-collections/community.general/pull/11813).
- pubnub_blocks - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- terraform - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- xenserver_guest - use ``enumerate()`` instead of manual index variable in ``for`` loop (https://github.com/ansible-collections/community.general/pull/11721).
Bugfixes
--------
- alternatives - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- apache2_module - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- apk - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- apt_repo - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
- apt_rpm - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- awall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
- beadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
- bower - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
- btrfs module_utils - set ``LANGUAGE`` and ``LC_ALL`` environment variables to ``C`` in all ``run_command()`` calls (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11787).
- bundler - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
- bzr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
- capabilities - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
- cargo - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- composer - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- cronvar - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
- dconf - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
- dnf_versionlock - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
- dpkg_divert - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
- easy_install - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
- etcd3 lookup plugin - improve HTTPS endpoint handling by stripping URL schemes from the ``host`` option and warning when ``ca_cert`` is not provided for HTTPS endpoints (https://github.com/ansible-collections/community.general/issues/1664, https://github.com/ansible-collections/community.general/pull/11861).
- facter_facts - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- filesystem - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- flatpak - fix removal of runtimes, which was broken because the module was filtering the installed flatpak list to apps only, so runtimes could never be matched for uninstallation (https://github.com/ansible-collections/community.general/issues/553, https://github.com/ansible-collections/community.general/pull/11688).
- flatpak - support new output message when an update resulted in no action that appears on Fedora 44 (https://github.com/ansible-collections/community.general/pull/11836).
- flatpak_remote - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
- git_config - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- git_config_info - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
- gitlab_project_members - fail with a clear error when multiple projects match the given name, instead of silently operating on the first result (https://github.com/ansible-collections/community.general/issues/2767, https://github.com/ansible-collections/community.general/pull/11851).
- gitlab_project_variable - use ``find_project()`` from module utils for project lookup, consistent with all other GitLab modules in the collection (https://github.com/ansible-collections/community.general/issues/3157, https://github.com/ansible-collections/community.general/pull/11878).
- hg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
- homebrew - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- homebrew_cask - fix ``sudo_password`` failing when the password contains single quotes or other special shell characters (https://github.com/ansible-collections/community.general/issues/4957, https://github.com/ansible-collections/community.general/pull/11850).
- homebrew_cask - fix failure when ``brew --version`` returns a placeholder version string (https://github.com/ansible-collections/community.general/issues/4708, https://github.com/ansible-collections/community.general/pull/11849).
- homebrew_cask - fix false task failure when upgrading casks with ``version=latest``; the post-upgrade check incorrectly re-ran ``brew outdated`` (which always lists ``latest`` casks as outdated under ``--greedy``), now uses the command exit code instead (https://github.com/ansible-collections/community.general/issues/1647, https://github.com/ansible-collections/community.general/pull/11838).
- homebrew_cask - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- homebrew_tap - fix ``None`` being passed as a command argument when adding a tap without a URL (https://github.com/ansible-collections/community.general/pull/11848).
- homectl - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/pull/11860).
- homectl - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
- icinga2_feature - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- imgadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- incus connection plugin - work when the active become plugin sets ``require_tty`` instead of failing silently (https://github.com/ansible-collections/community.general/pull/11771).
- ip_netns - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
- ipa module utils - fix failure to detect errors reported in the ``failed`` field of the IPA API response, which is returned with HTTP 200 on partial or full failures in member add/remove operations (https://github.com/ansible-collections/community.general/issues/1239, https://github.com/ansible-collections/community.general/pull/11698).
- ipa_dnsrecord - fix errors when module is used with existing record with default TTL (https://github.com/ansible-collections/community.general/pull/11717).
- ipa_host - fix logic to disable existing hosts (https://github.com/ansible-collections/community.general/issues/11483, https://github.com/ansible-collections/community.general/pull/11487).
- iptables_state - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- iso_extract - retry ``umount`` up to 5 times preventing ``OSError`` on cleanup (https://github.com/ansible-collections/community.general/issues/5333, https://github.com/ansible-collections/community.general/pull/11837).
- iso_extract - strip leading path separator from file entries so files with a leading ``/`` are extracted correctly (https://github.com/ansible-collections/community.general/issues/5283, https://github.com/ansible-collections/community.general/pull/11825).
- java_cert - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
- java_keystore - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- keyring - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
- keyring_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
- kibana_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
- known_hosts module utils - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- launchd - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
- lbu - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- listen_ports_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
- lldp - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
- locale_gen - add missing locale entries to ``/etc/locale.gen`` when not already present (https://github.com/ansible-collections/community.general/issues/2399, https://github.com/ansible-collections/community.general/pull/11824).
- logrotate - adds missing default values for ``state`` and ``config_dir`` parameters, and adds ``required_by`` declarations for shred and compression parameters (https://github.com/ansible-collections/community.general/pull/11764).
- logrotate - fixes ``TypeError`` when ``shred_cycles`` is ``None`` and corrects ``enabled=None`` handling in ``get_config_path()`` (https://github.com/ansible-collections/community.general/pull/11764).
- logrotate - writes configuration files to a temporary file first and validates before atomically moving to the destination, and properly wraps all ``os.remove()`` and ``atomic_move()`` calls in error handling (https://github.com/ansible-collections/community.general/pull/11764).
- logstash_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
- lvg - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
- lvol - fix LVM version parsing (https://github.com/ansible-collections/community.general/issues/5445, https://github.com/ansible-collections/community.general/pull/11823).
- lvol - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- lxc_container - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
- machinectl become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
- macports - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- mas - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
- modprobe - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- monit - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- mssql_db - fail with a clear error message when a named instance (``server\instance`` format) is used together with ``login_port``, since these are mutually exclusive connection methods (https://github.com/ansible-collections/community.general/issues/5693, https://github.com/ansible-collections/community.general/pull/11664).
- mssql_script - fail with a clear error message when a named instance (``server\instance`` format) is used together with ``login_port``, since these are mutually exclusive connection methods (https://github.com/ansible-collections/community.general/issues/5693, https://github.com/ansible-collections/community.general/pull/11664).
- mssql_script - only passes ``params`` to ``cursor.execute()`` when the user actually provides them (https://github.com/ansible-collections/community.general/issues/11699, https://github.com/ansible-collections/community.general/pull/11754).
- nmcli - use ``get_best_parsable_locale()`` to set locale environment for ``run_command()`` calls, fixing UTF-8 connection names being corrupted to ``????`` under ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/10384, https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11742).
- nsupdate - fix GSS-TSIG support (accidentally broken by https://github.com/ansible-collections/community.general/pull/11461, https://github.com/ansible-collections/community.general/pull/11712)
- ohai - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
- onepassword_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
- open_iscsi - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- openbsd_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11767).
- openwrt_init - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
- osx_defaults - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
- pacemaker_resource, pacemaker_stonith - fix resource and stonith creation race condition by polling PCS status (https://github.com/ansible-collections/community.general/issues/11574, https://github.com/ansible-collections/community.general/pull/11750).
- pacman - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- pacman_key - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- parted - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
- pear - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
- pip_package_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
- pkg5 - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
- pkg5_publisher - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
- pkgin - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- pkgng - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
- pkgutil - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
- pnpm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
- portage - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- portinstall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- redhat_subscription - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- rhsm_release - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- rhsm_repository - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- riak - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
- rpm_ostree_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- run0 become plugin - mark the plugin as incompatible with connection pipelining (see https://github.com/ansible/ansible/issues/81254, https://github.com/ansible-collections/community.general/pull/11771).
- run0 become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
- runit - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- sefcontext - flush the in-process ``matchpathcon`` cache after applying changes, so subsequent tasks running in the same process (for example via the Mitogen connection plugin) see the updated SELinux file context rules instead of stale cached data (https://github.com/ansible-collections/community.general/issues/888, https://github.com/ansible-collections/community.general/pull/11812).
- smartos_image_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- snmp_facts - the module now also supports pysnmp >= 7.1 (https://github.com/ansible-collections/community.general/issues/8852, https://github.com/ansible-collections/community.general/pull/11683).
- sorcery - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11767).
- supervisorctl - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- svc - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- swdepot - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
- syspatch - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- sysrc - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
- sysupgrade - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
- terraform - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
- timezone - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
- udm_user - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4690, https://github.com/ansible-collections/community.general/pull/11860).
- udm_user - fix alias-to-canonical parameter name mismatch that caused all camelCase-aliased parameters such as ``display_name`` and ``primary_group`` to be silently ignored (https://github.com/ansible-collections/community.general/issues/2950, https://github.com/ansible-collections/community.general/issues/3691, https://github.com/ansible-collections/community.general/pull/11859).
- ufw - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- xattr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
- xbps - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
- xenserver_guest - fix an issue where booting from ISO is not possible because CD-ROM device is placed in position above number 3. Position number 3 is now reserved for CD-ROM device and cannot be occupied by a disk (https://github.com/ansible-collections/community.general/issues/11624, https://github.com/ansible-collections/community.general/pull/11702).
- yarn - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
- yum_versionlock - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11777).
- zfs - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
- zfs_delegate_admin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
- zfs_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
- zpool_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
- zypper - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
- zypper_repository - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11777).
- zypper_repository_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
New Modules
-----------
- community.general.snap_connect - Manages snap interface connections.
v12.5.0
=======
Release Summary
---------------
Bugfix and feature release.
Minor Changes
-------------
- ansible_galaxy_install - add parameter ``executable`` (https://github.com/ansible-collections/community.general/issues/7261, https://github.com/ansible-collections/community.general/pull/11646).
- api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- bitbucket module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- consul module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- doas become plugin - add new option ``allow_pipelining`` to explicitly allow the use of pipelining with this plugin. This should only be set to ``true`` with ansible-core 2.19+ when ``doas`` does not require a password (https://github.com/ansible-collections/community.general/issues/11411, https://github.com/ansible-collections/community.general/pull/11481).
- gandi_livedns_api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- github_app_access_token lookup plugin - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- hwc_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- icinga2 inventory plugin - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- incus inventory plugin - add support for constructing project-independent FQDNs (https://github.com/ansible-collections/community.general/pull/11555).
- ipa module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- keycloak module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- keycloak_realm - add ``first_broker_login_flow`` parameter (https://github.com/ansible-collections/community.general/pull/11622).
- ldap_attrs - add ``binary_attributes`` and ``honor_binary`` parameters to handle binary attribute values (https://github.com/ansible-collections/community.general/pull/11558).
- ldap_entry - add ``binary_attributes`` and ``honor_binary`` parameters to handle creating objects with attributes set to binary values (https://github.com/ansible-collections/community.general/pull/11558).
- lookup plugin passwordstore - modernize internal ``check_output2()`` helper using ``subprocess.run()`` and rename it to ``run_backend_cmd()`` (https://github.com/ansible-collections/community.general/pull/11655).
- memset module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- merge_variables lookup plugin - extended merging capabilities added (https://github.com/ansible-collections/community.general/pull/11536).
- nmcli - fix idempotency for MAC VLAN interfaces when using ``macvlan.tap`` (https://github.com/ansible-collections/community.general/pull/11551).
- nsupdate - replace ``list(map(...))`` constructs with Python comprehensions (https://github.com/ansible-collections/community.general/pull/11590).
- ocapi_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- oci_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- online module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- osx_defaults - add support for ``dict`` type values, including ``dict_mode`` option to merge keys into an existing dictionary (https://github.com/ansible-collections/community.general/issues/238, https://github.com/ansible-collections/community.general/pull/11659).
- redfish_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- rundeck module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- scaleway module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- supervisorctl - added an additional condition for generating the error 'no such process' (https://github.com/ansible-collections/community.general/issues/11621, https://github.com/ansible-collections/community.general/pull/11632).
- timezone - replace ``list(map(...))`` constructs with Python comprehensions (https://github.com/ansible-collections/community.general/pull/11590).
- utm_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
Deprecated Features
-------------------
- aix_devices - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
- aix_filesystem - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
- aix_inittab - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
- aix_lvg - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
- aix_lvol - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
- monit - support for Monit version 5.18 or older is deprecated and will be removed in community.general 14.0.0 (https://github.com/ansible-collections/community.general/pull/11254).
- puppet - the ``timeout`` parameter is deprecated and will be removed in community.general 14.0.0. (https://github.com/ansible-collections/community.general/pull/11658).
Bugfixes
--------
- counter_enabled callback plugin - fix plugin not observing ``display_ok_hosts`` option (https://github.com/ansible-collections/community.general/issues/3978, https://github.com/ansible-collections/community.general/pull/11656).
- ipa_dnsrecord - fix idempotency bug when using ``dnsttl`` due to wrong Python types (https://github.com/ansible-collections/community.general/pull/11559).
- keycloak_authentication - fix ``TypeError`` crash when a flow is defined without ``authenticationExecutions`` (https://github.com/ansible-collections/community.general/issues/11547, https://github.com/ansible-collections/community.general/pull/11548).
- nictagadm - add a condition to the if statement so that ``is_valid_mac()`` does not get called if ``etherstub`` is false (https://github.com/ansible-collections/community.general/pull/11589).
- nmcli - add missing ``ipv6.routing-rules`` to ``settings_type()`` list type, preventing ``routing_rules6`` list from being corrupted (https://github.com/ansible-collections/community.general/issues/11630, https://github.com/ansible-collections/community.general/pull/11635).
- open_iscsi - fix IPv6 portal address formatting; iscsiadm requires bracket notation for IPv6 addresses but the module was producing an incorrect format (https://github.com/ansible-collections/community.general/issues/4467, https://github.com/ansible-collections/community.general/pull/11657).
- xfconf - representation of boolean properties was not consistent between Python and ``xfconf-query``, leading to broken idempotency (https://github.com/ansible-collections/community.general/pull/11645).
New Modules
-----------
- community.general.github_secrets - Manage GitHub repository or organization secrets.
- community.general.github_secrets_info - List GitHub repository or organization secrets.
- community.general.keycloak_authentication_v2 - Configure authentication flows in Keycloak in an idempotent and safe manner.
- community.general.logrotate - Manage logrotate configurations.
v12.4.0
=======

View File

@@ -56,7 +56,7 @@ The easiest way to format the code, and to run sanity and unit tests locally is
### Format code
The following commands show how to run ansible-test sanity tests:
The following commands show how to run ruff format:
```.bash
# Run all configured formatters:

View File

@@ -39,7 +39,7 @@ For more information about communication, see the [Ansible communication guide](
## Tested with Ansible
Tested with the current ansible-core 2.17, ansible-core 2.18, ansible-core 2.19, ansible-core 2.20 releases and the current development version of ansible-core. Ansible-core versions before 2.17.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
Tested with the current ansible-core 2.17, ansible-core 2.18, ansible-core 2.19, ansible-core 2.20, ansible-core 2.21 releases and the current development version of ansible-core. Ansible-core versions before 2.17.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
## External requirements

View File

@@ -1886,3 +1886,682 @@ releases:
name: loganalytics_ingestion
namespace: null
release_date: '2026-02-23'
12.5.0:
changes:
bugfixes:
- counter_enabled callback plugin - fix plugin not observing ``display_ok_hosts``
option (https://github.com/ansible-collections/community.general/issues/3978,
https://github.com/ansible-collections/community.general/pull/11656).
- ipa_dnsrecord - fix idempotency bug when using ``dnsttl`` due to wrong Python
types (https://github.com/ansible-collections/community.general/pull/11559).
- keycloak_authentication - fix ``TypeError`` crash when a flow is defined
without ``authenticationExecutions`` (https://github.com/ansible-collections/community.general/issues/11547,
https://github.com/ansible-collections/community.general/pull/11548).
- nictagadm - add a condition to the if statement so that ``is_valid_mac()``
does not get called if ``etherstub`` is false (https://github.com/ansible-collections/community.general/pull/11589).
- nmcli - add missing ``ipv6.routing-rules`` to ``settings_type()`` list type,
preventing ``routing_rules6`` list from being corrupted (https://github.com/ansible-collections/community.general/issues/11630,
https://github.com/ansible-collections/community.general/pull/11635).
- open_iscsi - fix IPv6 portal address formatting; iscsiadm requires bracket
notation for IPv6 addresses but the module was producing an incorrect format
(https://github.com/ansible-collections/community.general/issues/4467, https://github.com/ansible-collections/community.general/pull/11657).
- xfconf - representation of boolean properties was not consistent between
Python and ``xfconf-query``, leading to broken idempotency (https://github.com/ansible-collections/community.general/pull/11645).
deprecated_features:
- aix_devices - module is superseded by equivalent in ``ibm.power_aix`` collection.
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
https://github.com/ansible-collections/community.general/pull/11540).
- aix_filesystem - module is superseded by equivalent in ``ibm.power_aix``
collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
https://github.com/ansible-collections/community.general/pull/11540).
- aix_inittab - module is superseded by equivalent in ``ibm.power_aix`` collection.
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
https://github.com/ansible-collections/community.general/pull/11540).
- aix_lvg - module is superseded by equivalent in ``ibm.power_aix`` collection.
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
https://github.com/ansible-collections/community.general/pull/11540).
- aix_lvol - module is superseded by equivalent in ``ibm.power_aix`` collection.
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
https://github.com/ansible-collections/community.general/pull/11540).
- monit - support for Monit version 5.18 or older is deprecated and will be
removed in community.general 14.0.0 (https://github.com/ansible-collections/community.general/pull/11254).
- puppet - the ``timeout`` parameter is deprecated and will be removed in
community.general 14.0.0. (https://github.com/ansible-collections/community.general/pull/11658).
minor_changes:
- ansible_galaxy_install - add parameter ``executable`` (https://github.com/ansible-collections/community.general/issues/7261,
https://github.com/ansible-collections/community.general/pull/11646).
- api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- bitbucket module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- consul module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- doas become plugin - add new option ``allow_pipelining`` to explicitly allow
the use of pipelining with this plugin. This should only be set to ``true``
with ansible-core 2.19+ when ``doas`` does not require a password (https://github.com/ansible-collections/community.general/issues/11411,
https://github.com/ansible-collections/community.general/pull/11481).
- gandi_livedns_api module utils - use Python-defined constants for HTTP return
codes (https://github.com/ansible-collections/community.general/pull/11561).
- github_app_access_token lookup plugin - use Python-defined constants for
HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- hwc_utils module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- icinga2 inventory plugin - use Python-defined constants for HTTP return
codes (https://github.com/ansible-collections/community.general/pull/11561,
https://github.com/ansible-collections/community.general/pull/11573).
- incus inventory plugin - add support for constructing project-independent
FQDNs (https://github.com/ansible-collections/community.general/pull/11555).
- ipa module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
- keycloak module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- keycloak_realm - add ``first_broker_login_flow`` parameter (https://github.com/ansible-collections/community.general/pull/11622).
- ldap_attrs - add ``binary_attributes`` and ``honor_binary`` parameters to
handle binary attribute values (https://github.com/ansible-collections/community.general/pull/11558).
- ldap_entry - add ``binary_attributes`` and ``honor_binary`` parameters to
handle creating objects with attributes set to binary values (https://github.com/ansible-collections/community.general/pull/11558).
- lookup plugin passwordstore - modernize internal ``check_output2()`` helper
using ``subprocess.run()`` and rename it to ``run_backend_cmd()`` (https://github.com/ansible-collections/community.general/pull/11655).
- memset module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- merge_variables lookup plugin - extended merging capabilities added (https://github.com/ansible-collections/community.general/pull/11536).
- nmcli - fix idempotency for MAC VLAN interfaces when using ``macvlan.tap``
(https://github.com/ansible-collections/community.general/pull/11551).
- nsupdate - replace ``list(map(...))`` constructs with Python comprehensions
(https://github.com/ansible-collections/community.general/pull/11590).
- ocapi_utils module utils - use Python-defined constants for HTTP return
codes (https://github.com/ansible-collections/community.general/pull/11561).
- oci_utils module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- online module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- osx_defaults - add support for ``dict`` type values, including ``dict_mode``
option to merge keys into an existing dictionary (https://github.com/ansible-collections/community.general/issues/238,
https://github.com/ansible-collections/community.general/pull/11659).
- redfish_utils module utils - use Python-defined constants for HTTP return
codes (https://github.com/ansible-collections/community.general/pull/11561,
https://github.com/ansible-collections/community.general/pull/11573).
- rundeck module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
- scaleway module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561).
- supervisorctl - added an additional condition for generating the error 'no
such process' (https://github.com/ansible-collections/community.general/issues/11621,
https://github.com/ansible-collections/community.general/pull/11632).
- timezone - replace ``list(map(...))`` constructs with Python comprehensions
(https://github.com/ansible-collections/community.general/pull/11590).
- utm_utils module utils - use Python-defined constants for HTTP return codes
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
release_summary: Bugfix and feature release.
fragments:
- 11254-monit-deprecate-old.yml
- 11481-doas-pipelining.yml
- 11536-merge-variables-extended-merging-capabilities.yml
- 11540-deprecate-aix.yml
- 11551-fix-nmcli-idempotency-for-macvlan.yml
- 11555-incus-domain-name.yml
- 11558-binary-ldap-attributes.yml
- 11559-fix-ipa_dnsrecord-fail-when-no-change.yaml
- 11561-use-httpstatus-1.yml
- 11584-keycloak-first-roker-login-parameter.yml
- 11590-list-map.yml
- 11621-skip-no_such_process-for-name-all.yml
- 11630-nmcli-ipv6-routing-rules.yml
- 11645-xfconf-bool.yml
- 11646-galaxy-executable.yml
- 11655-passwordstore-cleanup.yml
- 11656-counter_enabled-display_ok_hosts.yml
- 11657-open-iscsi-ipv6.yml
- 11658-puppet-timeout-deprecation.yml
- 11659-osx-defaults-dict.yml
- 12.5.0.yml
- keycloak-authentication-none-executions.yml
- nictagadm-etherstub-nonetype-bugfix.yml
modules:
- description: Manage GitHub repository or organization secrets.
name: github_secrets
namespace: ''
- description: List GitHub repository or organization secrets.
name: github_secrets_info
namespace: ''
- description: Configure authentication flows in Keycloak in an idempotent and
safe manner.
name: keycloak_authentication_v2
namespace: ''
- description: Manage logrotate configurations.
name: logrotate
namespace: ''
release_date: '2026-03-23'
12.6.0:
changes:
bugfixes:
- alternatives - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- apache2_module - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- apk - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- apt_repo - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11782).
- apt_rpm - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- awall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11784).
- beadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11780).
- bower - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11783).
- btrfs module_utils - set ``LANGUAGE`` and ``LC_ALL`` environment variables
to ``C`` in all ``run_command()`` calls (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11787).
- bundler - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11783).
- bzr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11785).
- capabilities - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11779).
- cargo - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- composer - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- cronvar - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11773).
- dconf - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11765).
- dnf_versionlock - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11773).
- dpkg_divert - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11773).
- easy_install - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11782).
- etcd3 lookup plugin - improve HTTPS endpoint handling by stripping URL schemes
from the ``host`` option and warning when ``ca_cert`` is not provided for
HTTPS endpoints (https://github.com/ansible-collections/community.general/issues/1664,
https://github.com/ansible-collections/community.general/pull/11861).
- facter_facts - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- filesystem - normalize locale environment for ``run_command()`` calls to
``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- flatpak - fix removal of runtimes, which was broken because the module was
filtering the installed flatpak list to apps only, so runtimes could never
be matched for uninstallation (https://github.com/ansible-collections/community.general/issues/553,
https://github.com/ansible-collections/community.general/pull/11688).
- flatpak - support new output message when an update resulted in no action
that appears on Fedora 44 (https://github.com/ansible-collections/community.general/pull/11836).
- flatpak_remote - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11773).
- git_config - normalize locale environment for ``run_command()`` calls to
``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- git_config_info - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11738).
- gitlab_project_members - fail with a clear error when multiple projects
match the given name, instead of silently operating on the first result
(https://github.com/ansible-collections/community.general/issues/2767, https://github.com/ansible-collections/community.general/pull/11851).
- gitlab_project_variable - use ``find_project()`` from module utils for project
lookup, consistent with all other GitLab modules in the collection (https://github.com/ansible-collections/community.general/issues/3157,
https://github.com/ansible-collections/community.general/pull/11878).
- hg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11773).
- homebrew - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- homebrew_cask - fix ``sudo_password`` failing when the password contains
single quotes or other special shell characters (https://github.com/ansible-collections/community.general/issues/4957,
https://github.com/ansible-collections/community.general/pull/11850).
- homebrew_cask - fix failure when ``brew --version`` returns a placeholder
version string (https://github.com/ansible-collections/community.general/issues/4708,
https://github.com/ansible-collections/community.general/pull/11849).
- homebrew_cask - fix false task failure when upgrading casks with ``version=latest``;
the post-upgrade check incorrectly re-ran ``brew outdated`` (which always
lists ``latest`` casks as outdated under ``--greedy``), now uses the command
exit code instead (https://github.com/ansible-collections/community.general/issues/1647,
https://github.com/ansible-collections/community.general/pull/11838).
- homebrew_cask - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- homebrew_tap - fix ``None`` being passed as a command argument when adding
a tap without a URL (https://github.com/ansible-collections/community.general/pull/11848).
- homectl - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/pull/11860).
- homectl - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11774).
- icinga2_feature - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- imgadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- incus connection plugin - work when the active become plugin sets ``require_tty``
instead of failing silently (https://github.com/ansible-collections/community.general/pull/11771).
- ip_netns - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11779).
- ipa module utils - fix failure to detect errors reported in the ``failed``
field of the IPA API response, which is returned with HTTP 200 on partial
or full failures in member add/remove operations (https://github.com/ansible-collections/community.general/issues/1239,
https://github.com/ansible-collections/community.general/pull/11698).
- ipa_dnsrecord - fix errors when module is used with existing record with
default TTL (https://github.com/ansible-collections/community.general/pull/11717).
- ipa_host - fix logic to disable existing hosts (https://github.com/ansible-collections/community.general/issues/11483,
https://github.com/ansible-collections/community.general/pull/11487).
- iptables_state - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- iso_extract - retry ``umount`` up to 5 times preventing ``OSError`` on cleanup
(https://github.com/ansible-collections/community.general/issues/5333, https://github.com/ansible-collections/community.general/pull/11837).
- iso_extract - strip leading path separator from file entries so files with
a leading ``/`` are extracted correctly (https://github.com/ansible-collections/community.general/issues/5283,
https://github.com/ansible-collections/community.general/pull/11825).
- java_cert - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11774).
- java_keystore - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- keyring - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11774).
- keyring_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11786).
- kibana_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11783).
- known_hosts module utils - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set
when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- launchd - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11774).
- lbu - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- listen_ports_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11774).
- lldp - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11785).
- locale_gen - add missing locale entries to ``/etc/locale.gen`` when not
already present (https://github.com/ansible-collections/community.general/issues/2399,
https://github.com/ansible-collections/community.general/pull/11824).
- logrotate - adds missing default values for ``state`` and ``config_dir``
parameters, and adds ``required_by`` declarations for shred and compression
parameters (https://github.com/ansible-collections/community.general/pull/11764).
- logrotate - fixes ``TypeError`` when ``shred_cycles`` is ``None`` and corrects
``enabled=None`` handling in ``get_config_path()`` (https://github.com/ansible-collections/community.general/pull/11764).
- logrotate - writes configuration files to a temporary file first and validates
before atomically moving to the destination, and properly wraps all ``os.remove()``
and ``atomic_move()`` calls in error handling (https://github.com/ansible-collections/community.general/pull/11764).
- logstash_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11775).
- lvg - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11775).
- lvol - fix LVM version parsing (https://github.com/ansible-collections/community.general/issues/5445,
https://github.com/ansible-collections/community.general/pull/11823).
- lvol - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- lxc_container - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11779).
- machinectl become plugin - prevent printing ANSI terminal color sequences
(https://github.com/ansible-collections/community.general/pull/11771).
- macports - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- mas - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11775).
- modprobe - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- monit - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- mssql_db - fail with a clear error message when a named instance (``server\instance``
format) is used together with ``login_port``, since these are mutually exclusive
connection methods (https://github.com/ansible-collections/community.general/issues/5693,
https://github.com/ansible-collections/community.general/pull/11664).
- mssql_script - fail with a clear error message when a named instance (``server\instance``
format) is used together with ``login_port``, since these are mutually exclusive
connection methods (https://github.com/ansible-collections/community.general/issues/5693,
https://github.com/ansible-collections/community.general/pull/11664).
- mssql_script - only passes ``params`` to ``cursor.execute()`` when the user
actually provides them (https://github.com/ansible-collections/community.general/issues/11699,
https://github.com/ansible-collections/community.general/pull/11754).
- nmcli - use ``get_best_parsable_locale()`` to set locale environment for
``run_command()`` calls, fixing UTF-8 connection names being corrupted to
``????`` under ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/10384,
https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11742).
- nsupdate - fix GSS-TSIG support (accidentally broken by https://github.com/ansible-collections/community.general/pull/11461,
https://github.com/ansible-collections/community.general/pull/11712)
- ohai - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11785).
- onepassword_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11786).
- open_iscsi - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- openbsd_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11767).
- openwrt_init - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11784).
- osx_defaults - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11775).
- pacemaker_resource, pacemaker_stonith - fix resource and stonith creation
race condition by polling PCS status (https://github.com/ansible-collections/community.general/issues/11574,
https://github.com/ansible-collections/community.general/pull/11750).
- pacman - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- pacman_key - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- parted - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11740).
- pear - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11782).
- pip_package_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11784).
- pkg5 - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11780).
- pkg5_publisher - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11780).
- pkgin - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- pkgng - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11765).
- pkgutil - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11775).
- pnpm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11776).
- portage - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- portinstall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- redhat_subscription - normalize locale environment for ``run_command()``
calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- rhsm_release - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- rhsm_repository - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- riak - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11786).
- rpm_ostree_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- run0 become plugin - mark the plugin as incompatible with connection pipelining
(see https://github.com/ansible/ansible/issues/81254, https://github.com/ansible-collections/community.general/pull/11771).
- run0 become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
- runit - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- sefcontext - flush the in-process ``matchpathcon`` cache after applying
changes, so subsequent tasks running in the same process (for example via
the Mitogen connection plugin) see the updated SELinux file context rules
instead of stale cached data (https://github.com/ansible-collections/community.general/issues/888,
https://github.com/ansible-collections/community.general/pull/11812).
- smartos_image_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- snmp_facts - the module now also supports pysnmp >= 7.1 (https://github.com/ansible-collections/community.general/issues/8852,
https://github.com/ansible-collections/community.general/pull/11683).
- sorcery - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11767).
- supervisorctl - normalize locale environment for ``run_command()`` calls
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- svc - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- swdepot - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11780).
- syspatch - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- sysrc - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11776).
- sysupgrade - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11768).
- terraform - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11765).
- timezone - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11776).
- udm_user - allow to use passlib instead of legacycrypt for Python 3.13+
(https://github.com/ansible-collections/community.general/issues/4690, https://github.com/ansible-collections/community.general/pull/11860).
- udm_user - fix alias-to-canonical parameter name mismatch that caused all
camelCase-aliased parameters such as ``display_name`` and ``primary_group``
to be silently ignored (https://github.com/ansible-collections/community.general/issues/2950,
https://github.com/ansible-collections/community.general/issues/3691, https://github.com/ansible-collections/community.general/pull/11859).
- ufw - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- xattr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11776).
- xbps - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11781).
- xenserver_guest - fix an issue where booting from ISO is not possible because
CD-ROM device is placed in position above number 3. Position number 3 is
now reserved for CD-ROM device and cannot be occupied by a disk (https://github.com/ansible-collections/community.general/issues/11624,
https://github.com/ansible-collections/community.general/pull/11702).
- yarn - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11776).
- yum_versionlock - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11777).
- zfs - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11778).
- zfs_delegate_admin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11778).
- zfs_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11778).
- zpool_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11778).
- zypper - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11741).
- zypper_repository - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11777).
- zypper_repository_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
https://github.com/ansible-collections/community.general/pull/11782).
minor_changes:
- cobbler_sync - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- cobbler_system - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- composer - add ``force`` parameter; when ``command=create-project``, the
module now checks whether a ``composer.json`` already exists in ``working_dir``
and skips the command if so, making the task idempotent. Set ``force=true``
to always run the command regardless (https://github.com/ansible-collections/community.general/issues/725,
https://github.com/ansible-collections/community.general/pull/11689).
- consul_kv - add ``ca_path`` option to specify a CA bundle for HTTPS connections
(https://github.com/ansible-collections/community.general/pull/11817).
- consul_kv lookup plugin - add ``ca_path`` option to specify a CA bundle
for HTTPS connections (https://github.com/ansible-collections/community.general/issues/2876,
https://github.com/ansible-collections/community.general/pull/11817).
- dconf - add support for C(dbus-broker) (https://github.com/ansible-collections/community.general/issues/495,
https://github.com/ansible-collections/community.general/pull/11772).
- filesystem - migrate ``LVM.get_fs_size()`` to use ``CmdRunner``, ensuring
locale-independent output parsing (https://github.com/ansible-collections/community.general/pull/11888).
- flatpak - add new parameter ``from_url`` to install a flatpak from a ``.flatpakref``
URL (https://github.com/ansible-collections/community.general/issues/4000,
https://github.com/ansible-collections/community.general/pull/11748).
- gem - refactor module to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11733).
- homebrew_services - remove various redundancies including dead state validation,
unused return values, and unnecessary locale environment variables (https://github.com/ansible-collections/community.general/pull/11839).
- homebrew_tap - avoid redundant ``brew tap`` calls when processing multiple
taps by fetching the tap list once upfront (https://github.com/ansible-collections/community.general/pull/11848).
- ipa_dnsrecord - add ``exclusive`` parameter to allow appending values to
existing records without replacing them (https://github.com/ansible-collections/community.general/issues/682,
https://github.com/ansible-collections/community.general/pull/11694).
- java_cert - support proxy authentication when ``https_proxy`` environment
variable includes credentials (https://github.com/ansible-collections/community.general/issues/4126,
https://github.com/ansible-collections/community.general/pull/11753).
- jira - add ``cloud`` option to support Jira Cloud's new search endpoint
``/rest/api/2/search/jql``, since the legacy ``/rest/api/2/search`` endpoint
has been removed on Jira Cloud (https://github.com/ansible-collections/community.general/issues/10786,
https://github.com/ansible-collections/community.general/pull/11701).
- jira - when ``cloud=true``, user-type fields (``assignee``, ``reporter``,
and any listed in the new ``custom_user_fields`` parameter) containing an
email address are automatically resolved to Jira Cloud account IDs (https://github.com/ansible-collections/community.general/issues/11734,
https://github.com/ansible-collections/community.general/pull/11735).
- logrotate - adds optional ``backup`` parameter to create a backup of the
existing configuration file before writing changes (https://github.com/ansible-collections/community.general/pull/11764).
- lvg - migrate to ``CmdRunner``, removing direct ``run_command`` calls and
``run_command_environ_update`` (https://github.com/ansible-collections/community.general/pull/11835).
- lvm_pv - migrate to ``CmdRunner`` using shared runners from ``module_utils/_lvm``
(https://github.com/ansible-collections/community.general/pull/11811).
- lvol - migrate to ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11887).
- manageiq module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- manageiq_alert_profiles - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- manageiq_alerts - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- oneview module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- oneview_san_manager - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- opendj_backendprop - refactor to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11728).
- packet_device - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- packet_ip_subnet - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- pacman - add ``root``, ``cachedir``, and ``config`` options to support installing
packages into an alternative root directory (https://github.com/ansible-collections/community.general/issues/438,
https://github.com/ansible-collections/community.general/pull/11681).
- parted - add ``unit_preserve_case`` option to control the case of the ``unit``
field in the return value, fixing the round-trip use case where the returned
unit is fed back as input (https://github.com/ansible-collections/community.general/issues/1860,
https://github.com/ansible-collections/community.general/pull/11813).
- pubnub_blocks - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- terraform - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
- xenserver_guest - use ``enumerate()`` instead of manual index variable in
``for`` loop (https://github.com/ansible-collections/community.general/pull/11721).
release_summary: Regular bugfix and feature release.
fragments:
- 10786-jira-cloud-search.yml
- 11487-ipa-host-fix-disable.yml
- 11664-mssql-named-instance-port.yml
- 11681-pacman-root-cachedir-config.yml
- 11688-flatpak-fix-runtime-removal.yml
- 11689-composer-create-project-idempotent.yml
- 11698-ipa-failed-response.yml
- 11702-xenserver_guest-cdrom-handling-fix.yml
- 11717-fix-error-dnsttl.yml
- 11721-xenserver-guest-codeqa.yml
- 11728-opendj_backendprop-cmdrunner.yml
- 11733-gem-cmd-runner.yml
- 11734-jira-cloud-assignee-email-resolution.yml
- 11738-run-command-locale-group3-batch1.yml
- 11740-run-command-locale-group3-batch2.yml
- 11741-run-command-locale-group3-batch3.yml
- 11742-run-command-locale-nmcli.yml
- 11748-flatpak-from-url.yml
- 11750-pacemaker-wait-race-condition.yml
- 11753-java-cert-proxy-auth.yml
- 11754-mssql-script-params-substitution.yml
- 11764-logrotate-fixes.yml
- 11765-group4-locale.yml
- 11767-group4-batch2-locale.yml
- 11768-group5-batch1-locale.yml
- 11771-incus-machinectl-run0-become-pty.yml
- 11772-dconf-dbus-broker.yml
- 11773-group5-batch2-locale.yml
- 11774-group5-batch3-locale.yml
- 11775-group5-batch4-locale.yml
- 11776-group5-batch5-locale.yml
- 11777-group5-batch6-locale.yml
- 11778-group5-batch7-locale.yml
- 11779-group5-batch8-locale.yml
- 11780-group5-batch9-locale.yml
- 11781-group5-batch10-locale.yml
- 11782-group5-batch11-locale.yml
- 11783-group5-batch12-locale.yml
- 11784-group5-batch13-locale.yml
- 11785-group5-batch14-locale.yml
- 11786-group5-batch15-locale.yml
- 11787-group5-batch16-locale.yml
- 11811-lvm_pv-use-cmdrunner.yml
- 11812-sefcontext-matchpathcon-cache-flush.yml
- 11813-parted-unit-preserve-case.yml
- 11817-consul-kv-ca-path.yml
- 11823-lvol-lvm-version-regex.yml
- 11824-locale-gen-gentoo.yml
- 11825-iso-extract-leading-slash.yml
- 11835-lvg-use-cmdrunner.yml
- 11836-fixes.yml
- 11837-iso-extract-umount-retry.yml
- 11838-homebrew-cask-upgrade-latest.yml
- 11839-homebrew-services-cleanup.yml
- 11848-homebrew-tap-fixes.yml
- 11849-homebrew-cask-brew-version.yml
- 11850-homebrew-cask-sudo-password.yml
- 11851-gitlab-project-members-ambiguous.yml
- 11859-udm_user-param-name-fix.yml
- 11860-udm_user-replace-crypt.yml
- 11861-etcd3-lookup-https.yml
- 11878-gitlab_project_variable-find_project.yml
- 11879-convert-format-to-fstrings.yml
- 11887-lvol-use-cmdrunner.yml
- 11888-filesystem-use-cmdrunner.yml
- 12.6.0.yml
- 682-ipa-dnsrecord-solo.yml
- 8852-snmp-facts-pysnmp7.yml
- fix-nsupdate-gss-tsig.yml
modules:
- description: Manages snap interface connections.
name: snap_connect
namespace: ''
release_date: '2026-04-20'

View File

@@ -0,0 +1,2 @@
bugfixes:
- scaleway_image_info, scaleway_ip_info, scaleway_organization_info, scaleway_security_group_info, scaleway_server_info, scaleway_snapshot_info, scaleway_volume_info - fix ``NoneType`` error when the Scaleway API returns an empty or non-JSON response body (https://github.com/ansible-collections/community.general/issues/11361, https://github.com/ansible-collections/community.general/pull/11918).

View File

@@ -0,0 +1,2 @@
minor_changes:
- "mattermost, rocketchat, slack - update default ``icon_url`` to ansible favicon (https://github.com/ansible-collections/community.general/pull/11909)."

View File

@@ -0,0 +1,2 @@
bugfixes:
- crypttab - fix parsing of options whose value contains an equal sign (https://github.com/ansible-collections/community.general/issues/4963, https://github.com/ansible-collections/community.general/pull/11926).

View File

@@ -0,0 +1 @@
release_summary: Regular bugfix release.

View File

@@ -8,6 +8,9 @@ sections:
toctree:
- filter_guide
- test_guide
- title: Deployment Guides
toctree:
- guide_ee
- title: Technology Guides
toctree:
- guide_alicloud

View File

@@ -0,0 +1,114 @@
..
Copyright (c) Ansible Project
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
SPDX-License-Identifier: GPL-3.0-or-later
.. _ansible_collections.community.general.docsite.guide_ee:
Execution Environment Guide
===========================
`Ansible Execution Environments <https://docs.ansible.com/projects/ansible/latest/getting_started_ee/index.html>`_
(EEs) are container images that bundle ansible-core, collections, and their Python and system dependencies.
They are the standard runtime for Red Hat Ansible Automation Platform and AWX, replacing the older virtualenv model.
They can also be used outside of RHAAP and AWX by using `ansible-navigator <https://docs.ansible.com/projects/navigator/>`__, or by using ansible-runner directly.
What runs in the EE
^^^^^^^^^^^^^^^^^^^
Only **controller-side plugins** run inside the EE. Their Python and system dependencies must be installed there.
This includes: lookup plugins, inventory plugins, callback plugins, connection plugins, become plugins, and filter plugins.
Modules run on the managed nodes and are transferred there at runtime — their dependencies must be present on the
target, not in the EE.
.. note::
Modules delegated to ``localhost`` (for example, those that interact with a remote API) are an exception:
they run on the controller and their dependencies must therefore be available in the EE.
Why community.general does not provide EE metadata
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``community.general`` ships dozens of controller-side plugins covering a very broad range of technologies.
Bundling the dependencies for all of them into a single EE image would almost certainly create irreconcilable
conflicts — both within the collection and with other collections or tools (such as ``ansible-lint``) that
share the same image.
For that reason, ``community.general`` does **not** provide Python or system package dependency metadata.
Users are expected to build purpose-built, minimal EEs containing only the dependencies
required by the specific plugins they actually use.
Finding the dependencies you need
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Every plugin that has external dependencies documents them in its ``requirements`` field.
You can inspect those with ``ansible-doc``:
.. code-block:: shell
$ ansible-doc -t lookup community.general.some_lookup | grep -A 10 "REQUIREMENTS"
Or browse the plugin's documentation page on `docs.ansible.com <https://docs.ansible.com/ansible/latest/collections/community/general/>`_.
For example, a lookup plugin that wraps an external service might list:
.. code-block:: yaml
requirements:
- some-python-library >= 1.2
An inventory plugin backed by a REST API might list:
.. code-block:: yaml
requirements:
- requests
- some-sdk
These are the packages you need to add to your EE.
Building a minimal EE with ansible-builder
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`ansible-builder <https://docs.ansible.com/projects/builder/en/latest/>`_ is the standard tool for creating EEs.
Install it with:
.. code-block:: shell
$ pip install ansible-builder
Create an ``execution-environment.yml`` **in your own project** — not inside ``community.general``
that includes only the dependencies needed for the plugins you use:
.. code-block:: yaml
version: 3
dependencies:
galaxy:
collections:
- name: community.general
python:
- some-python-library>=1.2
- requests
system:
- libxml2-devel [platform:rpm]
images:
base_image:
name: ghcr.io/ansible/community-ee-base:latest
Then build the image:
.. code-block:: shell
$ ansible-builder build -t my-custom-ee:latest
.. seealso::
- `ansible-builder documentation <https://docs.ansible.com/projects/builder/en/latest/>`_
- `Building EEs with ansible-builder <https://ansible-builder.readthedocs.io/en/latest/definition/>`_
- `Issue #2968 — original request for EE requirements support <https://github.com/ansible-collections/community.general/issues/2968>`_
- `Issue #4512 — design discussion for EE support in community.general <https://github.com/ansible-collections/community.general/issues/4512>`_

View File

@@ -12,7 +12,7 @@ The inventory plugin :ansplugin:`community.general.iocage#inventory` gets the in
See:
* `iocage - A FreeBSD Jail Manager <https://iocage.readthedocs.io/en/latest>`_
* `iocage - A FreeBSD Jail Manager <https://freebsd.github.io/iocage/>`_
* `man iocage <https://man.freebsd.org/cgi/man.cgi?query=iocage>`_
* `Jails and Containers <https://docs.freebsd.org/en/books/handbook/jails>`_

View File

@@ -20,7 +20,7 @@ As root at the iocage host, create three VNET jails with a DHCP interface from t
shell> iocage create --template ansible_client --name srv_3 bpf=1 dhcp=1 vnet=1
srv_3 successfully created!
See: `Configuring a VNET Jail <https://iocage.readthedocs.io/en/latest/networking.html#configuring-a-vnet-jail>`_.
See: `Configuring VNET <https://freebsd.github.io/iocage/networking.html#vimage-vnet>`_.
As admin at the controller, list the jails:
@@ -115,7 +115,7 @@ Optionally, create shared IP jails:
| None | srv_3 | off | down | jail | 14.2-RELEASE-p3 | em0|10.1.0.103/24 | - | ansible_client | no |
+------+-------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
See: `Configuring a Shared IP Jail <https://iocage.readthedocs.io/en/latest/networking.html#configuring-a-shared-ip-jail>`_
See: `Configuring a Shared IP Jail <https://freebsd.github.io/iocage/networking.html#shared-ip>`_
If iocage needs environment variable(s), use the option :ansopt:`community.general.iocage#inventory:env`. For example,

View File

@@ -5,7 +5,7 @@
namespace: community
name: general
version: 12.4.0
version: 12.6.1
readme: README.md
authors:
- Ansible (https://github.com/ansible)

View File

@@ -21,6 +21,7 @@ action_groups:
keycloak:
- keycloak_authentication
- keycloak_authentication_required_actions
- keycloak_authentication_v2
- keycloak_authz_authorization_scope
- keycloak_authz_custom_policy
- keycloak_authz_permission
@@ -371,6 +372,26 @@ plugin_routing:
tombstone:
removal_version: 3.0.0
warning_text: Use community.general.hpilo_info instead.
aix_devices:
deprecation:
removal_version: 15.0.0
warning_text: Use ibm.power_aix.devices instead. The C(ibm.power_aix) collection is actively maintained by IBM.
aix_filesystem:
deprecation:
removal_version: 15.0.0
warning_text: Use ibm.power_aix.filesystem instead. The C(ibm.power_aix) collection is actively maintained by IBM.
aix_inittab:
deprecation:
removal_version: 15.0.0
warning_text: Use ibm.power_aix.inittab instead. The C(ibm.power_aix) collection is actively maintained by IBM.
aix_lvg:
deprecation:
removal_version: 15.0.0
warning_text: Use ibm.power_aix.lvg instead. The C(ibm.power_aix) collection is actively maintained by IBM.
aix_lvol:
deprecation:
removal_version: 15.0.0
warning_text: Use ibm.power_aix.lvol instead. The C(ibm.power_aix) collection is actively maintained by IBM.
idrac_firmware:
redirect: dellemc.openmanage.idrac_firmware
idrac_redfish_facts:

View File

@@ -82,9 +82,26 @@ options:
- name: ansible_doas_prompt_l10n
env:
- name: ANSIBLE_DOAS_PROMPT_L10N
allow_pipelining:
description:
- When set to V(true), do allow pipelining with ansible-core 2.19+.
- This should only be used when doas is configured to not ask for a password (C(nopass)).
type: boolean
default: false
version_added: 12.4.0
ini:
- section: doas_become_plugin
key: allow_pipelining
vars:
- name: ansible_doas_allow_pipelining
env:
- name: ANSIBLE_DOAS_ALLOW_PIPELINING
notes:
- This become plugin does not work when connection pipelining is enabled. With ansible-core 2.19+, using it automatically
disables pipelining. On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
- This become plugin does not work when connection pipelining is enabled
and doas requests a password.
With ansible-core 2.19+, using this plugin automatically disables pipelining,
unless O(allow_pipelining=true) is explicitly set by the user.
On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
"""
import re
@@ -101,8 +118,11 @@ class BecomeModule(BecomeBase):
missing = ("Authorization required",)
# See https://github.com/ansible-collections/community.general/issues/9977,
# https://github.com/ansible/ansible/pull/78111
pipelining = False
# https://github.com/ansible/ansible/pull/78111,
# https://github.com/ansible-collections/community.general/issues/11411
@property
def pipelining(self) -> bool: # type: ignore[override]
return self.get_option("allow_pipelining")
def check_password_prompt(self, b_output):
"""checks if the expected password prompt exists in b_output"""

View File

@@ -124,7 +124,10 @@ class BecomeModule(BecomeBase):
flags = self.get_option("become_flags")
user = self.get_option("become_user")
return f"{become} -q shell {flags} {user}@ {self._build_success_command(cmd, shell)}"
# SYSTEMD_COLORS=0 stops machinectl from appending ANSI reset
# sequences (ESC[0m, ESC[J) after the child exits, which would
# otherwise land after the module JSON and break result parsing.
return f"SYSTEMD_COLORS=0 {become} -q shell {flags} {user}@ {self._build_success_command(cmd, shell)}"
def check_success(self, b_output):
b_output = self.remove_ansi_codes(b_output)

View File

@@ -60,6 +60,8 @@ options:
type: string
notes:
- This plugin only works when a C(polkit) rule is in place.
- This become plugin does not work when connection pipelining is enabled. With ansible-core 2.19+, using it automatically
disables pipelining. On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
"""
EXAMPLES = r"""
@@ -91,6 +93,10 @@ class BecomeModule(BecomeBase):
success = ("==== AUTHENTICATION COMPLETE ====",)
require_tty = True # see https://github.com/ansible-collections/community.general/issues/6932
# See https://github.com/ansible/ansible/issues/81254,
# https://github.com/ansible/ansible/pull/78111
pipelining = False
@staticmethod
def remove_ansi_codes(line):
return ansi_color_codes.sub(b"", line)
@@ -105,7 +111,11 @@ class BecomeModule(BecomeBase):
flags = self.get_option("become_flags")
user = self.get_option("become_user")
return f"{become} --user={user} {flags} {self._build_success_command(cmd, shell)}"
# SYSTEMD_COLORS=0 stops run0 from emitting terminal control
# sequences (window title OSC, ANSI reset) around the child
# command, which would otherwise corrupt the module JSON and
# break result parsing.
return f"SYSTEMD_COLORS=0 {become} --user={user} {flags} {self._build_success_command(cmd, shell)}"
def check_success(self, b_output):
b_output = self.remove_ansi_codes(b_output)

View File

@@ -157,6 +157,8 @@ class CallbackModule(CallbackBase):
msg = f"changed: {self._host_counter}/{self._host_total} [{result._host.get_name()}]"
color = C.COLOR_CHANGED
else:
if not self._plugin_options.get("display_ok_hosts", True):
return
if delegated_vars:
msg = f"ok: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> {delegated_vars['ansible_host']}]"
else:

View File

@@ -3,6 +3,8 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = """
name: loganalytics_ingestion
type: notification

View File

@@ -131,12 +131,18 @@ class Connection(ConnectionBase):
def _build_command(self, cmd) -> list[str]:
"""build the command to execute on the incus host"""
# Force pseudo-terminal allocation if the active become plugin
# requires one (e.g. community.general.machinectl), otherwise the
# become helper runs without a controlling tty and silently fails.
require_tty = self.become is not None and getattr(self.become, "require_tty", False)
exec_cmd: list[str] = [
self._incus_cmd,
"--project",
self.get_option("project"),
"exec",
*(["-T"] if getattr(self._shell, "_IS_WINDOWS", False) else []),
*(["-t"] if require_tty and not getattr(self._shell, "_IS_WINDOWS", False) else []),
f"{self.get_option('remote')}:{self._instance()}",
"--",
]

View File

@@ -2,6 +2,8 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
name: accumulate
short_description: Produce a list of accumulated sums of the input list contents

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_toml
author:
- Matt Williaks (@milliams)
- Matt Williams (@milliams)
version_added: 12.3.0
short_description: Convert variable to TOML string
description:

View File

@@ -93,6 +93,7 @@ compose:
"""
import json
from http import HTTPStatus
from urllib.error import HTTPError
from ansible.errors import AnsibleParserError
@@ -164,7 +165,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self.display.vvv(f"Error returned: {error_body}")
except Exception:
error_body = {"status": None}
if e.code == 404 and error_body.get("status") == "No objects found.":
if e.code == HTTPStatus.NOT_FOUND and error_body.get("status") == "No objects found.":
raise AnsibleParserError(
"Host filter returned no data. Please confirm your host_filter value is valid"
) from e
@@ -173,15 +174,15 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
response_body = response.read()
json_data = json.loads(response_body.decode("utf-8"))
self.display.vvv(f"Returned Data: {json.dumps(json_data, indent=4, sort_keys=True)}")
if 200 <= response.status <= 299:
if HTTPStatus.OK <= response.status < HTTPStatus.MULTIPLE_CHOICES: # 2xx codes
return json_data
if response.status == 404 and json_data["status"] == "No objects found.":
if response.status == HTTPStatus.NOT_FOUND and json_data["status"] == "No objects found.":
raise AnsibleParserError(f"API returned no data -- Response: {response.status} - {json_data['status']}")
if response.status == 401:
if response.status == HTTPStatus.UNAUTHORIZED:
raise AnsibleParserError(
f"API was unable to complete query -- Response: {response.status} - {json_data['status']}"
)
if response.status == 500:
if response.status == HTTPStatus.INTERNAL_SERVER_ERROR:
raise AnsibleParserError(f"API Response - {json_data['status']} - {json_data['errors']}")
raise AnsibleParserError(f"Unexpected data returned - {json_data['status']} - {json_data['errors']}")

View File

@@ -34,7 +34,8 @@ options:
default: []
host_domain:
description:
- Domain to append to the host FQDN.
- Domain to append to the host.
- This is also used when O(host_fqdn) is not set since community.general 12.5.0.
type: string
host_fqdn:
description:
@@ -170,9 +171,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if self.get_option("host_fqdn"):
host_name = f"{host_name}.{project}.{remote_name}"
domain = self.get_option("host_domain")
if domain:
host_name = f"{host_name}.{domain}"
domain = self.get_option("host_domain")
if domain:
host_name = f"{host_name}.{domain}"
# Add some extra variables.
host_vars = {}

View File

@@ -3,6 +3,8 @@
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
name: binary_file
author: Felix Fontein (@felixfontein)

View File

@@ -57,13 +57,24 @@ options:
- If you use E(ANSIBLE_CONSUL_URL) this value is used from there.
validate_certs:
default: true
description: Whether to verify the TLS connection or not.
description:
- Whether to verify the TLS connection or not.
- Instead of setting this to V(false), please consider using O(ca_path) instead.
type: bool
env:
- name: ANSIBLE_CONSUL_VALIDATE_CERTS
ini:
- section: lookup_consul
key: validate_certs
ca_path:
description: The CA bundle to use for HTTPS connections.
type: str
version_added: "12.6.0"
env:
- name: ANSIBLE_CONSUL_CA_PATH
ini:
- section: lookup_consul
key: ca_path
client_cert:
description: The client cert to verify the TLS connection.
type: str
@@ -146,13 +157,16 @@ class LookupModule(LookupBase):
port = u.port
validate_certs = self.get_option("validate_certs")
ca_path = self.get_option("ca_path")
client_cert = self.get_option("client_cert")
verify = (ca_path or validate_certs) if validate_certs else False
values = []
try:
for term in terms:
params = self.parse_params(term)
consul_api = consul.Consul(host=host, port=port, scheme=scheme, verify=validate_certs, cert=client_cert)
consul_api = consul.Consul(host=host, port=port, scheme=scheme, verify=verify, cert=client_cert)
results = consul_api.kv.get(
params["key"],

View File

@@ -34,6 +34,8 @@ options:
V(https://hostname:2379), or V(<host>:<port>) form.
- The V(host) part is overwritten by O(host) option, if defined.
- The V(port) part is overwritten by O(port) option, if defined.
- Note that specifying V(https://) in the endpoint URL does not by itself enable TLS. To connect to an HTTPS etcd3
endpoint, you must provide O(ca_cert) (and optionally O(cert_cert) and O(cert_key)).
env:
- name: ETCDCTL_ENDPOINTS
default: '127.0.0.1:2379'
@@ -42,6 +44,8 @@ options:
description:
- Etcd3 listening client host.
- Takes precedence over O(endpoints).
- Must be a bare hostname or IP address without a URL scheme. If a V(https://) or V(http://) prefix is present,
it will be stripped automatically.
type: str
port:
description:
@@ -51,6 +55,7 @@ options:
ca_cert:
description:
- Etcd3 CA authority.
- Required to enable TLS when connecting to an HTTPS etcd3 endpoint.
env:
- name: ETCDCTL_CACERT
type: str
@@ -87,9 +92,11 @@ options:
type: str
notes:
- O(host) and O(port) options take precedence over (endpoints) option.
- O(host) and O(port) options take precedence over O(endpoints) option.
- The recommended way to connect to etcd3 server is using E(ETCDCTL_ENDPOINT) environment variable and keep O(endpoints),
O(host), and O(port) unused.
- To connect to an HTTPS etcd3 endpoint, the O(ca_cert) option must be provided. Merely specifying V(https://) in
O(endpoints) is not sufficient to enable TLS.
seealso:
- module: community.general.etcd3
- plugin: community.general.etcd
@@ -115,6 +122,10 @@ EXAMPLES = r"""
- name: "connect to etcd3 with a client certificate"
ansible.builtin.debug:
msg: "{{ lookup('community.general.etcd3', 'foo/bar', cert_cert='/etc/ssl/etcd/client.pem', cert_key='/etc/ssl/etcd/client.key') }}"
- name: "connect to etcd3 over HTTPS"
ansible.builtin.debug:
msg: "{{ lookup('community.general.etcd3', 'foo/bar', endpoints='https://etcd.example.com:2379', ca_cert='/etc/ssl/etcd/ca.pem') }}"
"""
RETURN = r"""
@@ -185,19 +196,42 @@ class LookupModule(LookupBase):
# etcd3 class expects host and port as connection parameters, so endpoints
# must be mangled a bit to fit in this scheme.
# so here we use a regex to extract server and port
is_https = False
match = re.compile(
r"^(https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$"
r"^(?P<scheme>https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$"
).match(self.get_option("endpoints"))
if match:
if match.group("host"):
client_params["host"] = match.group("host")
if match.group("port"):
client_params["port"] = match.group("port")
if match.group("scheme") and match.group("scheme").startswith("https"):
is_https = True
for opt in etcd3_cnx_opts:
if self.get_option(opt):
client_params[opt] = self.get_option(opt)
# strip URL scheme from host if present
if "host" in client_params:
host_match = re.match(r"^(?P<scheme>https?://)(?P<host>.+)$", client_params["host"])
if host_match:
display.warning(
f"The host option contained a URL scheme '{host_match.group('scheme')}' which has been removed. "
"Use a bare hostname or IP address for the host option. "
"To enable TLS, provide the ca_cert option."
)
client_params["host"] = host_match.group("host")
if host_match.group("scheme").startswith("https"):
is_https = True
if is_https and not self.get_option("ca_cert"):
display.warning(
"An HTTPS endpoint was specified but ca_cert was not provided. "
"The connection will be attempted without TLS. "
"To enable TLS, provide the ca_cert option."
)
cnx_log = dict(client_params)
if "password" in cnx_log:
cnx_log["password"] = "<redacted>"

View File

@@ -97,6 +97,7 @@ except ImportError:
import json
import time
from http import HTTPStatus
from urllib.error import HTTPError
from ansible.errors import AnsibleError, AnsibleOptionsError
@@ -177,9 +178,9 @@ def post_request(generated_jwt, installation_id, api_base):
display.vvv(f"Error returned: {error_body}")
except Exception:
error_body = {}
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
raise AnsibleError("Github return error. Please confirm your installation_id value is valid") from e
elif e.code == 401:
elif e.code == HTTPStatus.UNAUTHORIZED:
raise AnsibleError("Github return error. Please confirm your private key is valid") from e
raise AnsibleError(f"Unexpected data returned: {e} -- {error_body}") from e
response_body = response.read()

View File

@@ -9,6 +9,7 @@ author:
- Roy Lenferink (@rlenferink)
- Mark Ettema (@m-a-r-k-e)
- Alexander Petrenz (@alpex8)
- Christoph Fiehe (@cfiehe)
name: merge_variables
short_description: Merge variables whose names match a given pattern
description:
@@ -66,6 +67,81 @@ options:
type: list
elements: str
version_added: 8.5.0
dict_merge:
description:
- Behavior when encountering dictionary values.
type: str
default: deep
choices:
deep: Merge dictionaries recursively.
shallow: Merge only top-level values.
replace: Overwrite existing dictionaries.
keep: Keep existing dictionaries.
version_added: 12.5.0
list_merge:
description:
- Behavior when encountering list values.
type: str
default: append
choices:
replace: Overwrite existing lists.
keep: Keep existing lists.
append: Append elements to the end of an existing list.
prepend: Insert elements at the beginning of an existing list.
merge: Take the index as key and merge each element.
version_added: 12.5.0
type_conflict_merge:
description:
- Merge strategy to apply on type conflicts.
- This value is only considered in case of O(override=warn) or O(override=ignore).
type: str
default: replace
choices:
replace: Overwrite existing values.
keep: Keep existing values.
version_added: 12.5.0
default_merge:
description:
- Merge strategy applied to other types.
- This value is only considered in case of O(override=warn) or O(override=ignore).
type: str
default: replace
choices:
replace: Overwrite existing values.
keep: Keep existing values.
version_added: 12.5.0
list_transformations:
description:
- List transformations applied to list types.
- The definition order corresponds to the order in which these transformations are applied.
- Elements can be a dict with the keys mentioned below or a string naming the transformation to apply.
type: list
elements: raw
suboptions:
name:
description:
- Name of the list transformation.
required: true
type: str
choices:
flatten: Flatten lists, converting nested lists into single lists. Does not support any additional options.
dedup: Remove duplicates from lists. Supported option is C(keep).
options:
description:
- Options as key value pairs.
type: dict
suboptions:
keep:
description:
- Determines which duplicates (if any) to keep.
- Only valid in combination with the O(list_transformations[].name=dedup) list transformation.
type: str
default: first
choices:
first: Drop duplicates except for the first occurrence.
last: Drop duplicates except for the last occurrence.
default: []
version_added: 12.5.0
"""
EXAMPLES = r"""
@@ -88,6 +164,32 @@ testb__test_dict:
ports:
- 3
testa_low_dict__test:
a:
a:
x: low_value
y: low_value
list:
- low_value
b:
- 1
- 1
- 2
- 3
testb_high_dict__test:
a:
a:
y: high_value
z: high_value
list:
- high_value
b:
- 3
- 4
- 4
- '5': value
# Merge variables that end with '__test_dict' and store the result in a variable 'example_a'
example_a: "{{ lookup('community.general.merge_variables', '__test_dict', pattern_type='suffix') }}"
@@ -105,6 +207,56 @@ example_b: "{{ lookup('community.general.merge_variables', '^.+__test_list$', in
# - "list init item 2"
# - "test a item 1"
# - "test b item 1"
# Shallow merge variables that end with '__test', insert list elements at the beginning of the list,
# remove duplicates from lists (keep the first occurrence), and store the result in a variable 'example_c'
example_c: "{{
lookup(
'community.general.merge_variables',
'^.+__test$',
dict_merge='shallow',
list_merge='prepend',
list_transformations=['dedup']) }}"
# The variable example_c now contains:
# a:
# a:
# y: high_value
# z: high_value
# list:
# - high_value
# b:
# - 3
# - 4
# - '5': value
# - 1
# - 2
# Deep merge variables that end with '__test', merge list elements by index, ignore overrides, apply the strategies
# 'keep' for type conflicts and 'replace' for other types, and store the result in a variable 'example_d'
example_d: "{{
lookup(
'community.general.merge_variables',
'^.+__test$',
dict_merge='deep',
list_merge='merge',
override='ignore',
type_conflict_merge='keep',
default_merge='replace') }}"
# The variable example_d now contains:
# a:
# a:
# x: low_value
# y: high_value
# list:
# - high_value
# z: high_value
# b:
# - 3
# - 4
# - 4
# - 3
"""
RETURN = r"""
@@ -114,16 +266,23 @@ _raw:
elements: raw
"""
import re
import typing as t
from abc import ABC, abstractmethod
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
if t.TYPE_CHECKING:
from collections.abc import Callable
display = Display()
def _verify_and_get_type(variable):
def _verify_and_get_type(variable: t.Any) -> str:
if isinstance(variable, list):
return "list"
elif isinstance(variable, dict):
@@ -133,12 +292,17 @@ def _verify_and_get_type(variable):
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
def run(self, terms: list[str], variables: dict[str, t.Any], **kwargs) -> list[t.Any]:
self.set_options(direct=kwargs)
initial_value = self.get_option("initial_value", None)
self._override = self.get_option("override", "error")
self._override_behavior = self.get_option("override", "error")
self._pattern_type = self.get_option("pattern_type", "regex")
self._groups = self.get_option("groups", None)
self._dict_merge = self.get_option("dict_merge", "deep")
self._list_merge = self.get_option("list_merge", "append")
self._type_conflict_merge = self.get_option("type_conflict_merge", "replace")
self._default_merge = self.get_option("default_merge", "replace")
self._list_transformations = self.get_option("list_transformations", [])
ret = []
for term in terms:
@@ -158,25 +322,25 @@ class LookupModule(LookupBase):
return ret
def _is_host_in_allowed_groups(self, host_groups):
def _is_host_in_allowed_groups(self, host_groups: list[str]) -> bool:
if "all" in self._groups:
return True
group_intersection = [host_group_name for host_group_name in host_groups if host_group_name in self._groups]
return bool(group_intersection)
def _var_matches(self, key, search_pattern):
def _var_matches(self, key: str, search_pattern: str) -> bool:
if self._pattern_type == "prefix":
return key.startswith(search_pattern)
elif self._pattern_type == "suffix":
return key.endswith(search_pattern)
elif self._pattern_type == "regex":
matcher = re.compile(search_pattern)
return matcher.search(key)
return matcher.search(key) is not None
return False
def _merge_vars(self, search_pattern, initial_value, variables):
def _merge_vars(self, search_pattern: str, initial_value: t.Any, variables: dict[str, t.Any]) -> t.Any:
display.vvv(f"Merge variables with {self._pattern_type}: {search_pattern}")
var_merge_names = sorted([key for key in variables.keys() if self._var_matches(key, search_pattern)])
display.vvv(f"The following variables will be merged: {var_merge_names}")
@@ -187,11 +351,42 @@ class LookupModule(LookupBase):
prev_var_type = _verify_and_get_type(initial_value)
result = initial_value
builder = (
MergerBuilder()
.with_type_strategy(list, ListMergeStrategies.from_name(self._list_merge))
.with_type_conflict_strategy(BaseMergeStrategies.from_name(self._type_conflict_merge))
.with_default_strategy(BaseMergeStrategies.from_name(self._default_merge))
.with_override_behavior(self._override_behavior)
)
if self._dict_merge == "deep":
builder.with_type_strategy(dict, DictMergeStrategies.Merge())
elif self._dict_merge == "shallow":
builder.with_shallow_merge()
else:
builder.with_type_strategy(dict, DictMergeStrategies.from_name(self._dict_merge))
for transformation in self._list_transformations:
if isinstance(transformation, str):
builder.with_transformation(list, ListTransformations.from_name(transformation))
elif isinstance(transformation, dict):
name = transformation["name"]
options = transformation.get("options", {})
builder.with_transformation(list, ListTransformations.from_name(name, **options))
else:
raise AnsibleError(
f"Transformations must be specified through values of type 'str' or 'dict', but a value of type '{type(transformation)}' was given"
)
merger = builder.build()
if self._templar is None:
raise AnsibleError("Templar is not available")
templar = self._templar.copy_with_new_env(available_variables=variables)
for var_name in var_merge_names:
temp_templar = self._templar.copy_with_new_env(
available_variables=variables
) # tmp. switch renderer to context of current variables
var_value = temp_templar.template(variables[var_name]) # Render jinja2 templates
var_value = templar.template(variables[var_name]) # Render jinja2 templates
var_type = _verify_and_get_type(var_value)
if prev_var_type is None:
@@ -203,29 +398,271 @@ class LookupModule(LookupBase):
result = var_value
continue
if var_type == "dict":
result = self._merge_dict(var_value, result, [var_name])
else: # var_type == "list"
result += var_value
result = merger.merge(path=[var_name], left=result, right=var_value)
return result
def _merge_dict(self, src, dest, path):
for key, value in src.items():
if isinstance(value, dict):
node = dest.setdefault(key, {})
self._merge_dict(value, node, path + [key])
elif isinstance(value, list) and key in dest:
dest[key] += value
class MergeStrategy(ABC):
@abstractmethod
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
raise NotImplementedError
class MergeStrategies:
@classmethod
def from_name(cls, name: str, *args, **kwargs) -> MergeStrategy:
if name in cls.strategies:
return cls.strategies[name](*args, **kwargs)
else:
raise AnsibleError(f"Unknown merge strategy '{name}'")
strategies: dict[str, Callable[..., t.Any]] = {}
class BaseMergeStrategies(MergeStrategies):
class Replace(MergeStrategy):
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
return right
class Keep(MergeStrategy):
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
return left
strategies = {
"replace": Replace,
"keep": Keep,
}
class DictMergeStrategies(MergeStrategies):
class Merge(MergeStrategy):
def merge(
self, merger: ObjectMerger, path: list[str], left: dict[str, t.Any], right: dict[str, t.Any]
) -> dict[str, t.Any]:
result = left
for key, value in right.items():
if key not in result:
result[key] = value
else:
path.append(key)
merged = merger.merge(path=path, left=result[key], right=value)
merger.before_override(path=path, old_value=result[key], new_value=merged)
result[key] = merged
return result
strategies = {
"merge": Merge,
"replace": BaseMergeStrategies.Replace,
"keep": BaseMergeStrategies.Keep,
}
class ListMergeStrategies(MergeStrategies):
class Append(MergeStrategy):
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
return left + right
class Prepend(MergeStrategy):
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
return right + left
class Merge(MergeStrategy):
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
result = left
for i, value in enumerate(right):
if i >= len(result):
result.extend(right[i:])
break
path.append(str(i))
merged = merger.merge(path=path, left=result[i], right=value)
merger.before_override(path=path, old_value=result[i], new_value=merged)
result[i] = merged
return result
strategies = {
"append": Append,
"prepend": Prepend,
"merge": Merge,
"replace": BaseMergeStrategies.Replace,
"keep": BaseMergeStrategies.Keep,
}
class Transformation(ABC):
@abstractmethod
def transform(self, merger: ObjectMerger, value: t.Any) -> t.Any:
raise NotImplementedError
class Transformations:
@classmethod
def from_name(cls, name: str, *args, **kwargs) -> Transformation:
if name in cls.transformations:
return cls.transformations[name](*args, **kwargs)
else:
raise AnsibleError(f"Unknown transformation '{name}'")
transformations: dict[str, Callable[..., t.Any]] = {}
class ListTransformations(Transformations):
class Dedup(Transformation):
def __init__(self, keep: str = "first"):
self.keep = keep
def transform(self, merger: ObjectMerger, value: list[t.Any]) -> list[t.Any]:
result = []
if self.keep == "first":
for item in value:
if item not in result:
result.append(item)
elif self.keep == "last":
for item in reversed(value):
if item not in result:
result.insert(0, item)
else:
if (key in dest) and dest[key] != value:
msg = f"The key '{key}' with value '{dest[key]}' will be overwritten with value '{value}' from '{'.'.join(path)}.{key}'"
raise AnsibleError(
f"Unsupported 'keep' value for deduplication transformation. Given was '{self.keep}', but must be either 'first' or 'last'"
)
if self._override == "error":
raise AnsibleError(msg)
if self._override == "warn":
display.warning(msg)
return result
dest[key] = value
class Flatten(Transformation):
def transform(self, merger: ObjectMerger, value: list[t.Any]) -> list[t.Any]:
result = []
for item in value:
if isinstance(item, list):
result.extend(self.transform(merger, item))
else:
result.append(item)
return result
return dest
transformations = {
"dedup": Dedup,
"flatten": Flatten,
}
class MergerBuilder:
def __init__(self) -> None:
self.type_strategies: list[tuple[type, MergeStrategy]] = []
self.type_conflict_strategy: MergeStrategy = BaseMergeStrategies.Replace()
self.default_strategy: MergeStrategy = BaseMergeStrategies.Replace()
self.transformations: list[tuple[type, Transformation]] = []
self.override_behavior: str = "error"
self.shallow_merge: bool = False
def with_shallow_merge(self, shallow_merge: bool = True) -> MergerBuilder:
self.shallow_merge = shallow_merge
return self
def with_override_behavior(self, override_behavior: str) -> MergerBuilder:
self.override_behavior = override_behavior
return self
def with_type_strategy(self, cls, merge_strategy: MergeStrategy) -> MergerBuilder:
self.type_strategies.append((cls, merge_strategy))
return self
def with_default_strategy(self, merge_strategy: MergeStrategy) -> MergerBuilder:
self.default_strategy = merge_strategy
return self
def with_type_conflict_strategy(self, merge_strategy: MergeStrategy) -> MergerBuilder:
self.type_conflict_strategy = merge_strategy
return self
def with_transformation(self, cls, *args: Transformation) -> MergerBuilder:
for transformation in args:
self.transformations.append((cls, transformation))
return self
def build(self) -> Merger:
merger = ObjectMerger(
type_strategies=self.type_strategies,
type_conflict_strategy=self.type_conflict_strategy,
default_strategy=self.default_strategy,
transformations=self.transformations,
override_behavior=self.override_behavior,
)
if self.shallow_merge:
return ShallowMerger(merger)
return merger
class Merger(ABC):
@abstractmethod
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
raise NotImplementedError
class ObjectMerger(Merger):
def __init__(
self,
type_strategies: list[tuple[type, MergeStrategy]],
type_conflict_strategy: MergeStrategy,
default_strategy: MergeStrategy,
transformations: list[tuple[type, Transformation]],
override_behavior: str,
) -> None:
self.type_strategies = type_strategies
self.type_conflict_strategy = type_conflict_strategy
self.default_strategy = default_strategy
self.transformations = transformations
self.override_behavior = override_behavior
def before_override(self, path: list[str], old_value: t.Any, new_value: t.Any) -> None:
if (
not isinstance(old_value, type(new_value))
and not isinstance(new_value, type(old_value))
or not isinstance(new_value, dict)
and not isinstance(new_value, list)
and old_value != new_value
):
# An override is regarded as a value type conflict or
# when both values are neither dicts nor lists and
# have different values
msg = f"The key '{path[-1]}' with value '{old_value}' will be overwritten with value '{new_value}' from '{'.'.join(path)}'"
if self.override_behavior == "error":
raise AnsibleError(msg)
elif self.override_behavior == "warn":
display.warning(msg)
def transform(self, value: t.Any) -> t.Any:
for cls, transformation in self.transformations:
if isinstance(value, cls):
value = transformation.transform(self, value)
return value
def lookup_merge_strategy(self, left: t.Any, right: t.Any) -> MergeStrategy:
for cls, merge_strategy in self.type_strategies:
if isinstance(left, cls) and isinstance(right, cls):
return merge_strategy
if not isinstance(left, type(right)) and not isinstance(right, type(left)):
return self.type_conflict_strategy
return self.default_strategy
def apply_merge_strategy(self, merge_strategy: MergeStrategy, path: list[str], left: t.Any, right: t.Any) -> t.Any:
return self.transform(merge_strategy.merge(self, path, left, right))
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
return self.apply_merge_strategy(self.lookup_merge_strategy(left, right), path, left, right)
class ShallowMerger(Merger):
def __init__(self, merger: ObjectMerger) -> None:
self.merger = merger
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
if isinstance(left, dict) and isinstance(right, dict):
return self.merger.apply_merge_strategy(DictMergeStrategies.Merge(), path, left, right)
return self.merger.merge(path, left, right)

View File

@@ -259,38 +259,21 @@ from ansible_collections.community.general.plugins.module_utils._filelock import
display = Display()
# backhacked check_output with input for python 2.7
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
# note: contains special logic for calling 'pass', so not a drop-in replacement for check_output
def check_output2(*popenargs, **kwargs):
if "stdout" in kwargs:
raise ValueError("stdout argument not allowed, it will be overridden.")
if "stderr" in kwargs:
raise ValueError("stderr argument not allowed, it will be overridden.")
if "input" in kwargs:
if "stdin" in kwargs:
raise ValueError("stdin and input arguments may not both be used.")
b_inputdata = to_bytes(kwargs["input"], errors="surrogate_or_strict")
del kwargs["input"]
kwargs["stdin"] = subprocess.PIPE
else:
b_inputdata = None
process = subprocess.Popen(*popenargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
try:
b_out, b_err = process.communicate(b_inputdata)
except Exception:
process.kill()
process.wait()
raise
retcode = process.poll()
def run_backend_cmd(cmd, *, input=None, env=None):
result = subprocess.run(
cmd,
check=False,
capture_output=True,
input=to_bytes(input, errors="surrogate_or_strict") if input else None,
env=env,
)
b_out, b_err = result.stdout, result.stderr
retcode = result.returncode
if retcode == 0 and (
b"encryption failed: Unusable public key" in b_out or b"encryption failed: Unusable public key" in b_err
):
retcode = 78 # os.EX_CONFIG
if retcode != 0:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise subprocess.CalledProcessError(retcode, cmd, to_native(b_out + b_err, errors="surrogate_or_strict"))
return b_out
@@ -304,7 +287,7 @@ class LookupModule(LookupBase):
if self.realpass is None:
try:
passoutput = to_text(
check_output2([self.pass_cmd, "--version"], env=self.env), errors="surrogate_or_strict"
run_backend_cmd([self.pass_cmd, "--version"], env=self.env), errors="surrogate_or_strict"
)
self.realpass = "pass: the standard unix password manager" in passoutput
except subprocess.CalledProcessError as e:
@@ -349,7 +332,7 @@ class LookupModule(LookupBase):
# Collect pass environment variables from the plugin's parameters.
self.env = os.environ.copy()
self.env["LANGUAGE"] = "C" # make sure to get errors in English as required by check_output2
self.env["LANGUAGE"] = "C" # make sure to get errors in English as required by run_backend_cmd
if self.backend == "gopass":
self.env["GOPASS_NO_REMINDER"] = "YES"
@@ -371,7 +354,7 @@ class LookupModule(LookupBase):
def check_pass(self):
try:
self.passoutput = to_text(
check_output2([self.pass_cmd, "show"] + [self.passname], env=self.env), errors="surrogate_or_strict"
run_backend_cmd([self.pass_cmd, "show"] + [self.passname], env=self.env), errors="surrogate_or_strict"
).splitlines()
self.password = self.passoutput[0]
self.passdict = {}
@@ -456,7 +439,7 @@ class LookupModule(LookupBase):
msg += f"lookup_pass: old password was {self.password} (Updated on {datetime})\n"
try:
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
run_backend_cmd([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
except subprocess.CalledProcessError as e:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}") from e
return newpass
@@ -477,7 +460,7 @@ class LookupModule(LookupBase):
msg += f"\nlookup_pass: First generated by ansible on {datetime}\n"
try:
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
run_backend_cmd([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
except subprocess.CalledProcessError as e:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}") from e

View File

@@ -0,0 +1,45 @@
# Copyright (c) 2026, Alexei Znamensky <russoz@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
__all__ = ["CryptContext", "has_crypt_context"]
has_crypt_context = True
try:
from passlib.context import CryptContext
except ImportError:
try:
try:
import crypt as _crypt_mod
except ImportError:
import legacycrypt as _crypt_mod
_SCHEME_TO_METHOD = {
"sha512_crypt": _crypt_mod.METHOD_SHA512,
"sha256_crypt": _crypt_mod.METHOD_SHA256,
"md5_crypt": _crypt_mod.METHOD_MD5,
"des_crypt": _crypt_mod.METHOD_CRYPT,
}
class CryptContext: # type: ignore[no-redef]
@staticmethod
def verify(password, password_hash):
return _crypt_mod.crypt(password, password_hash) == password_hash
@staticmethod
def hash(password, scheme="sha512_crypt", rounds=10000):
method = _SCHEME_TO_METHOD.get(scheme)
if method is None:
raise ValueError(f"Unsupported scheme: {scheme}")
salt = _crypt_mod.mksalt(method, rounds=rounds)
return _crypt_mod.crypt(password, salt)
except ImportError:
class CryptContext: # type: ignore[no-redef]
pass
has_crypt_context = False

View File

@@ -0,0 +1,496 @@
# Copyright (c) 2026, Alexei Znamensky <russoz@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
# Do not use this from other collections or standalone plugins/modules!
from __future__ import annotations
import typing as t
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
if t.TYPE_CHECKING:
from ansible.module_utils.basic import AnsibleModule
# Options shared by the reporting commands: pvs, vgs, lvs (and pvdisplay in column mode).
_REPORT_ARG_FORMATS = dict(
noheadings=cmd_runner_fmt.as_fixed("--noheadings"),
nosuffix=cmd_runner_fmt.as_fixed("--nosuffix"),
readonly=cmd_runner_fmt.as_fixed("--readonly"),
units=cmd_runner_fmt.as_opt_val("--units"),
separator=cmd_runner_fmt.as_opt_val("--separator"),
fields=cmd_runner_fmt.as_opt_val("-o"),
select=cmd_runner_fmt.as_opt_val("--select"),
)
# ---- PV commands ----
def pvs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvs). Used by: community.general.lvg, community.general.lvm_pv,
community.general.lvm_pv_move_data, community.general.lvg_rename,
community.general.filesystem.
Suggested arg_formats keys: noheadings nosuffix readonly units separator fields select devices
"""
return CmdRunner(
module,
command="pvs",
arg_formats=dict(
**_REPORT_ARG_FORMATS,
devices=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvcreate). Used by: community.general.lvg, community.general.lvm_pv,
community.general.filesystem.
Suggested arg_formats keys: pv_options force yes device
Note: C(pv_options) accepts a pre-split list (e.g. from C(shlex.split())).
"""
return CmdRunner(
module,
command="pvcreate",
arg_formats=dict(
pv_options=cmd_runner_fmt.as_list(),
force=cmd_runner_fmt.as_bool("-f"),
yes=cmd_runner_fmt.as_bool("--yes"),
device=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvchange). Used by: community.general.lvg, community.general.filesystem.
Suggested arg_formats keys: uuid yes device
"""
return CmdRunner(
module,
command="pvchange",
arg_formats=dict(
uuid=cmd_runner_fmt.as_bool("-u"),
yes=cmd_runner_fmt.as_bool("--yes"),
device=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvresize_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvresize). Used by: community.general.lvg, community.general.lvm_pv,
community.general.filesystem.
Suggested arg_formats keys: set_size device
"""
return CmdRunner(
module,
command="pvresize",
arg_formats=dict(
set_size=cmd_runner_fmt.as_opt_val("--setphysicalvolumesize"),
device=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvremove). Used by: community.general.lvm_pv.
Suggested arg_formats keys: force device
Note: C(-y) is always passed (non-interactive). C(force=True) passes C(-ff),
which removes PVs even when part of a VG.
"""
return CmdRunner(
module,
command=["pvremove", "-y"],
arg_formats=dict(
force=cmd_runner_fmt.as_bool("-ff"),
device=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvdisplay_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvdisplay). Used by: community.general.lvg.
Enables machine-readable output via C(--columns). Fields such as C(dev_size),
C(pe_start), and C(vg_extent_size) are only available through C(pvdisplay),
not C(pvs).
Suggested arg_formats keys: columns noheadings nosuffix units separator fields device
"""
return CmdRunner(
module,
command="pvdisplay",
arg_formats=dict(
columns=cmd_runner_fmt.as_fixed("--columns"),
**_REPORT_ARG_FORMATS,
device=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def pvmove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(pvmove). Used by: community.general.lvm_pv_move_data.
Suggested arg_formats keys: auto_answer atomic autobackup verbosity source destination
Note: C(auto_answer) matches the O(auto_answer) module parameter.
Pass C(autobackup) as a boolean; it maps to C(--autobackup y/n).
"""
return CmdRunner(
module,
command="pvmove",
arg_formats=dict(
auto_answer=cmd_runner_fmt.as_bool("-y"),
atomic=cmd_runner_fmt.as_bool("--atomic"),
autobackup=cmd_runner_fmt.as_bool(["--autobackup", "y"], ["--autobackup", "n"], ignore_none=False),
verbosity=cmd_runner_fmt.as_func(lambda v: [f"-{'v' * v}"] if v > 0 else []),
source=cmd_runner_fmt.as_list(),
destination=cmd_runner_fmt.as_list(),
),
**kwargs,
)
# ---- VG commands ----
def vgs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgs). Used by: community.general.lvol, community.general.lvg,
community.general.lvg_rename.
Suggested arg_formats keys: noheadings nosuffix readonly units separator fields select vg
"""
return CmdRunner(
module,
command="vgs",
arg_formats=dict(
**_REPORT_ARG_FORMATS,
vg=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgcreate). Used by: community.general.lvg.
Suggested args order: vg_options pesize setautoactivation vg pvs
Note: C(vg) and C(pvs) are positional — C(vg) must appear before C(pvs)
in the args_order string. C(pvs) matches the O(pvs) module parameter in
community.general.lvg. C(vg_options) accepts a pre-split list (e.g. from
C(shlex.split())). C(setautoactivation) accepts C(True)/C(False)/C(None);
C(None) omits the flag entirely (C(ignore_none=True)).
"""
return CmdRunner(
module,
command="vgcreate",
arg_formats=dict(
vg_options=cmd_runner_fmt.as_list(),
pesize=cmd_runner_fmt.as_opt_val("-s"),
yes=cmd_runner_fmt.as_bool("--yes"),
setautoactivation=cmd_runner_fmt.as_bool(
["--setautoactivation", "y"],
["--setautoactivation", "n"],
ignore_none=True,
),
vg=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgchange). Used by: community.general.lvg, community.general.lvg_rename.
Suggested arg_formats keys: activate uuid setautoactivation help vg
Note: C(activate) and C(setautoactivation) are passed as booleans and map to
C(--activate y/n) and C(--setautoactivation y/n) respectively.
"""
return CmdRunner(
module,
command="vgchange",
arg_formats=dict(
activate=cmd_runner_fmt.as_bool(
["--activate", "y"],
["--activate", "n"],
ignore_none=False,
),
uuid=cmd_runner_fmt.as_bool("-u"),
setautoactivation=cmd_runner_fmt.as_bool(
["--setautoactivation", "y"],
["--setautoactivation", "n"],
ignore_none=False,
),
help=cmd_runner_fmt.as_fixed("--help"),
vg=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgextend_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgextend). Used by: community.general.lvg.
Suggested args order: vg pvs
Note: C(vg) must appear before C(pvs) in the args_order string.
C(pvs) matches the O(pvs) module parameter in community.general.lvg,
but callers must pass the subset of PVs to add explicitly.
"""
return CmdRunner(
module,
command="vgextend",
arg_formats=dict(
vg=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgreduce_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgreduce). Used by: community.general.lvg.
Suggested args order: force vg pvs
Note: C(vg) must appear before C(pvs) in the args_order string.
C(pvs) matches the O(pvs) module parameter in community.general.lvg,
but callers must pass the subset of PVs to remove explicitly.
"""
return CmdRunner(
module,
command="vgreduce",
arg_formats=dict(
force=cmd_runner_fmt.as_bool("--force"),
vg=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgremove). Used by: community.general.lvg.
Suggested arg_formats keys: force yes vg
"""
return CmdRunner(
module,
command="vgremove",
arg_formats=dict(
force=cmd_runner_fmt.as_bool("--force"),
yes=cmd_runner_fmt.as_bool("--yes"),
vg=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def vgrename_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(vgrename). Used by: community.general.lvg_rename.
Suggested args order: vg vg_new
Note: C(vg) (old name or UUID) must appear before C(vg_new) in the args_order string.
"""
return CmdRunner(
module,
command="vgrename",
arg_formats=dict(
vg=cmd_runner_fmt.as_list(),
vg_new=cmd_runner_fmt.as_list(),
),
**kwargs,
)
# ---- LV commands ----
def lvs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvs). Used by: community.general.lvol.
Suggested arg_formats keys: all noheadings nosuffix units separator fields select vg
Note: C(all) includes hidden internal LVs such as thin pool metadata.
"""
return CmdRunner(
module,
command="lvs",
arg_formats=dict(
all=cmd_runner_fmt.as_fixed("-a"),
**_REPORT_ARG_FORMATS,
vg=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def lvcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvcreate). Used by: community.general.lvol, community.general.lxc_container.
Suggested args order (normal LV): test yes lv size_L opts vg pvs
Suggested args order (snapshot): test yes size_L is_snapshot lv opts vg
Suggested args order (thin pool): test yes size_L opts thin vg pvs
Suggested args order (thin vol): test yes lv size_V opts thin vg
Note: C(vg) must appear after all option args and before C(pvs).
For snapshots and thin volumes, pass the origin as C(vg="{vg}/{lv}").
C(opts) accepts a pre-split list (e.g. from C(shlex.split())).
Intentional mismatches with module parameters:
- C(lv) matches O(lv) in community.general.lvol (the LV name, passed as C(-n lv)).
- C(is_snapshot) is a boolean flag for C(-s); it differs from the O(snapshot)
module parameter, which is a string holding the snapshot name.
- C(thin) is a boolean flag for C(-T); it differs from the O(thinpool)
module parameter, which is the pool name string.
- C(size_L), C(size_l), C(size_V) cannot match the O(size) module parameter
because one module param maps to three distinct CLI size options; callers
must always pass the appropriate size key explicitly.
- C(pvs) matches O(pvs) in community.general.lvol; callers must pass the value
explicitly since it is the list of PV paths, not the full module param value.
- C(opts) matches O(opts) in community.general.lvol; callers must pass the
pre-split list explicitly.
"""
return CmdRunner(
module,
command="lvcreate",
arg_formats=dict(
test=cmd_runner_fmt.as_bool("--test"),
yes=cmd_runner_fmt.as_bool("--yes"),
lv=cmd_runner_fmt.as_opt_val("-n"),
size_L=cmd_runner_fmt.as_opt_val("-L"),
size_l=cmd_runner_fmt.as_opt_val("-l"),
size_V=cmd_runner_fmt.as_opt_val("-V"),
is_snapshot=cmd_runner_fmt.as_bool("-s"),
thin=cmd_runner_fmt.as_fixed("-T"),
opts=cmd_runner_fmt.as_list(),
vg=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def lvchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvchange). Used by: community.general.lvol.
Suggested arg_formats keys: active lv
Note: C(active) matches the O(active) module parameter in community.general.lvol.
It maps to C(-ay) when true and C(-an) when false.
"""
return CmdRunner(
module,
command="lvchange",
arg_formats=dict(
active=cmd_runner_fmt.as_bool("-ay", "-an", ignore_none=False),
lv=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def lvextend_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvextend). Used by: community.general.lvol.
Suggested args order: test resizefs size_L lv pvs
(use size_l instead of size_L when sizing by extents or percentage)
Note: C(lv) must appear before C(pvs) in the args_order string.
C(pvs) matches the O(pvs) module parameter in community.general.lvol.
"""
return CmdRunner(
module,
command="lvextend",
arg_formats=dict(
test=cmd_runner_fmt.as_bool("--test"),
resizefs=cmd_runner_fmt.as_bool("--resizefs"),
size_L=cmd_runner_fmt.as_opt_val("-L"),
size_l=cmd_runner_fmt.as_opt_val("-l"),
lv=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def lvreduce_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvreduce). Used by: community.general.lvol.
Suggested args order: test force resizefs size_L lv pvs
(use size_l instead of size_L when sizing by extents or percentage)
Note: C(lv) must appear before C(pvs) in the args_order string.
C(pvs) matches the O(pvs) module parameter in community.general.lvol.
"""
return CmdRunner(
module,
command="lvreduce",
arg_formats=dict(
test=cmd_runner_fmt.as_bool("--test"),
force=cmd_runner_fmt.as_bool("--force"),
resizefs=cmd_runner_fmt.as_bool("--resizefs"),
size_L=cmd_runner_fmt.as_opt_val("-L"),
size_l=cmd_runner_fmt.as_opt_val("-l"),
lv=cmd_runner_fmt.as_list(),
pvs=cmd_runner_fmt.as_list(),
),
**kwargs,
)
def lvremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
"""
Runner for C(lvremove). Used by: community.general.lvol, community.general.lxc_container.
Suggested arg_formats keys: test force yes lv
"""
return CmdRunner(
module,
command="lvremove",
arg_formats=dict(
test=cmd_runner_fmt.as_bool("--test"),
force=cmd_runner_fmt.as_bool("--force"),
yes=cmd_runner_fmt.as_bool("--yes"),
lv=cmd_runner_fmt.as_list(),
),
**kwargs,
)

View File

@@ -35,6 +35,7 @@ class BtrfsCommands:
def __init__(self, module: AnsibleModule) -> None:
self.__module = module
self.__module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
self.__btrfs: str = self.__module.get_bin_path("btrfs", required=True)
def filesystem_show(self) -> list[dict[str, t.Any]]:

View File

@@ -8,6 +8,7 @@ import copy
import json
import re
import typing as t
from http import HTTPStatus
from urllib import error as urllib_error
from urllib.parse import urlencode
@@ -41,7 +42,7 @@ class RequestError(Exception):
def handle_consul_response_error(response):
if 400 <= response.status_code < 600:
if response.status_code >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
raise RequestError(f"{response.status_code} {response.content}")
@@ -242,9 +243,9 @@ class _ConsulModule:
try:
return self.get(url)
except RequestError as e:
if e.status == 404:
if e.status == HTTPStatus.NOT_FOUND:
return
elif e.status == 403 and b"ACL not found" in e.response_data:
elif e.status == HTTPStatus.FORBIDDEN and b"ACL not found" in e.response_data:
return
raise
@@ -321,7 +322,7 @@ class _ConsulModule:
)
raise
if 400 <= status < 600:
if status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
raise RequestError(status, response_data)
if response_data:

View File

@@ -6,6 +6,7 @@ from __future__ import annotations
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.urls import fetch_url
@@ -60,7 +61,7 @@ class GandiLiveDNSAPI:
resp, info = fetch_url(self.module, self.api_endpoint + api_call, headers=headers, data=data, method=method)
error_msg = ""
if info["status"] >= 400 and (info["status"] != 404 or error_on_404):
if info["status"] >= HTTPStatus.BAD_REQUEST and (info["status"] != HTTPStatus.NOT_FOUND or error_on_404):
err_s = self.error_strings.get(info["status"], "")
error_msg = f"API Error {err_s}: {self._build_error_message(self.module, info)}"
@@ -112,7 +113,7 @@ class GandiLiveDNSAPI:
records, status = self._gandi_api_call(url, error_on_404=False)
if status == 404:
if status == HTTPStatus.NOT_FOUND:
return []
if not isinstance(records, list):
@@ -135,8 +136,8 @@ class GandiLiveDNSAPI:
record, status = self._gandi_api_call(url, method="POST", payload=new_record)
if status in (
200,
201,
HTTPStatus.OK,
HTTPStatus.CREATED,
):
return new_record

View File

@@ -8,6 +8,7 @@ import re
import time
import traceback
import typing as t
from http import HTTPStatus
THIRD_LIBRARIES_IMP_ERR = None
try:
@@ -70,7 +71,7 @@ def session_method_wrapper(f):
raise HwcClientException(0, f"Parsing response to json failed, error: {ex}") from ex
code = r.status_code
if code not in [200, 201, 202, 203, 204, 205, 206, 207, 208, 226]:
if not (HTTPStatus.OK <= code < HTTPStatus.MULTIPLE_CHOICES): # not 2xx codes
msg = ""
for i in ["message", "error.message"]:
try:
@@ -81,7 +82,7 @@ def session_method_wrapper(f):
else:
msg = str(result)
if code == 404:
if code == HTTPStatus.NOT_FOUND:
raise HwcClientException404(msg)
raise HwcClientException(code, msg)

View File

@@ -8,6 +8,7 @@ import copy
import json
import traceback
import typing as t
from http import HTTPStatus
from urllib.error import HTTPError
from urllib.parse import quote, urlencode
@@ -102,6 +103,7 @@ URL_REALM_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{group}/role-m
URL_CLIENTSECRET = "{url}/admin/realms/{realm}/clients/{id}/client-secret"
URL_AUTHENTICATION_AUTHENTICATOR_PROVIDERS = "{url}/admin/realms/{realm}/authentication/authenticator-providers"
URL_AUTHENTICATION_FLOWS = "{url}/admin/realms/{realm}/authentication/flows"
URL_AUTHENTICATION_FLOW = "{url}/admin/realms/{realm}/authentication/flows/{id}"
URL_AUTHENTICATION_FLOW_COPY = "{url}/admin/realms/{realm}/authentication/flows/{copyfrom}/copy"
@@ -418,7 +420,7 @@ class KeycloakAPI:
validate_certs=self.validate_certs,
)
except HTTPError as e:
if e.code != 401:
if e.code != HTTPStatus.UNAUTHORIZED:
raise e
return e
@@ -440,7 +442,7 @@ class KeycloakAPI:
r = make_request_catching_401(headers)
except KeycloakError as e:
# Token refresh returns 400 if token is expired/invalid, so continue on if we get a 400
if e.authError is not None and e.authError.code != 400: # type: ignore # TODO!
if e.authError is not None and e.authError.code != HTTPStatus.BAD_REQUEST: # type: ignore # TODO!
raise e
if isinstance(r, Exception):
@@ -465,7 +467,7 @@ class KeycloakAPI:
r = make_request_catching_401(headers)
except KeycloakError as e:
# Token refresh returns 400 if token is expired/invalid, so continue on if we get a 400
if e.authError is not None and e.authError.code != 400: # type: ignore # TODO!
if e.authError is not None and e.authError.code != HTTPStatus.BAD_REQUEST: # type: ignore # TODO!
raise e
if isinstance(r, Exception):
@@ -496,7 +498,7 @@ class KeycloakAPI:
return self._request_and_deserialize(realm_info_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
@@ -525,7 +527,7 @@ class KeycloakAPI:
return self._request_and_deserialize(realm_keys_metadata_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
@@ -551,7 +553,7 @@ class KeycloakAPI:
return self._request_and_deserialize(realm_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
@@ -718,7 +720,7 @@ class KeycloakAPI:
return self._request_and_deserialize(client_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain client {id} for realm {realm}: {e}")
@@ -1310,7 +1312,7 @@ class KeycloakAPI:
return self._request_and_deserialize(clientscope_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch clientscope {cid} in realm {realm}: {e}")
@@ -1434,7 +1436,7 @@ class KeycloakAPI:
return self._request_and_deserialize(protocolmapper_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch protocolmapper {pid} in realm {realm}: {e}")
@@ -1641,7 +1643,7 @@ class KeycloakAPI:
return self._request_and_deserialize(clientsecret_url, method="POST")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain clientsecret of client {id} for realm {realm}: {e}")
@@ -1661,7 +1663,7 @@ class KeycloakAPI:
return self._request_and_deserialize(clientsecret_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not obtain clientsecret of client {id} for realm {realm}: {e}")
@@ -1695,7 +1697,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(groups_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch group {gid} in realm {realm}: {e}")
@@ -1967,7 +1969,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(role_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch role {name} in realm {realm}: {e}")
@@ -2169,7 +2171,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(role_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch role {name} in client {clientid} of realm {realm}: {e}")
@@ -2252,6 +2254,19 @@ class KeycloakAPI:
except Exception as e:
self.fail_request(e, msg=f"Unable to delete role {name} for client {clientid} in realm {realm}: {e}")
def get_authenticator_providers(self, realm: str = "master"):
"""
Get all available authenticator providers of the realm.
:param realm: Realm.
:return: List of authenticator provider representations.
"""
try:
return self._request_and_deserialize(
URL_AUTHENTICATION_AUTHENTICATOR_PROVIDERS.format(url=self.baseurl, realm=realm), method="GET"
)
except Exception as e:
self.fail_request(e, msg=f"Unable get authenticator providers in realm {realm}: {e}")
def get_authentication_flow_by_alias(self, alias, realm: str = "master"):
"""
Get an authentication flow by its alias
@@ -2273,6 +2288,35 @@ class KeycloakAPI:
except Exception as e:
self.fail_request(e, msg=f"Unable get authentication flow {alias}: {e}")
def get_authentication_flow_by_id(self, id, realm: str = "master"):
"""
Get an authentication flow by its id
:param id: id of the authentication flow to get.
:param realm: Realm.
:return: Authentication flow representation.
"""
flow_url = URL_AUTHENTICATION_FLOW.format(url=self.baseurl, realm=realm, id=id)
try:
return json.load(self._request(flow_url, method="GET"))
except Exception as e:
self.fail_request(e, msg=f"Could not get authentication flow {id} in realm {realm}: {e}")
def update_authentication_flow(self, id, config, realm: str = "master"):
"""
Updates an authentication flow
:param id: id of the authentication flow to update.
:param config: Authentication flow configuration.
:param realm: Realm.
:return: Authentication flow representation.
"""
flow_url = URL_AUTHENTICATION_FLOW.format(url=self.baseurl, realm=realm, id=id)
try:
return self._request(flow_url, method="PUT", data=json.dumps(config))
except Exception as e:
self.fail_request(e, msg=f"Could not get authentication flow {id} in realm {realm}: {e}")
def delete_authentication_flow_by_id(self, id, realm: str = "master"):
"""
Delete an authentication flow from Keycloak
@@ -2378,6 +2422,22 @@ class KeycloakAPI:
except Exception as e:
self.fail_request(e, msg=f"Unable to add authenticationConfig {executionId}: {e}")
def update_authentication_config(self, configId, authenticationConfig, realm: str = "master"):
"""
Updates an authentication config
:param configId: id of the authentication config
:param authenticationConfig: The authentication config
:param realm: realm of authentication config
"""
try:
self._request(
URL_AUTHENTICATION_CONFIG.format(url=self.baseurl, realm=realm, id=configId),
method="PUT",
data=json.dumps(authenticationConfig),
)
except Exception as e:
self.fail_request(e, msg=f"Unable to update the authentication config {configId}: {e}")
def delete_authentication_config(self, configId, realm: str = "master"):
"""Delete authenticator config
@@ -2597,7 +2657,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(idp_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch identity provider {alias} in realm {realm}: {e}")
@@ -2682,7 +2742,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(mapper_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(
@@ -2767,7 +2827,7 @@ class KeycloakAPI:
try:
return self._request_and_deserialize(comp_url, method="GET")
except HTTPError as e:
if e.code == 404:
if e.code == HTTPStatus.NOT_FOUND:
return None
else:
self.fail_request(e, msg=f"Could not fetch component {cid} in realm {realm}: {e}")

View File

@@ -17,6 +17,7 @@ import re
import socket
import typing as t
import uuid
from http import HTTPStatus
from urllib.parse import quote
from ansible.module_utils.basic import AnsibleFallbackNotFound, env_fallback
@@ -90,7 +91,7 @@ class IPAClient:
module=self.module, url=url, data=to_bytes(data), headers=headers, timeout=self.timeout
)
status_code = info["status"]
if status_code not in [200, 201, 204]:
if status_code not in (HTTPStatus.OK, HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
self._fail("login", info["msg"])
self.headers = {"Cookie": info.get("set-cookie")}
@@ -145,7 +146,7 @@ class IPAClient:
use_gssapi=self.use_gssapi,
)
status_code = info["status"]
if status_code not in [200, 201, 204]:
if status_code not in (HTTPStatus.OK, HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
self._fail(method, info["msg"])
except Exception as e:
self._fail(f"post {method}", f"{e}")
@@ -158,6 +159,9 @@ class IPAClient:
if "result" in resp:
result = resp.get("result")
failed = result.get("failed")
if failed:
self._fail(f"response {method}", failed)
if "result" in result:
result = result.get("result")
if isinstance(result, list):

View File

@@ -152,7 +152,7 @@ def add_host_key(module, fqdn, port=22, key_type="rsa", create_dir=False):
else:
this_cmd = f"{keyscan_cmd} -t {key_type} {fqdn}"
rc, out, err = module.run_command(this_cmd)
rc, out, err = module.run_command(this_cmd, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
# ssh-keyscan gives a 0 exit code and prints nothing on timeout
if rc != 0 or not out:
msg = "failed to retrieve hostkey"

View File

@@ -53,7 +53,6 @@ def check_client(module: AnsibleModule) -> None:
def validate_connection_params(module: AnsibleModule) -> dict[str, t.Any]:
params: dict[str, t.Any] = module.params["manageiq_connection"]
error_str = "missing required argument: manageiq_connection[{}]"
url: str | None = params["url"]
token: str | None = params["token"]
username: str | None = params["username"]
@@ -63,7 +62,7 @@ def validate_connection_params(module: AnsibleModule) -> dict[str, t.Any]:
return params
for arg in ["url", "username", "password"]:
if params[arg] in (None, ""):
module.fail_json(msg=error_str.format(arg))
module.fail_json(msg=f"missing required argument: manageiq_connection[{arg}]")
raise AssertionError("should be unreachable")
@@ -218,9 +217,9 @@ class ManageIQPolicies:
def query_resource_profiles(self):
"""Returns a set of the profile objects objects assigned to the resource"""
url = "{resource_url}/policy_profiles?expand=resources"
url = f"{self.resource_url}/policy_profiles?expand=resources"
try:
response = self.client.get(url.format(resource_url=self.resource_url))
response = self.client.get(url)
except Exception as e:
msg = f"Failed to query {self.resource_type} policies: {e}"
self.module.fail_json(msg=msg)
@@ -235,9 +234,9 @@ class ManageIQPolicies:
def query_profile_policies(self, profile_id):
"""Returns a set of the policy objects assigned to the resource"""
url = "{api_url}/policy_profiles/{profile_id}?expand=policies"
url = f"{self.api_url}/policy_profiles/{profile_id}?expand=policies"
try:
response = self.client.get(url.format(api_url=self.api_url, profile_id=profile_id))
response = self.client.get(url)
except Exception as e:
msg = f"Failed to query {self.resource_type} policies: {e}"
self.module.fail_json(msg=msg)
@@ -370,9 +369,9 @@ class ManageIQTags:
def query_resource_tags(self):
"""Returns a set of the tag objects assigned to the resource"""
url = "{resource_url}/tags?expand=resources&attributes=categorization"
url = f"{self.resource_url}/tags?expand=resources&attributes=categorization"
try:
response = self.client.get(url.format(resource_url=self.resource_url))
response = self.client.get(url)
except Exception as e:
msg = f"Failed to query {self.resource_type} tags: {e}"
self.module.fail_json(msg=msg)

View File

@@ -12,6 +12,7 @@
from __future__ import annotations
import urllib.error as urllib_error
from http import HTTPStatus
from urllib.parse import urlencode
from ansible.module_utils.basic import json
@@ -93,7 +94,7 @@ def check_zone_domain(data, domain):
"""
exists = False
if data.status_code in [201, 200]:
if data.status_code in (HTTPStatus.CREATED, HTTPStatus.OK):
for zone_domain in data.json():
if zone_domain["domain"] == domain:
exists = True
@@ -108,7 +109,7 @@ def check_zone(data, name):
counter = 0
exists = False
if data.status_code in [201, 200]:
if data.status_code in (HTTPStatus.CREATED, HTTPStatus.OK):
for zone in data.json():
if zone["nickname"] == name:
counter += 1

View File

@@ -15,6 +15,7 @@ import json
import time
import typing as t
import uuid
from http import HTTPStatus
from ansible.module_utils.urls import open_url
@@ -158,7 +159,7 @@ def list_pritunl_organizations(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException("Could not retrieve organizations from Pritunl")
else:
for org in json.loads(response.read()):
@@ -190,7 +191,7 @@ def list_pritunl_users(
organization_id=organization_id,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException("Could not retrieve users from Pritunl")
else:
for user in json.loads(response.read()):
@@ -220,7 +221,7 @@ def post_pritunl_organization(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException(f"Could not add organization {organization_name} to Pritunl")
# The user PUT request returns the updated user object
return json.loads(response.read())
@@ -246,7 +247,7 @@ def post_pritunl_user(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException(f"Could not remove user {user_id} from organization {organization_id} from Pritunl")
# user POST request returns an array of a single item,
# so return this item instead of the list
@@ -262,7 +263,7 @@ def post_pritunl_user(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException(f"Could not update user {user_id} from organization {organization_id} from Pritunl")
# The user PUT request returns the updated user object
return json.loads(response.read())
@@ -279,7 +280,7 @@ def delete_pritunl_organization(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException(f"Could not remove organization {organization_id} from Pritunl")
return json.loads(response.read())
@@ -297,7 +298,7 @@ def delete_pritunl_user(
validate_certs=validate_certs,
)
if response.getcode() != 200:
if response.getcode() != HTTPStatus.OK:
raise PritunlException(f"Could not remove user {user_id} from organization {organization_id} from Pritunl")
return json.loads(response.read())

View File

@@ -9,6 +9,7 @@ import json
import os
import typing as t
import uuid
from http import HTTPStatus
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
@@ -91,7 +92,7 @@ class OcapiUtils:
use_proxy=True,
timeout=self.timeout,
)
if resp.status != 204:
if resp.status != HTTPStatus.NO_CONTENT:
data = json.loads(resp.read())
else:
data = ""
@@ -390,7 +391,7 @@ class OcapiUtils:
job_uri = self.get_uri_with_slot_number_query_param(job_uri)
response = self.get_request(job_uri)
if response["ret"] is False:
if response.get("status") == 404:
if response.get("status") == HTTPStatus.NOT_FOUND:
# Job not found -- assume 0%
return {
"ret": True,
@@ -436,7 +437,7 @@ class OcapiUtils:
return {"ret": False, "changed": False, "msg": "Cannot delete job because it is in progress."}
if response["ret"] is False:
if response["status"] == 404:
if response["status"] == HTTPStatus.NOT_FOUND:
return {"ret": True, "changed": False, "msg": "Job already deleted."}
return response
if self.module.check_mode:
@@ -445,9 +446,9 @@ class OcapiUtils:
# Do the DELETE (unless we are in check mode)
response = self.delete_request(job_uri, etag)
if response["ret"] is False:
if response["status"] == 404:
if response["status"] == HTTPStatus.NOT_FOUND:
return {"ret": True, "changed": False}
elif response["status"] == 409:
elif response["status"] == HTTPStatus.CONFLICT:
return {"ret": False, "changed": False, "msg": "Cannot delete job because it is in progress."}
return response
return {"ret": True, "changed": True}

View File

@@ -186,7 +186,6 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
MSG_DELETED = "Resource deleted successfully."
MSG_ALREADY_PRESENT = "Resource is already present."
MSG_ALREADY_ABSENT = "Resource is already absent."
MSG_DIFF_AT_KEY = "Difference found at key '{0}'. "
ONEVIEW_COMMON_ARGS = dict(
config=dict(type="path"),
@@ -407,7 +406,7 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
if key not in resource2:
if resource1[key] is not None:
# Inexistent key is equivalent to exist with value None
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
return False
# If both values are null, empty or False it will be considered equal.
elif not resource1[key] and not resource2[key]:
@@ -415,15 +414,15 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
elif isinstance(resource1[key], Mapping):
# recursive call
if not self.compare(resource1[key], resource2[key]):
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
return False
elif isinstance(resource1[key], list):
# change comparison function to compare_list
if not self.compare_list(resource1[key], resource2[key]):
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
return False
elif _standardize_value(resource1[key]) != _standardize_value(resource2[key]):
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
return False
# Checks all keys in the second dict, looking for missing elements
@@ -431,7 +430,7 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
if key not in resource1:
if resource2[key] is not None:
# Inexistent key is equivalent to exist with value None
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
return False
return True

View File

@@ -7,6 +7,7 @@ from __future__ import annotations
import json
import sys
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.urls import fetch_url
@@ -60,7 +61,12 @@ class Response:
@property
def ok(self):
return self.status_code in (200, 201, 202, 204)
return self.status_code in (
HTTPStatus.OK,
HTTPStatus.CREATED,
HTTPStatus.ACCEPTED,
HTTPStatus.NO_CONTENT,
)
class Online:

View File

@@ -18,6 +18,7 @@ import typing as t
# (TODO: remove next line!)
from datetime import datetime # noqa: F401, pylint: disable=unused-import
from http import HTTPStatus
from operator import eq
try:
@@ -1381,7 +1382,7 @@ def delete_and_wait(
except MaximumWaitTimeExceeded as ex:
module.fail_json(msg=str(ex))
except ServiceError as ex:
if ex.status != 404:
if ex.status != HTTPStatus.NOT_FOUND:
module.fail_json(msg=ex.message)
else:
# While waiting for resource to get into terminated state, if the resource is not found.
@@ -1405,9 +1406,9 @@ def delete_and_wait(
# DNS API throws a 400 InvalidParameter when a zone id is provided for zone_name_or_id and if the zone
# resource is not available, instead of the expected 404. So working around this for now.
if isinstance(client, oci.dns.DnsClient):
if ex.status == 400 and ex.code == "InvalidParameter":
if ex.status == HTTPStatus.BAD_REQUEST and ex.code == "InvalidParameter":
_debug(f"Resource {resource_type} with {kwargs_get} already deleted. So returning changed=False")
elif ex.status != 404:
elif ex.status != HTTPStatus.NOT_FOUND:
module.fail_json(msg=ex.message)
result[resource_type] = dict()
return result
@@ -1654,7 +1655,7 @@ def get_existing_resource(target_fn, module: AnsibleModule, **kwargs):
response = call_with_backoff(target_fn, **kwargs)
existing_resource = response.data
except ServiceError as ex:
if ex.status != 404:
if ex.status != HTTPStatus.NOT_FOUND:
module.fail_json(msg=ex.message)
return existing_resource
@@ -1682,7 +1683,7 @@ def get_attached_instance_info(
# Pass ServiceError due to authorization issue in accessing volume attachments of a compartment
except ServiceError as ex:
if ex.status == 404:
if ex.status == HTTPStatus.NOT_FOUND:
pass
else:

View File

@@ -5,6 +5,7 @@
from __future__ import annotations
import re
import time
import typing as t
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
@@ -59,6 +60,22 @@ def get_pacemaker_maintenance_mode(runner: CmdRunner) -> bool:
return bool(maintenance_mode_output)
def wait_for_resource(runner: CmdRunner, cli_noun: str, name: str, wait: int, sleep_interval: int = 5) -> None:
"""Poll ``pcs <cli_noun> status <name>`` until the resource reports Started or the wait budget expires.
Raises an exception if the resource does not reach the Started state within *wait* seconds.
"""
deadline = time.monotonic() + wait
while True:
with runner("cli_action state name") as ctx:
rc, out, err = ctx.run(cli_action=cli_noun, state="status")
if out and "Started" in out:
return
if time.monotonic() >= deadline:
raise Exception(f"Timed out waiting {wait}s for {cli_noun} resource '{name}' to start")
time.sleep(sleep_interval)
def pacemaker_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
runner_command = ["pcs"]
runner = CmdRunner(

View File

@@ -52,12 +52,11 @@ def puppet_runner(module: AnsibleModule) -> CmdRunner:
# If this can be replaced with ansible `timeout` parameter in playbook,
# then this function could be removed.
def _prepare_base_cmd():
_tout_cmd = module.get_bin_path("timeout", False)
if _tout_cmd:
cmd = ["timeout", "-s", "9", module.params["timeout"], _puppet_cmd(module)]
else:
cmd = ["puppet"]
return cmd
if module.params["timeout"]:
_tout_cmd = module.get_bin_path("timeout", False)
if _tout_cmd:
return ["timeout", "-s", "9", module.params["timeout"], _puppet_cmd(module)]
return ["puppet"]
def noop_func(v):
return ["--noop"] if module.check_mode or v else ["--no-noop"]

View File

@@ -11,6 +11,7 @@ import random
import string
import time
import typing as t
from http import HTTPStatus
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
@@ -442,7 +443,7 @@ class RedfishUtils:
"""
msg = http_client.responses.get(error.code, "")
data = None
if error.code >= 400:
if error.code >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
try:
body = error.read().decode("utf-8")
data = json.loads(body)
@@ -1498,8 +1499,8 @@ class RedfishUtils:
response = self.post_request(self.root_uri + self.accounts_uri, payload)
if not response["ret"]:
if response.get("status") == 405:
# if POST returned a 405, try to add via PATCH
if response.get("status") == HTTPStatus.METHOD_NOT_ALLOWED:
# if POST is not allowed, try to add via PATCH
return self.add_user_via_patch(user)
else:
return response
@@ -1549,8 +1550,8 @@ class RedfishUtils:
response = self.delete_request(self.root_uri + uri)
if not response["ret"]:
if response.get("status") == 405:
# if DELETE returned a 405, try to delete via PATCH
if response.get("status") == HTTPStatus.METHOD_NOT_ALLOWED:
# if DELETE is not allowed, try to delete via PATCH
return self.delete_user_via_patch(user, uri=uri, data=data)
else:
return response
@@ -1868,7 +1869,7 @@ class RedfishUtils:
operation_results = {"status": None, "messages": [], "handle": None, "ret": True, "resets_requested": []}
if response.status == 204:
if response.status == HTTPStatus.NO_CONTENT:
# No content; successful, but nothing to return
# Use the Redfish "Completed" enum from TaskState for the operation status
operation_results["status"] = "Completed"
@@ -1877,7 +1878,7 @@ class RedfishUtils:
# Determine the next handle, if any
operation_results["handle"] = handle
if response.status == 202:
if response.status == HTTPStatus.ACCEPTED:
# Task generated; get the task monitor URI
operation_results["handle"] = response.getheader("Location", handle)
@@ -1891,15 +1892,15 @@ class RedfishUtils:
else:
# Error response body, which is a bit of a misnomer since it is used in successful action responses
operation_results["status"] = "Completed"
if response.status >= 400:
if response.status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
operation_results["status"] = "Exception"
operation_results["messages"] = data.get("error", {}).get("@Message.ExtendedInfo", [])
else:
# No response body (or malformed); build based on status code
operation_results["status"] = "Completed"
if response.status == 202:
if response.status == HTTPStatus.ACCEPTED:
operation_results["status"] = "New"
elif response.status >= 400:
elif response.status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
operation_results["status"] = "Exception"
# Clear out the handle if the operation is complete

View File

@@ -7,6 +7,7 @@ from __future__ import annotations
import json
import traceback
import typing as t
from http import HTTPStatus
from ansible.module_utils.urls import fetch_url, url_argument_spec
@@ -74,13 +75,15 @@ def api_request(
},
)
if info["status"] == 403:
_status = HTTPStatus(info["status"])
if _status == HTTPStatus.FORBIDDEN:
module.fail_json(msg="Token authorization failed", execution_info=json.loads(info["body"]))
elif info["status"] == 404:
elif _status == HTTPStatus.NOT_FOUND:
return None, info
elif info["status"] == 409:
elif _status == HTTPStatus.CONFLICT:
module.fail_json(msg="Job executions limit reached", execution_info=json.loads(info["body"]))
elif info["status"] >= 500:
elif _status >= HTTPStatus.INTERNAL_SERVER_ERROR: # 5xx errors
module.fail_json(msg="Rundeck API error", execution_info=json.loads(info["body"]))
try:

View File

@@ -12,6 +12,7 @@ import sys
import time
import traceback
import typing as t
from http import HTTPStatus
from urllib.parse import urlencode
from ansible.module_utils.basic import env_fallback, missing_required_lib
@@ -199,7 +200,12 @@ class Response:
@property
def ok(self):
return self.status_code in (200, 201, 202, 204)
return self.status_code in (
HTTPStatus.OK,
HTTPStatus.CREATED,
HTTPStatus.ACCEPTED,
HTTPStatus.NO_CONTENT,
)
class Scaleway:
@@ -231,10 +237,15 @@ class Scaleway:
results = self.get(f"/{self.name}")
if not results.ok:
api_response = results.json if results.json is not None else results.body
message = api_response.get("message") if isinstance(api_response, dict) else api_response
raise ScalewayException(
f"Error fetching {self.name} ({self.module.params.get('api_url')}/{self.name}) [{results.status_code}: {results.json['message']}]"
f"Error fetching {self.name} ({self.module.params.get('api_url')}/{self.name}) [{results.status_code}: {message}]"
)
if results.json is None:
raise ScalewayException(f"Scaleway API returned an empty or non-JSON response for {self.name}")
return results.json.get(self.name)
def _url_builder(self, path, params):
@@ -302,7 +313,7 @@ class Scaleway:
self.module.debug(f"fetch_state of resource: {resource['id']}")
response = self.get(path=f"{self.api_path}/{resource['id']}")
if response.status_code == 404:
if response.status_code == HTTPStatus.NOT_FOUND:
return "absent"
if not response.ok:

View File

@@ -45,6 +45,10 @@ def snap_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
info=cmd_runner_fmt.as_fixed("info"),
dangerous=cmd_runner_fmt.as_bool("--dangerous"),
version=cmd_runner_fmt.as_fixed("version"),
_connect=cmd_runner_fmt.as_func(lambda v: ["connect", v]),
_disconnect=cmd_runner_fmt.as_func(lambda v: ["disconnect", v]),
_connections=cmd_runner_fmt.as_fixed("connections"),
slot=cmd_runner_fmt.as_list(),
),
check_rc=False,
**kwargs,

View File

@@ -6,6 +6,7 @@ from __future__ import annotations
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.urls import basic_auth_header, fetch_url
@@ -56,7 +57,7 @@ class BitbucketHelper:
headers=headers,
)
if info["status"] == 200:
if info["status"] == HTTPStatus.OK:
self.access_token = content["access_token"]
else:
self.module.fail_json(msg=f"Failed to retrieve access token: {info}")

View File

@@ -13,6 +13,7 @@ from __future__ import annotations
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
@@ -116,7 +117,7 @@ class UTM:
returns the info for an object in utm
"""
info, result = self._lookup_entry(self.module, self.request_url)
if info["status"] >= 400:
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
self.module.fail_json(result=json.loads(info))
else:
if result is None:
@@ -133,7 +134,7 @@ class UTM:
is_changed = False
info, result = self._lookup_entry(self.module, self.request_url)
if info["status"] >= 400:
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
self.module.fail_json(result=json.loads(info))
else:
data_as_json_string = self.module.jsonify(self.module.params)
@@ -141,7 +142,7 @@ class UTM:
response, info = fetch_url(
self.module, self.request_url, method="POST", headers=combined_headers, data=data_as_json_string
)
if info["status"] >= 400:
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
self.module.fail_json(msg=json.loads(info["body"]))
is_changed = True
result = self._clean_result(json.loads(response.read()))
@@ -154,7 +155,7 @@ class UTM:
headers=combined_headers,
data=data_as_json_string,
)
if info["status"] >= 400:
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
self.module.fail_json(msg=json.loads(info["body"]))
is_changed = True
result = self._clean_result(json.loads(response.read()))
@@ -187,7 +188,7 @@ class UTM:
headers={"Accept": "application/json", "X-Restd-Err-Ack": "all"},
data=self.module.jsonify(self.module.params),
)
if info["status"] >= 400:
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
self.module.fail_json(msg=json.loads(info["body"]))
else:
is_changed = True

View File

@@ -13,6 +13,12 @@ module: aix_devices
short_description: Manages AIX devices
description:
- This module discovers, defines, removes and modifies attributes of AIX devices.
deprecated:
removed_in: 15.0.0
why: The module is not actively maintained.
alternative: >-
Use C(ibm.power_aix.devices) instead.
See U(https://ibm.github.io/ansible-power-aix/modules/devices.html) for details.
extends_documentation_fragment:
- community.general.attributes
attributes:

View File

@@ -14,6 +14,12 @@ short_description: Configure LVM and NFS file systems for AIX
description:
- This module creates, removes, mount and unmount LVM and NFS file system for AIX using C(/etc/filesystems).
- For LVM file systems is possible to resize a file system.
deprecated:
removed_in: 15.0.0
why: The module is not actively maintained.
alternative: >-
Use C(ibm.power_aix.filesystem) instead.
See U(https://ibm.github.io/ansible-power-aix/modules/filesystem.html) for details.
extends_documentation_fragment:
- community.general.attributes
attributes:

View File

@@ -13,6 +13,12 @@ module: aix_inittab
short_description: Manages the C(inittab) on AIX
description:
- Manages the C(inittab) on AIX.
deprecated:
removed_in: 15.0.0
why: The module is not actively maintained.
alternative: >-
Use C(ibm.power_aix.inittab) instead.
See U(https://ibm.github.io/ansible-power-aix/modules/inittab.html) for details.
extends_documentation_fragment:
- community.general.attributes
attributes:

View File

@@ -13,6 +13,12 @@ module: aix_lvg
short_description: Manage LVM volume groups on AIX
description:
- This module creates, removes or resize volume groups on AIX LVM.
deprecated:
removed_in: 15.0.0
why: The module is not actively maintained.
alternative: >-
Use C(ibm.power_aix.lvg) instead.
See U(https://ibm.github.io/ansible-power-aix/modules/lvg.html) for details.
extends_documentation_fragment:
- community.general.attributes
attributes:

View File

@@ -13,6 +13,12 @@ module: aix_lvol
short_description: Configure AIX LVM logical volumes
description:
- This module creates, removes or resizes AIX logical volumes. Inspired by M(community.general.lvol) module.
deprecated:
removed_in: 15.0.0
why: The module is not actively maintained.
alternative: >-
Use C(ibm.power_aix.lvol) instead.
See U(https://ibm.github.io/ansible-power-aix/modules/lvol.html) for details.
extends_documentation_fragment:
- community.general.attributes
attributes:

View File

@@ -163,7 +163,7 @@ class AlternativesModule:
def __init__(self, module):
self.module = module
self.result = dict(changed=False, diff=dict(before=dict(), after=dict()))
self.module.run_command_environ_update = {"LC_ALL": "C"}
self.module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
self.messages = []
self.run()

View File

@@ -72,6 +72,12 @@ options:
- Please notice that C(ansible-galaxy) does not install collections with O(type=both), when O(requirements_file) contains
both roles and collections and O(dest) is specified.
type: path
executable:
description:
- Path to the C(ansible-galaxy) executable.
- When not specified, the module uses C(ansible-galaxy) found by Ansible.
type: path
version_added: 12.5.0
no_deps:
description:
- Refrain from installing dependencies.
@@ -202,7 +208,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
)
ansible_version = None
output_params = ("type", "name", "dest", "requirements_file", "force", "no_deps")
output_params = ("type", "name", "dest", "requirements_file", "executable", "force", "no_deps")
module = dict(
argument_spec=dict(
state=dict(type="str", choices=["present", "latest"], default="present"),
@@ -210,6 +216,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
name=dict(type="str"),
requirements_file=dict(type="path"),
dest=dict(type="path"),
executable=dict(type="path"),
force=dict(type="bool", default=False),
no_deps=dict(type="bool", default=False),
),
@@ -234,7 +241,11 @@ class AnsibleGalaxyInstall(ModuleHelper):
def _make_runner(self, lang):
return CmdRunner(
self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=lang, check_rc=True
self.module,
command=self.vars.executable or self.command,
arg_formats=self.command_args_formats,
force_lang=lang,
check_rc=True,
)
def _get_ansible_galaxy_version(self):
@@ -264,7 +275,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
self.runner, self.vars.version = self._get_ansible_galaxy_version()
self.ansible_version = tuple(int(x) for x in self.vars.version.split(".")[:3])
if self.ansible_version < (2, 11):
self.module.fail_json(msg="Support for Ansible 2.9 and ansible-base 2.10 has been removed.")
self.do_raise(msg="Support for Ansible 2.9 and ansible-base 2.10 has been removed.")
self.vars.set("new_collections", {}, change=True)
self.vars.set("new_roles", {}, change=True)
if self.vars.type != "collection":

View File

@@ -245,6 +245,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
name = module.params["name"]
if name == "cgi" and module.params["state"] == "present" and _run_threaded(module):

View File

@@ -342,7 +342,7 @@ def main():
)
# Set LANG env since we parse stdout
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
global APK_PATH
APK_PATH = [module.get_bin_path("apk", required=True)]

View File

@@ -122,6 +122,7 @@ def main():
update=dict(type="bool", default=False),
),
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
if not os.path.exists(APT_REPO_PATH):
module.fail_json(msg="cannot find /usr/bin/apt-repo")

View File

@@ -175,7 +175,7 @@ def check_package_version(module, name):
# if newest version already installed return True
# otherwise return False
rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANG": "C"})
rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
installed = re.split("\n |: ", out)[2]
candidate = re.split("\n |: ", out)[4]
return installed >= candidate
@@ -204,7 +204,9 @@ def query_package_provides(module, name, allow_upgrade=False):
def update_package_db(module):
rc, update_out, err = module.run_command([APT_PATH, "update"], check_rc=True, environ_update={"LANG": "C"})
rc, update_out, err = module.run_command(
[APT_PATH, "update"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
)
return (False, update_out)
@@ -223,12 +225,16 @@ def clean(module):
def dist_upgrade(module):
rc, out, err = module.run_command([APT_PATH, "-y", "dist-upgrade"], check_rc=True, environ_update={"LANG": "C"})
rc, out, err = module.run_command(
[APT_PATH, "-y", "dist-upgrade"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
)
return (APT_GET_ZERO not in out, out)
def update_kernel(module):
rc, out, err = module.run_command(["/usr/sbin/update-kernel", "-y"], check_rc=True, environ_update={"LANG": "C"})
rc, out, err = module.run_command(
["/usr/sbin/update-kernel", "-y"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
)
return (UPDATE_KERNEL_ZERO not in out, out)
@@ -243,7 +249,9 @@ def remove_packages(module, packages):
if not query_package(module, package):
continue
rc, out, err = module.run_command([APT_PATH, "-y", "remove", package], environ_update={"LANG": "C"})
rc, out, err = module.run_command(
[APT_PATH, "-y", "remove", package], environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
)
if rc != 0:
module.fail_json(msg=f"failed to remove {package}: {err}")
@@ -267,7 +275,7 @@ def install_packages(module, pkgspec, allow_upgrade=False):
if packages:
command = [APT_PATH, "-y", "install"] + packages
rc, out, err = module.run_command(command, environ_update={"LANG": "C"})
rc, out, err = module.run_command(command, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
installed = True
for package in pkgspec:

View File

@@ -135,6 +135,7 @@ def main():
required_one_of=[["name", "activate"]],
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
global AWALL_PATH
AWALL_PATH = module.get_bin_path("awall", required=True)

View File

@@ -288,6 +288,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
be = BE(module)

View File

@@ -202,6 +202,7 @@ def main():
version=dict(),
)
module = AnsibleModule(argument_spec=arg_spec)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
name = module.params["name"]
offline = module.params["offline"]

View File

@@ -143,6 +143,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
state = module.params.get("state")
chdir = module.params.get("chdir")

View File

@@ -147,6 +147,7 @@ def main():
executable=dict(type="str"),
)
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
dest = module.params["dest"]
parent = module.params["name"]

View File

@@ -183,6 +183,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
CapabilitiesModule(module)

View File

@@ -254,7 +254,7 @@ def main():
module.fail_json(msg="Source directory does not exist")
# Set LANG env since we parse stdout
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
cargo = Cargo(module, **module.params)
changed, out, err = False, None, None

View File

@@ -99,9 +99,9 @@ def main():
use_ssl = module.params["use_ssl"]
validate_certs = module.params["validate_certs"]
module.params["proto"] = "https" if use_ssl else "http"
proto = "https" if use_ssl else "http"
if not port:
module.params["port"] = "443" if use_ssl else "80"
port = "443" if use_ssl else "80"
result = dict(
changed=True,
@@ -111,17 +111,13 @@ def main():
ssl_context = None if validate_certs or not use_ssl else ssl._create_unverified_context()
url = "{proto}://{host}:{port}/cobbler_api".format(**module.params)
url = f"{proto}://{module.params['host']}:{port}/cobbler_api"
conn = xmlrpc_client.ServerProxy(url, context=ssl_context)
try:
token = conn.login(username, password)
except xmlrpc_client.Fault as e:
module.fail_json(
msg="Failed to log in to Cobbler '{url}' as '{username}'. {error}".format(
url=url, error=f"{e}", **module.params
)
)
module.fail_json(msg=f"Failed to log in to Cobbler '{url}' as '{username}'. {e}")
except Exception as e:
module.fail_json(msg=f"Connection to '{url}' failed. {e}")

View File

@@ -220,9 +220,9 @@ def main():
name = module.params["name"]
state = module.params["state"]
module.params["proto"] = "https" if use_ssl else "http"
proto = "https" if use_ssl else "http"
if not port:
module.params["port"] = "443" if use_ssl else "80"
port = "443" if use_ssl else "80"
result = dict(
changed=False,
@@ -232,17 +232,13 @@ def main():
ssl_context = None if validate_certs or not use_ssl else ssl._create_unverified_context()
url = "{proto}://{host}:{port}/cobbler_api".format(**module.params)
url = f"{proto}://{module.params['host']}:{port}/cobbler_api"
conn = xmlrpc_client.ServerProxy(url, context=ssl_context)
try:
token = conn.login(username, password)
except xmlrpc_client.Fault as e:
module.fail_json(
msg="Failed to log in to Cobbler '{url}' as '{username}'. {error}".format(
url=url, error=f"{e}", **module.params
)
)
module.fail_json(msg=f"Failed to log in to Cobbler '{url}' as '{username}'. {e}")
except Exception as e:
module.fail_json(msg=f"Connection to '{url}' failed. {e}")

View File

@@ -98,6 +98,14 @@ options:
these.
default: false
type: bool
force:
description:
- When O(command) is V(create-project), the module checks whether a V(composer.json) already
exists in O(working_dir) and skips the command if it does, making the task idempotent.
- Set to V(true) to always run the command regardless.
default: false
type: bool
version_added: 12.6.0
composer_executable:
type: path
description:
@@ -139,6 +147,7 @@ EXAMPLES = r"""
arguments: my/package
"""
import os
import re
import shlex
@@ -212,11 +221,13 @@ def main():
optimize_autoloader=dict(default=True, type="bool"),
classmap_authoritative=dict(default=False, type="bool"),
ignore_platform_reqs=dict(default=False, type="bool"),
force=dict(default=False, type="bool"),
composer_executable=dict(type="path"),
),
required_if=[("global_command", False, ["working_dir"])],
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
# Get composer command with fallback to default
command = module.params["command"]
@@ -257,6 +268,12 @@ def main():
option = f"--{option}"
options.append(option)
working_dir = module.params["working_dir"]
if command == "create-project" and not module.params["force"]:
if working_dir and os.path.exists(os.path.join(working_dir, "composer.json")):
module.exit_json(changed=False, msg="composer.json already exists in working_dir, skipping create-project")
if module.check_mode:
if "dry-run" in available_options:
options.append("--dry-run")

View File

@@ -94,9 +94,15 @@ options:
default: http
validate_certs:
description:
- Whether to verify the tls certificate of the Consul agent.
- Whether to verify the TLS certificate of the Consul agent.
- Instead of setting this to V(false), please consider using O(ca_path) instead.
type: bool
default: true
ca_path:
description:
- The CA bundle to use for HTTPS connections.
type: str
version_added: "12.6.0"
datacenter:
description:
- The name of the datacenter to query. If unspecified, the query defaults to the datacenter of the Consul agent on O(host).
@@ -263,11 +269,14 @@ def remove_value(module):
def get_consul_api(module):
ca_path = module.params.get("ca_path")
validate_certs = module.params.get("validate_certs")
verify = (ca_path or validate_certs) if validate_certs else False
return consul.Consul(
host=module.params.get("host"),
port=module.params.get("port"),
scheme=module.params.get("scheme"),
verify=module.params.get("validate_certs"),
verify=verify,
token=module.params.get("token"),
dc=module.params.get("datacenter"),
)
@@ -291,6 +300,7 @@ def main():
host=dict(type="str", default="localhost"),
scheme=dict(type="str", default="http"),
validate_certs=dict(type="bool", default=True),
ca_path=dict(type="str"),
port=dict(type="int", default=8500),
recurse=dict(type="bool"),
retrieve=dict(type="bool", default=True),

View File

@@ -360,6 +360,7 @@ def main():
mutually_exclusive=[["insertbefore", "insertafter"]],
supports_check_mode=False,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
name = module.params["name"]
value = module.params["value"]

View File

@@ -281,7 +281,7 @@ class Options(dict):
self.itemlist = []
if opts_string is not None:
for opt in opts_string.split(","):
kv = opt.split("=")
kv = opt.split("=", 1)
if len(kv) > 1:
k, v = (kv[0], kv[1])
else:

View File

@@ -15,13 +15,15 @@ description:
- This module allows modifications and reading of C(dconf) database. The module is implemented as a wrapper around C(dconf)
tool. Please see the dconf(1) man page for more details.
- Since C(dconf) requires a running D-Bus session to change values, the module tries to detect an existing session and reuse
it, or run the tool using C(dbus-run-session).
it, or run the tool using C(dbus-run-session). Both C(dbus-daemon) and C(dbus-broker) are supported.
requirements:
- Optionally the C(gi.repository) Python library (usually included in the OS on hosts which have C(dconf)); this is to become
a non-optional requirement in a future major release of community.general.
notes:
- This module depends on C(psutil) Python library (version 4.0.0 and upwards), C(dconf), C(dbus-send), and C(dbus-run-session)
binaries. Depending on distribution you are using, you may need to install additional packages to have these available.
- This module depends on C(psutil) Python library (version 4.0.0 and upwards), C(dconf), and either C(dbus-send) or C(busctl)
for D-Bus session validation, and C(dbus-run-session) as a fallback when no existing session is found.
Depending on distribution you are using, you may need to install additional packages to have these available.
Both the reference C(dbus-daemon) implementation and C(dbus-broker) are supported.
- This module uses the C(gi.repository) Python library when available for accurate comparison of values in C(dconf) to values
specified in Ansible code. C(gi.repository) is likely to be present on most systems which have C(dconf) but may not be
present everywhere. When it is missing, a simple string comparison between values is used, and there may be false positives,
@@ -156,6 +158,13 @@ class DBusWrapper:
If possible, command will be run against an existing D-Bus session,
otherwise the session will be spawned via dbus-run-session.
Discovery order:
1. DBUS_SESSION_BUS_ADDRESS in the current process environment
2. /run/user/<uid>/bus -- canonical socket for systemd and dbus-broker
3. Process scan for DBUS_SESSION_BUS_ADDRESS -- legacy fallback
Validation uses C(dbus-send) if available, C(busctl) otherwise.
Example usage:
dbus_wrapper = DBusWrapper(ansible_module)
@@ -163,24 +172,32 @@ class DBusWrapper:
"""
def __init__(self, module):
"""
Initialises an instance of the class.
:param module: Ansible module instance used to signal failures and run commands.
:type module: AnsibleModule
"""
# Store passed-in arguments and set-up some defaults.
self.module = module
# Try to extract existing D-Bus session address.
self.dbus_session_bus_address = self._get_existing_dbus_session()
# If no existing D-Bus session was detected, check if dbus-run-session
# is available.
if self.dbus_session_bus_address is None:
self.dbus_run_session_cmd = self.module.get_bin_path("dbus-run-session", required=True)
def _validate_address(self, address):
dbus_send = self.module.get_bin_path("dbus-send")
if dbus_send:
rc, dummy, dummy = self.module.run_command(
[dbus_send, f"--address={address}", "--type=signal", "/", "com.example.test"]
)
if rc == 0:
return True
busctl = self.module.get_bin_path("busctl")
if busctl:
rc, dummy, dummy = self.module.run_command([busctl, f"--address={address}", "list"])
if rc == 0:
return True
if not dbus_send and not busctl:
self.module.fail_json(msg="Neither dbus-send nor busctl is available. Please install one of them.")
return False
def _get_existing_dbus_session(self):
"""
Detects and returns an existing D-Bus session bus address.
@@ -191,11 +208,25 @@ class DBusWrapper:
# We'll be checking the processes of current user only.
uid = os.getuid()
# Go through all the pids for this user, try to extract the D-Bus
# session bus address from environment, and ensure it is possible to
# connect to it.
self.module.debug(f"Trying to detect existing D-Bus user session for user: {int(uid)}")
# Step 1: current process environment
address = os.environ.get("DBUS_SESSION_BUS_ADDRESS")
if address:
self.module.debug(f"Trying D-Bus address from environment: {address}")
if self._validate_address(address):
self.module.debug(f"Using D-Bus session from environment: {address}")
return address
# Step 2: canonical systemd/dbus-broker socket path
canonical_path = f"/run/user/{uid}/bus"
if os.path.exists(canonical_path):
address = f"unix:path={canonical_path}"
self.module.debug(f"Trying canonical D-Bus socket: {canonical_path}")
if self._validate_address(address):
self.module.debug(f"Using canonical D-Bus socket: {canonical_path}")
return address
# Step 3: process scan (legacy fallback)
self.module.debug(f"Scanning processes for D-Bus session (uid={uid})")
for pid in psutil.pids():
try:
process = psutil.Process(pid)
@@ -205,21 +236,10 @@ class DBusWrapper:
self.module.debug(
f"Found D-Bus user session candidate at address: {dbus_session_bus_address_candidate}"
)
dbus_send_cmd = self.module.get_bin_path("dbus-send", required=True)
command = [
dbus_send_cmd,
f"--address={dbus_session_bus_address_candidate}",
"--type=signal",
"/",
"com.example.test",
]
rc, dummy, dummy = self.module.run_command(command)
if rc == 0:
if self._validate_address(dbus_session_bus_address_candidate):
self.module.debug(
f"Verified D-Bus user session candidate as usable at address: {dbus_session_bus_address_candidate}"
)
return dbus_session_bus_address_candidate
# This can happen with things like SSH sessions etc.
@@ -230,7 +250,6 @@ class DBusWrapper:
pass
self.module.debug("Failed to find running D-Bus user session, will use dbus-run-session")
return None
def run_command(self, command):
@@ -249,8 +268,7 @@ class DBusWrapper:
self.module.debug("Using dbus-run-session wrapper for running commands.")
command = [self.dbus_run_session_cmd] + command
rc, out, err = self.module.run_command(command)
if self.dbus_session_bus_address is None and rc == 127:
if rc == 127:
self.module.fail_json(
msg=f"Failed to run passed-in command, dbus-run-session faced an internal error: {err}"
)
@@ -311,7 +329,7 @@ class DconfPreference:
"""
command = [self.dconf_bin, "read", key]
rc, out, err = self.module.run_command(command)
rc, out, err = self.module.run_command(command, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
if rc != 0:
self.module.fail_json(msg=f"dconf failed while reading the value with error: {err}", out=out, err=err)

View File

@@ -257,6 +257,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
patterns = module.params["name"]
raw = module.params["raw"]

View File

@@ -171,6 +171,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
path = module.params["path"]
state = module.params["state"]

View File

@@ -139,6 +139,7 @@ def main():
)
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
name = module.params["name"]
env = module.params["virtualenv"]

View File

@@ -69,6 +69,7 @@ def main():
),
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
facter_path = module.get_bin_path("facter", opt_dirs=["/opt/puppetlabs/bin"])

View File

@@ -154,6 +154,7 @@ import stat
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._lvm import pvs_runner
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@@ -213,7 +214,7 @@ class Filesystem:
CHANGE_UUID_OPTION: str | None = None
CHANGE_UUID_OPTION_HAS_ARG = True
LANG_ENV = {"LANG": "C", "LC_ALL": "C", "LC_MESSAGES": "C"}
LANG_ENV = {"LANGUAGE": "C", "LC_ALL": "C"}
def __init__(self, module):
self.module = module
@@ -569,14 +570,15 @@ class LVM(Filesystem):
CHANGE_UUID_OPTION = "-u"
CHANGE_UUID_OPTION_HAS_ARG = False
def __init__(self, module):
super().__init__(module)
self._pvs = pvs_runner(module)
def get_fs_size(self, dev):
"""Get and return PV size, in bytes."""
cmd = self.module.get_bin_path(self.INFO, required=True)
dummy, size, dummy = self.module.run_command(
[cmd, "--noheadings", "-o", "pv_size", "--units", "b", "--nosuffix", str(dev)], check_rc=True
)
pv_size = int(size)
return pv_size
with self._pvs("noheadings nosuffix units fields devices") as ctx:
dummy, size, dummy = ctx.run(units="b", fields="pv_size", devices=[str(dev)])
return int(size.strip())
class Swap(Filesystem):

View File

@@ -45,18 +45,27 @@ options:
name:
description:
- The name of the flatpak to manage. To operate on several packages this can accept a list of packages.
- When used with O(state=present), O(name) can be specified as a URL to a C(flatpakref) file or the unique reverse DNS
name that identifies a flatpak.
- Both C(https://) and C(http://) URLs are supported.
- Should be specified as the unique reverse DNS name that identifies a flatpak (for example V(org.gnome.gedit)).
- When supplying a reverse DNS name, you can use the O(remote) option to specify on what remote to look for the flatpak.
An example for a reverse DNS name is C(org.gnome.gedit).
- When used with O(state=absent) or O(state=latest), it is recommended to specify the name in the reverse DNS format.
- When used with O(state=present), O(name) can also be specified as a C(https://) or C(http://) URL to a C(flatpakref) file.
However, it is recommended you use O(from_url) instead to get reliable idempotency.
Passing URLs in O(name) will be deprecated in the future.
- When used with O(state=absent) or O(state=latest), always specify the name in the reverse DNS format.
- When supplying a URL with O(state=absent) or O(state=latest), the module tries to match the installed flatpak based
on the name of the flatpakref to remove or update it. However, there is no guarantee that the names of the flatpakref
file and the reverse DNS name of the installed flatpak do match.
type: list
elements: str
required: true
from_url:
description:
- A C(http://) or C(https://) URL pointing to a C(.flatpakref) file to install from.
- When this option is set, O(name) must contain exactly one entry specifying the reverse DNS application ID of the
flatpak (for example V(com.onepassword.OnePassword)). This is used to check whether the flatpak is already installed.
- O(name) and O(from_url) cannot both contain URLs.
- This option is recommended instead of passing a URL in O(name); passing URLs in O(name) will be deprecated in the future.
type: str
version_added: "12.6.0"
no_dependencies:
description:
- If installing runtime dependencies should be omitted or not.
@@ -84,12 +93,14 @@ options:
EXAMPLES = r"""
- name: Install the spotify flatpak
community.general.flatpak:
name: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
name: com.spotify.Client
from_url: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
state: present
- name: Install the gedit flatpak package without dependencies (not recommended)
community.general.flatpak:
name: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
name: org.gnome.gedit
from_url: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
state: present
no_dependencies: true
@@ -120,12 +131,14 @@ EXAMPLES = r"""
- name: Update the spotify flatpak
community.general.flatpak:
name: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
name: com.spotify.Client
from_url: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
state: latest
- name: Update the gedit flatpak package without dependencies (not recommended)
community.general.flatpak:
name: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
name: org.gnome.gedit
from_url: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
state: latest
no_dependencies: true
@@ -180,7 +193,7 @@ from ansible_collections.community.general.plugins.module_utils.version import L
OUTDATED_FLATPAK_VERSION_ERROR_MESSAGE = "Unknown option --columns=application"
def install_flat(module, binary, remote, names, method, no_dependencies):
def install_flat(module, binary, remote, names, method, no_dependencies, from_url=None):
"""Add new flatpaks."""
global result # pylint: disable=global-variable-not-assigned
uri_names = []
@@ -198,12 +211,16 @@ def install_flat(module, binary, remote, names, method, no_dependencies):
base_command += ["--noninteractive"]
if no_dependencies:
base_command += ["--no-deps"]
if uri_names:
command = base_command + uri_names
_flatpak_command(module, module.check_mode, command)
if id_names:
command = base_command + [remote] + id_names
if from_url:
command = base_command + ["--from", from_url]
_flatpak_command(module, module.check_mode, command)
else:
if uri_names:
command = base_command + uri_names
_flatpak_command(module, module.check_mode, command)
if id_names:
command = base_command + [remote] + id_names
_flatpak_command(module, module.check_mode, command)
result["changed"] = True
@@ -221,7 +238,9 @@ def update_flat(module, binary, names, method, no_dependencies):
command += ["--no-deps"]
command += installed_flat_names
stdout = _flatpak_command(module, module.check_mode, command)
result["changed"] = True if module.check_mode else stdout.find("Nothing to do.") == -1
result["changed"] = (
True if module.check_mode else (stdout.find("Nothing to do.") == -1 and stdout.find("Nothing to update.") == -1)
)
def uninstall_flat(module, binary, names, method):
@@ -261,7 +280,7 @@ def _match_installed_flat_name(module, binary, name, method):
global result # pylint: disable=global-variable-not-assigned
parsed_name = _parse_flatpak_name(name)
# Try running flatpak list with columns feature
command = [binary, "list", f"--{method}", "--app", "--columns=application"]
command = [binary, "list", f"--{method}", "--columns=application"]
_flatpak_command(module, False, command, ignore_failure=True)
if result["rc"] != 0 and OUTDATED_FLATPAK_VERSION_ERROR_MESSAGE in result["stderr"]:
# Probably flatpak before 1.2
@@ -283,7 +302,7 @@ def _match_installed_flat_name(module, binary, name, method):
def _match_flat_using_outdated_flatpak_format(module, binary, parsed_name, method):
global result # pylint: disable=global-variable-not-assigned
command = [binary, "list", f"--{method}", "--app", "--columns=application"]
command = [binary, "list", f"--{method}", "--columns=application"]
output = _flatpak_command(module, False, command)
for row in output.split("\n"):
if parsed_name.lower() == row.lower():
@@ -292,7 +311,7 @@ def _match_flat_using_outdated_flatpak_format(module, binary, parsed_name, metho
def _match_flat_using_flatpak_column_feature(module, binary, parsed_name, method):
global result # pylint: disable=global-variable-not-assigned
command = [binary, "list", f"--{method}", "--app"]
command = [binary, "list", f"--{method}"]
output = _flatpak_command(module, False, command)
for row in output.split("\n"):
if parsed_name.lower() in row.lower():
@@ -356,6 +375,7 @@ def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type="list", elements="str", required=True),
from_url=dict(type="str"),
remote=dict(type="str", default="flathub"),
method=dict(type="str", default="system", choices=["user", "system"]),
state=dict(type="str", default="present", choices=["absent", "present", "latest"]),
@@ -366,6 +386,7 @@ def main():
)
name = module.params["name"]
from_url = module.params["from_url"]
state = module.params["state"]
remote = module.params["remote"]
no_dependencies = module.params["no_dependencies"]
@@ -380,6 +401,14 @@ def main():
if not binary:
module.fail_json(msg=f"Executable '{executable}' was not found on the system.", **result)
url_names = [n for n in name if n.startswith("http://") or n.startswith("https://")]
if from_url is not None:
if not (from_url.startswith("http://") or from_url.startswith("https://")):
module.fail_json(msg="The 'from_url' parameter must be an http:// or https:// URL.", **result)
if url_names:
module.fail_json(msg="The 'name' and 'from_url' parameters cannot both contain URLs.", **result)
if len(name) != 1:
module.fail_json(msg="When 'from_url' is used, 'name' must contain exactly one entry.", **result)
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
installed, not_installed = flatpak_exists(module, binary, name, method)
@@ -389,7 +418,7 @@ def main():
if state == "latest" and installed:
update_flat(module, binary, installed, method, no_dependencies)
if state in ("present", "latest") and not_installed:
install_flat(module, binary, remote, not_installed, method, no_dependencies)
install_flat(module, binary, remote, not_installed, method, no_dependencies, from_url)
module.exit_json(**result)

View File

@@ -199,6 +199,7 @@ def main():
# This module supports check mode
supports_check_mode=True,
)
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
name = module.params["name"]
flatpakrepo_url = module.params["flatpakrepo_url"]

View File

@@ -126,53 +126,86 @@ import re
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils import cmd_runner_fmt as fmt
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner
RE_VERSION = re.compile(r"^(\d+)\.(\d+)\.(\d+)")
RE_INSTALLED = re.compile(r"\S+\s+\((?:default: )?(.+)\)")
def get_rubygems_path(module):
if module.params["executable"]:
result = module.params["executable"].split(" ")
else:
result = [module.get_bin_path("gem", True)]
return result
return module.params["executable"].split()
return [module.get_bin_path("gem", True)]
def get_rubygems_version(module):
if hasattr(get_rubygems_version, "ver"):
return get_rubygems_version.ver
cmd = get_rubygems_path(module) + ["--version"]
(rc, out, err) = module.run_command(cmd, check_rc=True)
match = re.match(r"^(\d+)\.(\d+)\.(\d+)", out)
rc, out, err = module.run_command(cmd, check_rc=True)
match = RE_VERSION.match(out)
if not match:
return None
ver = tuple(int(x) for x in match.groups())
get_rubygems_version.ver = ver
return ver
return tuple(int(x) for x in match.groups())
def get_rubygems_environ(module):
def make_runner(module, ver):
command = get_rubygems_path(module)
environ_update = {}
if module.params["install_dir"]:
return {"GEM_HOME": module.params["install_dir"]}
return None
environ_update["GEM_HOME"] = module.params["install_dir"]
if ver and ver < (2, 0, 0):
include_dependencies_fmt = fmt.as_bool("--include-dependencies", "--ignore-dependencies")
include_doc_fmt = fmt.as_bool_not(["--no-rdoc", "--no-ri"])
else:
include_dependencies_fmt = fmt.as_bool_not("--ignore-dependencies")
include_doc_fmt = fmt.as_bool_not("--no-document")
norc_fmt = fmt.as_bool("--norc") if (ver and ver >= (2, 5, 2)) else fmt.as_bool([])
return CmdRunner(
module,
command=command,
environ_update=environ_update,
check_rc=True,
arg_formats=dict(
_list_subcmd=fmt.as_fixed("list"),
_install_subcmd=fmt.as_fixed("install"),
_uninstall_subcmd=fmt.as_fixed("uninstall"),
norc=norc_fmt,
_remote_flag=fmt.as_fixed("--remote"),
repository=fmt.as_opt_val("--source"),
_name_pattern=fmt.as_func(lambda v: [f"^{v}$"]),
version=fmt.as_opt_val("--version"),
include_dependencies=include_dependencies_fmt,
user_install=fmt.as_bool("--user-install", "--no-user-install"),
install_dir=fmt.as_opt_val("--install-dir"),
bindir=fmt.as_opt_val("--bindir"),
pre_release=fmt.as_bool("--pre"),
include_doc=include_doc_fmt,
env_shebang=fmt.as_bool("--env-shebang"),
gem_source=fmt.as_list(),
build_flags=fmt.as_opt_val("--"),
force=fmt.as_bool("--force"),
_uninstall_version=fmt.as_func(lambda v: ["--version", v] if v else ["--all"], ignore_none=False),
_executable_flag=fmt.as_fixed("--executable"),
name=fmt.as_list(),
),
)
def get_installed_versions(module, remote=False):
cmd = get_rubygems_path(module)
cmd.append("list")
cmd.extend(common_opts(module))
def get_installed_versions(runner, remote=False):
name = runner.module.params["name"]
if remote:
cmd.append("--remote")
if module.params["repository"]:
cmd.extend(["--source", module.params["repository"]])
cmd.append(f"^{module.params['name']}$")
environ = get_rubygems_environ(module)
(rc, out, err) = module.run_command(cmd, environ_update=environ, check_rc=True)
args_order = ["_list_subcmd", "norc", "_remote_flag", "repository", "_name_pattern"]
else:
args_order = ["_list_subcmd", "norc", "_name_pattern"]
with runner(args_order) as ctx:
rc, out, err = ctx.run(_name_pattern=name)
installed_versions = []
for line in out.splitlines():
match = re.match(r"\S+\s+\((?:default: )?(.+)\)", line)
match = RE_INSTALLED.match(line)
if match:
versions = match.group(1)
for version in versions.split(", "):
@@ -180,95 +213,52 @@ def get_installed_versions(module, remote=False):
return installed_versions
def exists(module):
def exists(runner):
module = runner.module
if module.params["state"] == "latest":
remoteversions = get_installed_versions(module, remote=True)
remoteversions = get_installed_versions(runner, remote=True)
if remoteversions:
module.params["version"] = remoteversions[0]
installed_versions = get_installed_versions(module)
installed_versions = get_installed_versions(runner)
if module.params["version"]:
if module.params["version"] in installed_versions:
return True
else:
if installed_versions:
return True
return False
return module.params["version"] in installed_versions
return bool(installed_versions)
def common_opts(module):
opts = []
ver = get_rubygems_version(module)
if module.params["norc"] and ver and ver >= (2, 5, 2):
opts.append("--norc")
return opts
def install(runner):
args_order = [
"_install_subcmd",
"norc",
"version",
"repository",
"include_dependencies",
"user_install",
"install_dir",
"bindir",
"pre_release",
"include_doc",
"env_shebang",
"gem_source",
"build_flags",
"force",
]
with runner(args_order, check_mode_skip=True) as ctx:
ctx.run()
def uninstall(module):
if module.check_mode:
return
cmd = get_rubygems_path(module)
environ = get_rubygems_environ(module)
cmd.append("uninstall")
cmd.extend(common_opts(module))
if module.params["install_dir"]:
cmd.extend(["--install-dir", module.params["install_dir"]])
if module.params["bindir"]:
cmd.extend(["--bindir", module.params["bindir"]])
if module.params["version"]:
cmd.extend(["--version", module.params["version"]])
else:
cmd.append("--all")
cmd.append("--executable")
if module.params["force"]:
cmd.append("--force")
cmd.append(module.params["name"])
return module.run_command(cmd, environ_update=environ, check_rc=True)
def install(module):
if module.check_mode:
return
ver = get_rubygems_version(module)
cmd = get_rubygems_path(module)
cmd.append("install")
cmd.extend(common_opts(module))
if module.params["version"]:
cmd.extend(["--version", module.params["version"]])
if module.params["repository"]:
cmd.extend(["--source", module.params["repository"]])
if not module.params["include_dependencies"]:
cmd.append("--ignore-dependencies")
else:
if ver and ver < (2, 0, 0):
cmd.append("--include-dependencies")
if module.params["user_install"]:
cmd.append("--user-install")
else:
cmd.append("--no-user-install")
if module.params["install_dir"]:
cmd.extend(["--install-dir", module.params["install_dir"]])
if module.params["bindir"]:
cmd.extend(["--bindir", module.params["bindir"]])
if module.params["pre_release"]:
cmd.append("--pre")
if not module.params["include_doc"]:
if ver and ver < (2, 0, 0):
cmd.append("--no-rdoc")
cmd.append("--no-ri")
else:
cmd.append("--no-document")
if module.params["env_shebang"]:
cmd.append("--env-shebang")
cmd.append(module.params["gem_source"])
if module.params["build_flags"]:
cmd.extend(["--", module.params["build_flags"]])
if module.params["force"]:
cmd.append("--force")
module.run_command(cmd, check_rc=True)
def uninstall(runner):
args_order = [
"_uninstall_subcmd",
"norc",
"install_dir",
"bindir",
"_uninstall_version",
"_executable_flag",
"force",
"name",
]
with runner(args_order, check_mode_skip=True) as ctx:
return ctx.run(_uninstall_version=runner.module.params["version"])
def main():
@@ -305,16 +295,19 @@ def main():
if not module.params["gem_source"]:
module.params["gem_source"] = module.params["name"]
ver = get_rubygems_version(module)
runner = make_runner(module, ver)
changed = False
if module.params["state"] in ["present", "latest"]:
if not exists(module):
install(module)
if not exists(runner):
install(runner)
changed = True
elif module.params["state"] == "absent":
if exists(module):
command_output = uninstall(module)
if command_output is not None and exists(module):
if exists(runner):
command_output = uninstall(runner)
if command_output is not None and exists(runner):
rc, out, err = command_output
module.fail_json(
msg=(

View File

@@ -163,7 +163,7 @@ def main():
params = module.params
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
# Set the locale to C to ensure consistent messages.
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
name = params["name"] or ""
unset = params["state"] == "absent"

View File

@@ -122,7 +122,7 @@ def main():
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
# Set the locale to C to ensure consistent messages.
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
name = module.params["name"]
path = module.params["path"]

View File

@@ -0,0 +1,401 @@
#!/usr/bin/python
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
module: github_secrets
short_description: Manage GitHub repository or organization secrets
description:
- Create, update, or delete secrets in a GitHub repository or organization.
author:
- Thomas Sjögren (@konstruktoid)
version_added: '12.5.0'
requirements:
- pynacl
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: full
diff_mode:
support: none
options:
organization:
description:
- The GitHub username or organization name.
type: str
required: true
aliases: ["org", "username"]
repository:
description:
- The name of the repository.
- If not provided, the secret will be managed at the organization level.
type: str
aliases: ["repo"]
key:
description:
- The name of the secret.
type: str
value:
description:
- The value of the secret. Required when O(state=present).
type: str
visibility:
description:
- The visibility of the secret when set at the organization level.
- Required when O(state=present) and O(repository) is not set.
type: str
choices: ["all", "private", "selected"]
state:
description:
- The desired state of the secret.
type: str
choices: ["present", "absent"]
default: "present"
api_url:
description:
- The base URL for the GitHub API.
type: str
default: "https://api.github.com"
token:
description:
- The GitHub token used for authentication.
type: str
required: true
"""
EXAMPLES = r"""
- name: Add Github secret
community.general.github_secrets:
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
repository: "ansible"
organization: "ansible"
key: "TEST_SECRET"
value: "bob"
state: "present"
- name: Delete Github secret
community.general.github_secrets:
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
repository: "ansible"
organization: "ansible"
key: "TEST_SECRET"
state: "absent"
"""
RETURN = r"""
result:
description: The result of the module.
type: dict
returned: always
sample: {
"msg": "OK (2 bytes)",
"response": "Secret created",
"status": 201
}
"""
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible_collections.community.general.plugins.module_utils import deps
with deps.declare(
"pynacl",
reason="pynacl is a required dependency",
url="https://pypi.org/project/PyNaCl/",
):
from nacl import encoding, public
def get_public_key(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
) -> tuple[str, str]:
"""Retrieve the GitHub Actions public key used to encrypt secrets."""
if repository:
url = f"{api_url}/repos/{organization}/{repository}/actions/secrets/public-key"
else:
url = f"{api_url}/orgs/{organization}/actions/secrets/public-key"
resp, info = fetch_url(module, url, headers=headers)
if info["status"] != HTTPStatus.OK:
module.fail_json(msg=f"Failed to get public key: {info}")
data = json.loads(resp.read())
return data["key_id"], data["key"]
def encrypt_secret(public_key: str, secret_value: str) -> str:
"""Encrypt a secret value using GitHub's public key."""
key = public.PublicKey(
public_key.encode("utf-8"),
encoding.Base64Encoder(), # type: ignore [arg-type]
)
sealed_box = public.SealedBox(key)
encrypted = sealed_box.encrypt(secret_value.encode("utf-8"))
return encoding.Base64Encoder.encode(encrypted).decode("utf-8")
def check_secret(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
key: str,
) -> dict[str, int]:
url = (
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
if repository
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
)
resp, info = fetch_url(module, url, headers=headers)
if info["status"] in (HTTPStatus.OK, HTTPStatus.NOT_FOUND):
return {"status": info["status"]}
else:
module.fail_json(msg=f"Failed to check secret: {info}")
def upsert_secret(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
key: str,
encrypted_value: str,
key_id: str,
) -> dict[str, t.Any]:
"""Create or update a GitHub Actions secret."""
url = (
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
if repository
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
)
payload = {
"encrypted_value": encrypted_value,
"key_id": key_id,
}
if not repository and module.params.get("visibility"):
payload["visibility"] = module.params["visibility"]
if module.check_mode:
secret_present = check_secret(module, api_url, headers, organization, repository, key)
if secret_present["status"] == HTTPStatus.NOT_FOUND:
check_mode_msg = "OK (2 bytes)"
check_mode_status = HTTPStatus.CREATED.value
info = {
"msg": check_mode_msg,
"status": check_mode_status,
}
else:
check_mode_msg = "OK (unknown bytes)"
check_mode_status = HTTPStatus.NO_CONTENT
info = {
"msg": check_mode_msg,
"status": check_mode_status,
}
else:
resp, info = fetch_url(
module,
url,
headers=headers,
data=json.dumps(payload).encode("utf-8"),
method="PUT",
)
if info["status"] not in (HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
module.fail_json(msg=f"Failed to upsert secret: {info}")
return info
def delete_secret(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
key: str,
) -> dict[str, t.Any]:
"""Delete a GitHub Actions secret."""
url = (
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
if repository
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
)
if module.check_mode:
secret_present = check_secret(module, api_url, headers, organization, repository, key)
info = {
"msg": (
"HTTP Error 404: Not Found"
if secret_present["status"] == HTTPStatus.NOT_FOUND
else "OK (unknown bytes)"
),
"status": (
HTTPStatus.NO_CONTENT if secret_present["status"] == HTTPStatus.OK else secret_present["status"]
),
}
else:
resp, info = fetch_url(
module,
url,
headers=headers,
method="DELETE",
)
if info["status"] not in (HTTPStatus.NO_CONTENT, HTTPStatus.NOT_FOUND):
module.fail_json(msg=f"Failed to delete secret: {info}")
return info
def main() -> None:
"""Ansible module entry point."""
argument_spec = {
"organization": {
"type": "str",
"aliases": ["org", "username"],
"required": True,
},
"repository": {"type": "str", "aliases": ["repo"]},
"key": {"type": "str", "no_log": False},
"value": {"type": "str", "no_log": True},
"visibility": {"type": "str", "choices": ["all", "private", "selected"]},
"state": {
"type": "str",
"choices": ["present", "absent"],
"default": "present",
},
"api_url": {"type": "str", "default": "https://api.github.com"},
"token": {"type": "str", "required": True, "no_log": True},
}
module = AnsibleModule(
argument_spec=argument_spec,
required_if=[("state", "present", ["value"])],
required_by={"value": "key"},
supports_check_mode=True,
)
deps.validate(module)
organization: str = module.params["organization"]
repository: str = module.params["repository"]
key: str = module.params["key"]
value: str = module.params["value"]
visibility: str = module.params.get("visibility")
state: str = module.params["state"]
api_url: str = module.params["api_url"]
token: str = module.params["token"]
if state == "present" and value is None:
module.fail_json(
msg="Invalid parameters",
details="The 'value' parameter cannot be empty",
params=module.params,
)
if state == "present" and not repository and not visibility:
module.fail_json(
msg="Invalid parameters",
details="When 'state' is 'present' and 'repository' is not set, 'visibility' must be provided",
params=module.params,
)
result: dict[str, t.Any] = {}
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
if state == "present":
key_id, public_key = get_public_key(
module,
api_url,
headers,
organization,
repository,
)
encrypted_value = encrypt_secret(public_key, value)
upsert = upsert_secret(
module,
api_url,
headers,
organization,
repository,
key,
encrypted_value,
key_id,
)
response_msg = "Secret created" if upsert["status"] == HTTPStatus.CREATED else "Secret updated"
result["changed"] = True
result.update(
result={
"status": upsert["status"],
"msg": upsert.get("msg"),
"response": response_msg,
},
)
if state == "absent":
delete = delete_secret(
module,
api_url,
headers,
organization,
repository,
key,
)
if delete["status"] == HTTPStatus.NO_CONTENT:
result["changed"] = True
result.update(
result={
"status": delete["status"],
"msg": delete.get("msg"),
"response": "Secret deleted",
},
)
if delete["status"] == HTTPStatus.NOT_FOUND:
result["changed"] = False
result.update(
result={
"status": delete["status"],
"msg": delete.get("msg"),
"response": "Secret not found",
},
)
module.exit_json(**result)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,158 @@
#!/usr/bin/python
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
module: github_secrets_info
short_description: List GitHub repository or organization secrets
description:
- List secrets in a GitHub repository or organization.
author:
- Thomas Sjögren (@konstruktoid)
version_added: '12.5.0'
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
options:
organization:
description:
- The GitHub username or organization name.
type: str
required: true
aliases: ["org", "username"]
repository:
description:
- The name of the repository.
- If not provided, the listing will be at organization level.
type: str
aliases: ["repo"]
api_url:
description:
- The base URL for the GitHub API.
type: str
default: "https://api.github.com"
token:
description:
- The GitHub token used for authentication.
type: str
required: true
"""
EXAMPLES = r"""
- name: List Github secret
community.general.github_secrets_info:
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
repository: "ansible"
organization: "ansible"
"""
RETURN = r"""
secrets:
description: The list of currently existing secrets.
type: list
elements: dict
returned: success
sample: [
{
"created_at": "2026-01-11T23:19:00Z",
"name": "ANSIBLE",
"updated_at": "2026-02-15T22:18:16Z"
},
]
contains:
name:
description: The name of the secret.
type: str
created_at:
description: The date and time when the secret was created.
type: str
updated_at:
description: The date and time when the secret was last updated.
type: str
"""
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible_collections.community.general.plugins.module_utils import deps
def list_secrets(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
) -> dict[str, list]:
url = (
f"{api_url}/repos/{organization}/{repository}/actions/secrets"
if repository
else f"{api_url}/orgs/{organization}/actions/secrets"
)
resp, info = fetch_url(module, url, headers=headers, method="GET")
if info["status"] == HTTPStatus.OK:
body = resp.read()
return {"secrets": json.loads(body).get("secrets", [])}
elif info["status"] == HTTPStatus.NOT_FOUND:
return {
"secrets": [],
}
else:
module.fail_json(msg=f"Failed to list secrets: {info}")
def main() -> None:
"""Ansible module entry point."""
argument_spec = {
"organization": {
"type": "str",
"aliases": ["org", "username"],
"required": True,
},
"repository": {"type": "str", "aliases": ["repo"]},
"api_url": {"type": "str", "default": "https://api.github.com"},
"token": {"type": "str", "required": True, "no_log": True},
}
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
deps.validate(module)
organization: str = module.params["organization"]
repository: str = module.params["repository"]
api_url: str = module.params["api_url"]
token: str = module.params["token"]
result: dict[str, t.Any] = {}
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
secrets = list_secrets(module, api_url, headers, organization, repository)
result["changed"] = False
result.update(
secrets=secrets["secrets"],
)
module.exit_json(**result)
if __name__ == "__main__":
main()

View File

@@ -179,8 +179,15 @@ class GitLabProjectMembers:
return project_exists.id
except gitlab.exceptions.GitlabGetError:
project_exists = self._gitlab.projects.list(search=project_name, all=False)
if project_exists:
if len(project_exists) == 1:
return project_exists[0].id
if len(project_exists) > 1:
self._module.fail_json(
msg=(
f"More than one project matches '{project_name}'. "
"Use the full path ('group/project') to disambiguate."
)
)
def get_user_id(self, gitlab_user):
user_exists = self._gitlab.users.list(username=gitlab_user, all=False)

View File

@@ -240,6 +240,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.gitlab import (
auth_argument_spec,
filter_returned_variables,
find_project,
gitlab_authentication,
list_all_kwargs,
vars_to_variables,
@@ -249,11 +250,14 @@ from ansible_collections.community.general.plugins.module_utils.gitlab import (
class GitlabProjectVariables:
def __init__(self, module, gitlab_instance):
self.repo = gitlab_instance
self.project = self.get_project(module.params["project"])
self._module = module
self.project = self.get_project(module.params["project"])
def get_project(self, project_name):
return self.repo.projects.get(project_name)
project = find_project(self.repo, project_name)
if project is None:
self._module.fail_json(msg=f"Project {project_name} not found or insufficient permissions.")
return project
def list_all_project_variables(self):
return list(self.project.variables.list(**list_all_kwargs))

Some files were not shown because too many files have changed in this diff Show More