Compare commits

...

135 Commits

Author SHA1 Message Date
Felix Fontein
68c3c9b7ba Release 10.6.0. 2025-04-21 21:09:23 +02:00
patchback[bot]
7bb291864e [PR #9898/6e384a1c backport][stable-10] Add support for addressing subgroups by paths to the keycloak_user module (#10049)
Add support for addressing subgroups by paths to the keycloak_user module (#9898)

* Add support for addressing subgroups by paths to the keycloak_user module (issue #9647)

* Apply suggestions from code review.

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 6e384a1c6a)

Co-authored-by: Christian Schlichtherle <christian@schlichtherle.de>
2025-04-21 16:52:30 +02:00
patchback[bot]
0090af8cfb [PR #10043/2a5abab7 backport][stable-10] Remove blanket skips for Python 3 in CI (#10048)
Remove blanket skips for Python 3 in CI (#10043)

* Remove blanket skips for Python 3 in CI.

* Try to fix hg tests.

* Disable hg tests.

* Drop restriction of supervisor to <4.0.0.

This was introduced in https://github.com/ansible/ansible/pull/54935.

* Make tests work with supervisorctl 4.0.0.

According to https://supervisord.org/changes.html#id12,
"supervisorctl will now set its exit code to a non-zero value when an error condition occurs."
I'm not sure why a stopped service in 'status' constitutes an error condition,
but whatever 🤷...

* Use correct Python executable.

* Skip RHEL/macOS; diff on config write.

* Skip CentOS 7 and OpenSuSE on ansible-core 2.16.

(cherry picked from commit 2a5abab738)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-04-21 16:34:52 +02:00
patchback[bot]
42aeeb975b [PR #10029/73178e3d backport][stable-10] fixed hidden warnings from extra tests - batch 3 (#10045)
fixed hidden warnings from extra tests - batch 3 (#10029)

* fixed hidden warnings from extra tests - batch 3

* add empty lines to separate sections of the EXAMPLE block

* Apply suggestions from code review

* Update plugins/modules/nmcli.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 73178e3d33)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-04-21 13:53:51 +00:00
Felix Fontein
9dd7be05dc [stable-10] Use antsibull-nox instead of extra sanity test runner and extra workfows (#10042)
Use antsibull-nox instead of extra sanity test runner and extra workflows (#10022)

* Use antsibull-nox instead of extra sanity test runner and extra workflows.

* Avoid sys.argv[0].

(cherry picked from commit 3ee55c6828)
2025-04-21 14:21:00 +02:00
patchback[bot]
11a847a7b5 [PR #10024/ce421dbd backport][stable-10] Allowing uppercase tags in proxmox & proxmox_kvm (#10039)
Allowing uppercase tags in proxmox & proxmox_kvm (#10024)

* Allowing uppercase tags in proxmox & proxmox_kvm

* Fix #9895 : fixes the 'not a valid tag' error message when the VM or container tag contains uppercase characters

* Add PR URL to changelog fragment.

---------

Co-authored-by: s1githug <sgithug@free.fr>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit ce421dbd7d)

Co-authored-by: s1github <sgithub@free.fr>
2025-04-21 13:21:21 +02:00
patchback[bot]
ebcceafdb7 [PR #10028/e9997e08 backport][stable-10] deprecation: manifold (#10038)
deprecation: manifold (#10028)

* deprecation: manifold

* add changelog frag

* restore test file

(cherry picked from commit e9997e08ed)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-04-21 13:21:10 +02:00
patchback[bot]
79b3521547 [PR #10011/c2480730 backport][stable-10] fix: github_deploy_key check key exists on 422 (#10036)
fix: github_deploy_key check key exists on 422 (#10011)

* fix: github_deploy_key check key exists on 422

If we get a 422 response code as we add a key, check if it's because the key already exists or for another reason.

fixes: #6718

* chore: add changelog 10011-github_deploy_key-check-key-present

* chore: fix changelog fragment

* chore: fix changelog fragment

* Update changelog fragment.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c248073079)

Co-authored-by: Alex Garel <alex@garel.org>
2025-04-21 13:21:02 +02:00
patchback[bot]
7aae8a94f2 [PR #10005/e0a283bb backport][stable-10] Fix method exists in sysrc (#10034)
Fix method exists in sysrc (#10005)

* Fix method exists.

* Add changelog fragment.

* Update the exists method to pass the present method tests.

* Replace f-string formatting.

* Update changelogs/fragments/10005-fix-method-exists-in-sysrc.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Add comment to the method exists.

* Update plugins/modules/sysrc.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update changelogs/fragments/10005-fix-method-exists-in-sysrc.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* The improved comment formatting fixed.

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit e0a283bb36)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2025-04-21 13:20:53 +02:00
patchback[bot]
acde075b5f [PR #10026/63cb8f0a backport][stable-10] deprecation: stackpath_compute (#10037)
deprecation: stackpath_compute (#10026)

* deprecation: stackpath_compute

* add changelog frag

* restore test file

(cherry picked from commit 63cb8f0ace)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-04-21 13:20:40 +02:00
patchback[bot]
0310c7875d [PR #10013/4b9373f6 backport][stable-10] Homebrew: Emit a useful error message if brew info reports a package tap is null. (#10040)
Homebrew: Emit a useful error message if brew info reports a package tap is null. (#10013)

* Fix #10012.

Homebrew: Emit a useful error message if a package tap is null.  This can happen if an installed package is subsequently removed from the tap (e.g. it is withdrawn by homebrew).

* Added changelogs fragment for PR 10013

* Do not raise error when tap is null in package_detail
pylint: remove trailing whitespace

* Minor: Update plugins/modules/homebrew.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Minor: Update changelogs/fragments/10012-improve-error-handling-homebrew-missing-tap.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update plugins/modules/homebrew.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 4b9373f694)

Co-authored-by: brad2014 <brad2014@users.noreply.github.com>
2025-04-21 13:20:30 +02:00
patchback[bot]
8bce7601bc [PR #10014/89105559 backport][stable-10] puppet: use better CmdRunner param formatting (#10021)
puppet: use better CmdRunner param formatting (#10014)

* puppet: use better CmdRunner param formatting

* ignore none

* add changelog frag

(cherry picked from commit 8910555983)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-04-19 09:34:26 +02:00
patchback[bot]
ab5c4b186b [PR #9959/5ef6f1eb backport][stable-10] Update one_vm.py (#10020)
Update one_vm.py (#9959)

* Update one_vm.py

Update updateconf attributes to match latest acceptable values.

* Add changelog fragment

* Update plugins/modules/one_vm.py

Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com>

* Update plugins/modules/one_vm.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/9959-update-opennebula-onevm-updateconf-params.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update one_vm.py

Add updateconf values to documentation

* Update one_vm.py

* Update one_vm.py

* Update one_vm.py

* Update one_vm.py

Fix doc formatting

* Update plugins/modules/one_vm.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update one_vm.py

Colon causing test failure

* Add colon.

---------

Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 5ef6f1ebd2)

Co-authored-by: Tom Paine <github@aioue.net>
2025-04-19 09:34:18 +02:00
patchback[bot]
ee2779e6c1 [PR #9795/96b49300 backport][stable-10] add the wsl connection plugin (#10019)
add the wsl connection plugin (#9795)

* add the wsl connection plugin

* move the banner_timeout required paramiko version to its own line

* document the proxy_command required paramiko version

* document the timeout required paramiko version

* simplify the sending of the become_pass value

* add Connection.__init__ type hints

* add MyAddPolicy.missing_host_key type hints

* normalize the Connection._parse_proxy_command replacers dict values to the str type

* add the user_known_hosts_file option

* modify the private_key_file option type to path

(cherry picked from commit 96b493002c)

Co-authored-by: Rui Lopes <rgl@ruilopes.com>
2025-04-19 09:34:11 +02:00
patchback[bot]
91ac9f84b8 [PR #9973/80252b29 backport][stable-10] Add zypper skip post errors feature (#10016)
Add zypper skip post errors feature (#9973)

* Add zypper skip post errors feature

* Add feature to handle zypper return code 107 with skip_post_errors (default: false).
* Add integration test to verify the skip_post_errors flag.
* Add changelog fragment

Issue: #9972
Issue-Ref: https://github.com/ansible-collections/community.general/issues/9972

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/zypper.py

* Update changelogs/fragments/9972-zypper-skip-post-errors.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update tests/integration/targets/zypper/tasks/zypper.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 80252b29f8)

Co-authored-by: mk2km <205020320+mk2km@users.noreply.github.com>
2025-04-19 09:34:06 +02:00
patchback[bot]
1c1d58482c [PR #9987/a8b97732 backport][stable-10] Fix Keycloak authentication flow configuration issues (#10018)
Fix Keycloak authentication flow configuration issues (#9987)

* Add delete_authentication_config method and integrate it into create_or_update_executions

* typo

* Sanity

* Add integration tests for keycloak_authentication module with README, tasks, and variables

* Add copyright and license information to access_token.yml

* Sanity

* Refactor Keycloak integration tests: streamline README, update access token task, and enhance variable management

* Maj changelogs fragments

---------

Co-authored-by: Andre Desrosiers <andre.desrosiers@ssss.gouv.qc.ca>
(cherry picked from commit a8b977320c)

Co-authored-by: desand01 <desrosiers.a@hotmail.com>
2025-04-19 09:33:56 +02:00
patchback[bot]
138740127a [PR #9970/42a161ab backport][stable-10] param pkcs12_alias and cert_alias to be optional in java_cert module (#10001)
param pkcs12_alias and cert_alias to be optional in java_cert module  (#9970)

* changed pkcs12_alias and cert_alias to be optional when importing pkcs12 certificate in keystore

* Add changelog fragment

* Update changelogs/fragments/9970-pkcs12_alias_cert_alias_optional.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/9970-pkcs12_alias_cert_alias_optional.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 42a161abf5)

Co-authored-by: Emanuele Bernardi <e.berna@gmail.com>
2025-04-16 21:14:31 +02:00
patchback[bot]
1d7aad9b46 [PR #9952/1243846c backport][stable-10] improve ansible_host in proxmox inventory plugin (#10003)
improve ansible_host in proxmox inventory plugin (#9952)

* improve ansible_host in proxmox inventory plugin

I had this issue myself and found out there was already an issue thread:

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

this fixes the issue for hope we can all benefit after this gets merged

* f string styling

* add log line for the successful address selection

* remove white space

* add changelog: 9952-proxmox-inventory-plugin-improve-ansible_host.yml

* Update changelogs/fragments/9952-proxmox-inventory-plugin-improve-ansible_host.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1243846c3a)

Co-authored-by: Stein van Broekhoven <stein@aapjeisbaas.nl>
2025-04-16 21:06:04 +02:00
patchback[bot]
f3a12a9e78 [PR #9999/216e7dc0 backport][stable-10] Fix typo in rpm_ostree_pkg documentation example (#10000)
Fix typo in rpm_ostree_pkg documentation example (#9999)

Fix typo in rpm_ostree_pkg examples

The example showing use of a delay to improve resiliency misspelled 'delay'

(cherry picked from commit 216e7dc06b)

Co-authored-by: Jeffrey Borcean <jjborcean@gmail.com>
2025-04-15 20:43:43 +02:00
patchback[bot]
0e818c4812 [PR #9976/04137746 backport][stable-10] keycloak_client: fix idempotency regression (#9997)
keycloak_client: fix idempotency regression (#9976)

* add function to normalize kc responses

* add changelog fragment

* Update changelogs/fragments/9976-keycloak_client-fix-idempotency-regression.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* add newline to changelog fragment

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 0413774641)

Co-authored-by: gruenbauer@b1-systems.de <gruenbauer@b1-systems.de>
2025-04-14 22:51:23 +02:00
patchback[bot]
8751f0feea [PR #9960/ab6e18b6 backport][stable-10] gitlab_project: add build_timeout option (#9995)
gitlab_project: add `build_timeout` option (#9960)

* gitlab_project: add `build_timeout` option

* gitlab_project: document unspecified build_timeout on creation

(cherry picked from commit ab6e18b6cf)

Co-authored-by: David Phillips <phillid@users.noreply.github.com>
2025-04-14 22:51:12 +02:00
patchback[bot]
5dd4cc5148 [PR #9962/a7ab7e92 backport][stable-10] Feat: Add infiniband mac address support in nmcli module (#9998)
Feat: Add infiniband mac address support in nmcli module (#9962)

* Feat: Add infiniband mac address support in nmcli module

* Add changelog fragment

* Tentative to fix the error

* Update changelogs/fragments/9962-nmcli-add-infiniband-mac-support.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/nmcli.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Fix: fix test_bond_connection_unchanged module check

* Update plugins/modules/nmcli.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update changelogs/fragments/9962-nmcli-add-infiniband-mac-support.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit a7ab7e9247)

Co-authored-by: Benoît Leveugle <oxedions@gmail.com>
2025-04-14 22:51:01 +02:00
Felix Fontein
39f27d7d43 Prepare 10.6.0. 2025-04-14 22:11:48 +02:00
patchback[bot]
4dec46778c [PR #9992/8525e420 backport][stable-10] Avoid deprecated AnsibleFilterTypeError (#9994)
Avoid deprecated AnsibleFilterTypeError (#9992)

Avoid deprecated AnsibleFilterTypeError.

(cherry picked from commit 8525e420bc)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-04-14 21:23:21 +02:00
patchback[bot]
d5e0d36e48 [PR #9833/04cfce78 backport][stable-10] Make ready for data tagging (#9990)
Make ready for data tagging (#9833)

* Fix dependent lookup.

* Fix ansible_type plugin utils and adjust documentation of reveal_ansible_type filter and ansible_type test.

* Fix diy callback plugin.

* Adjust to Data Tagging.

* Vendor and use internal code from ansible-core to fix YAML callback.

Ref: https://github.com/ansible/ansible/issues/84781
(cherry picked from commit 04cfce78ea)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-04-14 21:23:00 +02:00
patchback[bot]
fb45b908dd [PR #9951/02ffb6e7 backport][stable-10] update PHP apache module workaround (#9979)
update PHP apache module workaround (#9951)

* update php apache module workaround

* Update apache2_module.py

* Update apache2_module.py

* Update apache2_module.py

* add changelog fragment

* Update changelogs/fragments/9951-mod-php-identifier.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update 9951-mod-php-identifier.yml

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 02ffb6e7e3)

Co-authored-by: simonLeary42 <71396965+simonLeary42@users.noreply.github.com>
2025-04-10 07:27:14 +02:00
patchback[bot]
6e16c6c649 [PR #9953/1157b710 backport][stable-10] allow gitlab-project-members module to handle user level "owner" (#9980)
allow gitlab-project-members module to handle user level "owner" (#9953)

* fix(modules/gitlab-project-members): fix ...

... module not being able to handle owner access level

* add changelog fragment for this pr

* fix and extend integration tests

* extend parameter docu as requested by review

* also add docu for other parameters

* remove pip install break-packages flag from ...

... integration tests

---------

Co-authored-by: Mirko Wilhelmi <Mirko.Wilhelmi@sma.de>
(cherry picked from commit 1157b7102f)

Co-authored-by: morco <thegreatwiper@web.de>
2025-04-10 07:27:06 +02:00
patchback[bot]
033d5f23f8 [PR #9646/d7edd34b backport][stable-10] hpilo_boot: fix module failing when trying to power on an already powered-on server (#9981)
hpilo_boot: fix module failing when trying to power on an already powered-on server (#9646)

* fix: fix hpilo_boot.py module failing when trying to power on an already powered-on server

For this module to be idempotent, it should be successful when trying to reach a power state which is already there.

It was already the case for "poweroff", however when running the module with "boot_once" state, it was failing if the server was already powered_on, which is not an idempotent behavior

* doc: Add changelog fragment

* fix: add flag to run boot_once idempotently without breaking the previous behavior and add deprecation warning

* doc: fix documentation fragment description

* fix unwanted format changes

seems like I had an older version of this module formatted differently or that I had a formatter that automatically ran on this file

* fix linting errors

Removed trailing whitespace line 164

* add missing dash in idempotent_boot_once parameter description

* fix doc issue

* Update changelogs/fragments/9646-hpilo-fix-idempotency.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update plugins/modules/hpilo_boot.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update changelogs/fragments/9646-hpilo-fix-idempotency.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* comment out module deprecation and change idempotent boot_once parameter description

* Update plugins/modules/hpilo_boot.py

* Update plugins/modules/hpilo_boot.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Ryan BADAÏ <ryan.badai@dbi-services.com>
(cherry picked from commit d7edd34ba4)

Co-authored-by: Ryan Badaï <43403063+ryanb74@users.noreply.github.com>
2025-04-10 07:26:57 +02:00
patchback[bot]
6367bb853d [PR #9964/1375cb65 backport][stable-10] Unify TLS/SSL config for Redfish modules with new common argument spec and docs fragment; add validate_certs and ca_path options (#9982)
Unify TLS/SSL config for Redfish modules with new common argument spec and docs fragment; add validate_certs and ca_path options (#9964)

Unify TLS/SSL config for Redfish modules with new common argument spec and docs fragment.

(cherry picked from commit 1375cb65d6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-04-10 07:26:48 +02:00
patchback[bot]
8e6941ed5d [PR #9965/d923e326 backport][stable-10] fix duplicate json conversion for rocketchat pre740 (#9969)
fix duplicate json conversion for rocketchat pre740 (#9965)

* fix duplicate json conversion for rocketchat pre740

* add changelog

* Update changelogs/fragments/9965-fix-duplicate-jsonify-payload-for-rocketchat-pre740.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit d923e326f6)

Co-authored-by: pandrieux <31440210+pandrieux@users.noreply.github.com>
2025-04-06 14:43:41 +02:00
patchback[bot]
2d730da8a7 [PR #9963/34b6fb74 backport][stable-10] proxmox_disk: fail gracefully if storage hasn't been provided by the user (#9968)
proxmox_disk: fail gracefully if storage hasn't been provided by the user (#9963)

Fail gracefully if storage hasn't been provided by the user.

(cherry picked from commit 34b6fb74eb)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-04-06 14:24:07 +02:00
Felix Fontein
88f5100657 Migrate .reuse/dep5 to REUSE.toml.
(cherry picked from commit 70b5e362f9)
2025-03-29 13:46:13 +01:00
patchback[bot]
0293f84b3e [PR #9945/e5e33534 backport][stable-10] Simplify YAML callback tests (#9948)
Simplify YAML callback tests (#9945)

Simplify YAML callback tests.

(cherry picked from commit e5e335348a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-29 11:02:00 +01:00
Felix Fontein
8333c881d3 Next expected release will be 10.6.0. 2025-03-24 22:28:48 +01:00
Felix Fontein
4a394088b3 Release 10.5.0. 2025-03-24 21:03:09 +01:00
patchback[bot]
d72d9b3e45 [PR #9910/1fbf5d8e backport][stable-10] proxmox_vm_info: don't expect key 'template' exists in dictionary (#9935)
proxmox_vm_info: don't expect key 'template' exists in dictionary (#9910)

* don't expect key 'template' exists

* add changelog fragment

* Update changelogs/fragments/9875-proxmox-dont-expect-key-template-to-exist.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1fbf5d8eb4)

Co-authored-by: florianfischer91 <72799603+florianfischer91@users.noreply.github.com>
2025-03-24 18:10:09 +01:00
patchback[bot]
e44bbbdcba [PR #9882/c3b0354d backport][stable-10] Fix payload to match Rocket Chat 7.4.1 API (#9933)
Fix payload to match Rocket Chat 7.4.1 API (#9882)

* Fix payload to match Rocket Chat 7.4 API

* Add a fallback to send payload argument in case the user still interacts with a Rocket Chat version < 7.4.0

* Fix sanity checks

* Add changelog fragment of PR #9882

* Add argument option_is_pre740 to keep backward compatibility of the payload

* Add new argument doc

* Rename new parameter, add missing pieces of information in parameter doc

* Use appropriate change label and fix change description. Description about future plans for the parameter is now set at the parameter doc level

* Fix missing punctuation in the new parameter doc block

* Improve documentation.

* Fix line length.

---------

Co-authored-by: ludovic <ludovic.petetin@aleph-networks.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c3b0354da0)

Co-authored-by: X <2465124+broferek@users.noreply.github.com>
2025-03-24 05:52:10 +01:00
patchback[bot]
eca7c1a00b [PR #9926/cb776e7c backport][stable-10] The yarn module is Yarn Classic only at the moment (#9927)
The yarn module is Yarn Classic only at the moment (#9926)

The yarn module is Yarn Classic only.

(cherry picked from commit cb776e7cd5)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-23 14:59:00 +01:00
patchback[bot]
b1ff713c41 [PR #9867/ec38a82e backport][stable-10] tests: enable copr tests (#9931)
tests: enable copr tests (#9867)

[WIP] tests: enable copr tests

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>
(cherry picked from commit ec38a82ef1)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2025-03-23 14:58:51 +01:00
patchback[bot]
c95a8b6540 [PR #9921/410cf72a backport][stable-10] Unit tests: replace mock and compat with code from community.internal_test_tools (#9922)
Unit tests: replace mock and compat with code from community.internal_test_tools (#9921)

* Replace compat with equivalent from community.internal_test_tools.

* Replace mock with equivalent from community.internal_test_tools.

(cherry picked from commit 410cf72aec)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-22 14:20:45 +01:00
patchback[bot]
57dcd31c82 [PR #9918/8ab8010b backport][stable-10] Use more unit test utils from community.internal_test_tools (#9919)
Use more unit test utils from community.internal_test_tools (#9918)

* Make conftest's patch_ansible_module use the context manager from .utils.

* Fix test dependencies.

* Use module mock utils from community.internal_test_tools.

* Use DataDictLoader from community.internal_test_tools.

* Use trust util from community.internal_test_tools.

(cherry picked from commit 8ab8010b6d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-22 13:52:39 +01:00
patchback[bot]
7ba3d84004 [PR #9880/3922b82a backport][stable-10] nmcli: fix reordering of DNS nameservers and search suffixes (#9912)
nmcli: fix reordering of DNS nameservers and search suffixes (#9880)

* nmcli: fix reordering of DNS nameservers and search suffixes

- Fixes #8724

* Update changelog fragment index in line with PR number

- Now I understand what that number is for

* Use correct changelog format for nmcli PR #9880

(cherry picked from commit 3922b82a57)

Co-authored-by: ashleyghooper <ashleyghooper@gmail.com>
2025-03-21 21:50:53 +01:00
patchback[bot]
837c1289d0 [PR #9892/579f369e backport][stable-10] vmadm - Add new options (#9913)
vmadm - Add new options (#9892)

* Add flexible_disk_size and owner_uuid options

* vmadm - add changelog fragment

* Improve descriptions for options

(cherry picked from commit 579f369ef3)

Co-authored-by: stratacast <courtney@courtnix.systems>
2025-03-21 21:50:47 +01:00
patchback[bot]
3c7c946297 [PR #9904/e3d92491 backport][stable-10] Add caddy example to copr module (#9916)
Add caddy example to copr module (#9904)

Add caddy example to copr.py

(cherry picked from commit e3d92491a3)

Co-authored-by: Elijah Lopez <elijahllopezz@gmail.com>
2025-03-21 21:50:39 +01:00
patchback[bot]
f0f5035ba2 [PR #9893/9286b601 backport][stable-10] cmd_runner_fmt.as_fixed() now accepts list of args (#9915)
cmd_runner_fmt.as_fixed() now accepts list of args (#9893)

* cmd_runner_fmt.as_fixed() now accepts list of args

* update CmdRunner guide

* add changelog frag

* Update changelogs/fragments/9893-cmdrunner-as-fixed-args.yml

* fix overdoing in as_fixed()

(cherry picked from commit 9286b60182)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-03-21 21:50:30 +01:00
Felix Fontein
3955a6be0f Prepare 10.5.0. 2025-03-21 21:07:44 +01:00
patchback[bot]
bc5b4bdef3 [PR #9900/6a2d9ccd backport][stable-10] sysrc: extend the list of FreeBSD releases where the jail test fails (#9903)
sysrc: extend the list of FreeBSD releases where the jail test fails (#9900)

Extend the list of FreeBSD releases where the jail test fails.

(cherry picked from commit 6a2d9ccd99)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-18 22:14:23 +01:00
patchback[bot]
8f8b1ee4ce [PR #9891/4a2cc711 backport][stable-10] systemd_info - extend support to timer unit (#9894)
systemd_info - extend support to timer unit (#9891)

* systemd_info - extend support to timer unit

* systemd_info - add changelogs fragments

* systemd_info - fix description and base_props

(cherry picked from commit 4a2cc71141)

Co-authored-by: Nocchia <133043574+NomakCooper@users.noreply.github.com>
2025-03-16 21:33:28 +01:00
patchback[bot]
6534db4942 [PR #9881/e5eac9fe backport][stable-10] homebrew_cask: Handle unusual brew version strings (#9889)
homebrew_cask: Handle unusual brew version strings (#9881)

* Use regex to parse unusual brew version strings

Fixes: #8432

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>
(cherry picked from commit e5eac9fed1)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2025-03-15 09:22:45 +01:00
patchback[bot]
7a55295798 [PR #9847/96b003f9 backport][stable-10] Adding Audio device support to proxmox_kvm (#9887)
Adding Audio device support to proxmox_kvm (#9847)

* Add Audio device support to proxmox_kvm.py

Audio device was unsupported with message :
`FAILED! => {"changed": false, "msg": "Unsupported parameters for (community.general.proxmox_kvm) module: audio. Supported parameters include: acpi, agent, api_host, api_password, api_port, api_token_id, api_token_secret, api_user, archive, args, autostart, balloon, bios, boot, bootdisk, cicustom, cipassword, citype, ciupgrade, ciuser, clone, cores, cpu, cpulimit, cpuunits, delete, description, digest, efidisk0, force, format, freeze, full, hookscript, hostpci, hotplug, hugepages, ide, ipconfig, keyboard, kvm, localtime, lock, machine, memory, migrate, migrate_downtime, migrate_speed, name, nameservers, net, newid, node, numa, numa_enabled, onboot, ostype, parallel, pool, protection, reboot, revert, sata, scsi, scsihw, searchdomains, serial, shares, skiplock, smbios, snapname, sockets, sshkeys, startdate, startup, state, storage, tablet, tags, target, tdf, template, timeout, tpmstate0, update, update_unsafe, usb, validate_certs, vcpus, vga, virtio, vmid, watchdog."}`

With this patch it is possible to update proxmox VM config with an audio device.

```yaml
- name: Add Spice compatible audio device
  community.general.proxmox_kvm:
    api_user: "{{ api_user }}"
    api_password: "{{ api_password }}"
    api_host: "{{ api_host }}"
    node: "{{ node_name }}"
    vmid: "{{ proxmox_vmid }}"
    audio: '{"audio0":"device=ich9-intel-hda,driver=spice"}'
    update: true
  delegate_to: localhost
```

* Update plugins/modules/proxmox_kvm.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update plugins/modules/proxmox_kvm.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/proxmox_kvm.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Create changelog fragment 9847-Adding_audio_device-support_to_proxmox_kvm.yml

* Update 9847-Adding_audio_device-support_to_proxmox_kvm.yml

Update following recommandations, thanks

* Update changelogs/fragments/9847-Adding_audio_device-support_to_proxmox_kvm.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 96b003f9af)

Co-authored-by: Croko-fr <62189784+Croko-fr@users.noreply.github.com>
2025-03-15 08:04:40 +01:00
patchback[bot]
0fd7cfd2d6 [PR #9821/3bd0ab4a backport][stable-10] systemd_info - add wildcards support (#9883)
systemd_info - add wildcards support (#9821)

* systemd_info - add wildcards support

* systemd_info - add wildcards fragments

* systemd_info - improved dedicated functions

* systemd_info - improved code and functions for better maintenance and timing

* fix unitname description

* removed redundancies and keys() in lists, replaced fnmatch with filter and run_command with cmdrunner

* systemd_info - add new cmdrunner

* systemd_info - fix runner

* systemd_info - fix env in runner

* systemd_info - rename runner and get_version

* systemd_info - change args runner, fix fragment, add botmeta

* systemd_info - merge type args

(cherry picked from commit 3bd0ab4a49)

Co-authored-by: Nocchia <133043574+NomakCooper@users.noreply.github.com>
2025-03-15 07:46:34 +01:00
patchback[bot]
68ca28b69a [PR #9849/add892aa backport][stable-10] NMAP Inventory Plugin: Added option for specifying DNS servers for name resolution (#9886)
NMAP Inventory Plugin: Added option for specifying DNS servers for name resolution (#9849)

* Added option for specifying DNS servers for name resolution in NMAP inventory plugin.

* Added option for specifying DNS servers for name resolution in NMAP inventory plugin.

* NMAP Inventory Plugin: Added option for specifying DNS servers for name resolution.

* Update plugins/inventory/nmap.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* NMAP Inventory Plugin: Added option for specifying DNS servers for name resolution.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit add892aa45)

Co-authored-by: Jim Anderson <thesemicolons@protonmail.com>
2025-03-15 07:46:25 +01:00
patchback[bot]
c91e7b4c03 [PR #9871/dd0a2cbf backport][stable-10] sudoers: display stderr raised while validation (#9885)
sudoers: display stderr raised while validation (#9871)

* sudoers: display stderr raised while validation

* Print stdout and stderr raised from sudoers validation

Fixes: #9674

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>

* Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit dd0a2cbff9)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2025-03-15 07:46:14 +01:00
patchback[bot]
2583152512 [PR #9837/abe4e5ce backport][stable-10] Redfish: implement setting PowerRestorePolicy (#9878)
Redfish: implement setting PowerRestorePolicy (#9837)

This property ("The desired power state of the system when power is
restored after a power loss.") was added in ComputerSystem.v1_6_0 which
became part of 2018.3 Redfish release.

Tested against an OpenBMC system running bmcweb Redfish server making sure the
policy is updated only when needed and that errors and messages are propogated
properly.

Signed-off-by: Paul Fertser <fercerpav@gmail.com>
(cherry picked from commit abe4e5ce95)

Co-authored-by: Paul Fertser <fercerpav@gmail.com>
2025-03-12 20:06:02 +01:00
patchback[bot]
cee6c98d2a [PR #9872/fdbc06c7 backport][stable-10] CI: Add FreeBSD 13.5 (#9874)
CI: Add FreeBSD 13.5 (#9872)

Add FreeBSD 13.5.

(cherry picked from commit fdbc06c714)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-12 17:58:32 +01:00
patchback[bot]
8859379bed [PR #9858/710dc5df backport][stable-10] pacemaker unit test: passing null with UTHelper (#9868)
pacemaker unit test: passing null with UTHelper (#9858)

(cherry picked from commit 710dc5df86)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-03-11 07:14:08 +01:00
patchback[bot]
e899631137 [PR #9836/941df094 backport][stable-10] Adds option for http agent for user in slack callback (#9866)
Adds option for http agent for user in slack callback (#9836)

* Adds option for http agent for user in slack callback

* Adds changelog fragment for 9836 issue

* Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

* Fix typo.

---------

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 941df094ca)

Co-authored-by: Anwesha Das <anwesha@das.community>
2025-03-10 18:12:18 +01:00
patchback[bot]
e99dcaa729 [PR #9846/86dea88c backport][stable-10] dnf_versionlock: add support for Fedora 41 and dnf5 (#9865)
dnf_versionlock: add support for Fedora 41 and dnf5 (#9846)

Fixes: #9556

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>
(cherry picked from commit 86dea88cb6)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2025-03-10 06:31:08 +01:00
patchback[bot]
c12dd2f9c7 [PR #9845/7d5357d7 backport][stable-10] Fix roles/policies normalization in consul_token. (#9863)
Fix roles/policies normalization in consul_token. (#9845)

* Fix roles/policies normalization in consul_token.

* Update changelogs/fragments/9845-consul_token_idempotency.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 7d5357d74c)

Co-authored-by: Florian Apolloner <florian@apolloner.eu>
2025-03-10 06:30:54 +01:00
patchback[bot]
8253fb171d [PR #9859/eff25c8a backport][stable-10] Fix/improve tests (#9860)
Fix/improve tests (#9859)

* Fix tests.

* Improve callback tests.

(cherry picked from commit eff25c8a6e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-09 17:01:54 +01:00
patchback[bot]
5f1f76b8f4 [PR #9853/4727fb77 backport][stable-10] cmd_runner tests: fix reliance on unspecified behavior (#9857)
cmd_runner tests: fix reliance on unspecified behavior (#9853)

Fix reliance on unspecified behavior.

(cherry picked from commit 4727fb77b3)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-09 09:01:13 +01:00
patchback[bot]
e3793e09e8 [PR #9850/9df84654 backport][stable-10] Improve/fix unit tests (#9852)
Improve/fix unit tests (#9850)

* Improve/fix tests.

* Fix cargo test.

(cherry picked from commit 9df8465476)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-08 16:42:05 +01:00
patchback[bot]
a800a6dbad [PR #9842/c46575cf backport][stable-10] Simplify module_utils unit tests (#9844)
Simplify module_utils unit tests (#9842)

Simplify module_utils unit tests.

(cherry picked from commit c46575cf06)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-07 18:33:20 +01:00
patchback[bot]
7d45b678e4 [PR #9838/a1781d09 backport][stable-10] Unit tests: make set_module_args() a context manager, and remove copies of it in some tests (#9839)
Unit tests: make set_module_args() a context manager, and remove copies of it in some tests (#9838)

Make set_module_args() a context manager, and remove copies of set_module_args().

Prepares for Data Tagging.

(cherry picked from commit a1781d09dd)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-07 07:27:55 +01:00
patchback[bot]
cd0ca389ed [PR #9803/c43289b8 backport][stable-10] homebrew: Do not crash when package names include tap prefix. (#9834)
homebrew:  Do not crash when package names include tap prefix. (#9803)

* homebrew:  Do not crash when package names include tap prefix.

Fixes #9777

* homebrew: PR #9803 minor update: removed trailing whitespace

* Update changelogs/fragments/9777-homebrew-fix-crash-when-packages-include-tap.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Apply suggestions from code review

Co-authored-by: Thibaut Decombe <68703331+UnknownPlatypus@users.noreply.github.com>

* Update plugins/modules/homebrew.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Thibaut Decombe <68703331+UnknownPlatypus@users.noreply.github.com>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit c43289b8f1)

Co-authored-by: brad2014 <brad2014@users.noreply.github.com>
2025-03-05 21:37:08 +01:00
patchback[bot]
9ebf72d560 [PR #9531/402f7254 backport][stable-10] add pacemaker_resource plugin (#9835)
add pacemaker_resource plugin (#9531)

* Add initial pacemaker resource

* Additional fixes on pacemaker_resource

* Fix up module parameters

* fix doc and lint

* fix group command build

* Apply suggestions for removing status and improve descriptions

* fix cmd builder list

* Apply suggestions and add initial unit tests

* Fix unit tests expected output

* Initial refactor on pacemaker resource

Refactorization on pacemaker_resource to utilize module helpers.

* Apply suggestions and fix up initial unit test

* Apply suggestions from code review

* Fix pep8 format for utils

* Fix unit tests for pacemaker resource

* Add botmeta maintainers for new moduules

* Apply suggestions from code review

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Apply unit test suggestion

* Add disable and enable states for pacemaker_resource

* Fix state names and add cli_action for runner

* Remove unnecessary variables

* Fix documentation example playbook

* Fix IP Address for resource_option

* Refactor and remove unnecessary facts

* Apply suggestions from code review

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 402f725424)

Co-authored-by: Dexter <45038532+munchtoast@users.noreply.github.com>
2025-03-05 21:36:56 +01:00
patchback[bot]
d6a4fab8ea [PR #9819/5f48f2ca backport][stable-10] Example typo in homebrew_services.py (#9827)
Example typo in homebrew_services.py (#9819)

Maybe this was mixed up with the _brew_service_state() function? I get this error as-written:
```
fatal: [eahmm3]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (community.general.homebrew_services) module: service
_state. Supported parameters include: name, path, state (formula)."}
```

(cherry picked from commit 5f48f2ca0d)

Co-authored-by: Ernie Hershey <github@ernie.org>
2025-03-03 21:32:19 +01:00
patchback[bot]
4e43b124cd [PR #9828/77dc0868 backport][stable-10] homebrew_services: skip tests on macOS 13.2 and 14.3 (#9830)
homebrew_services: skip tests on macOS 13.2 and 14.3 (#9828)

Skip tests on macOS 13.2 and 14.3.

(cherry picked from commit 77dc086896)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-03-03 21:32:00 +01:00
patchback[bot]
9bcf61d153 [PR #9824/129f51cf backport][stable-10] Redfish: implement obtaining PowerRestorePolicy (#9824) (#9825)
Redfish: implement obtaining PowerRestorePolicy (#9824) (#9824)

This property ("The desired power state of the system when power is
restored after a power loss.") was added in ComputerSystem.v1_6_0 which
became part of 2018.3 Redfish release.

Example result from querying OpenBMC's bmcweb Redfish server:
```
    entries:
    -   -   system_uri: /redfish/v1/Systems/system
        - AlwaysOff
    ret: true
```

Signed-off-by: Paul Fertser <fercerpav@gmail.com>
(cherry picked from commit 129f51cf9d)

Co-authored-by: Paul Fertser <fercerpav@gmail.com>
2025-03-03 21:15:22 +01:00
patchback[bot]
7f5305fb80 [PR #9818/3b6efd5c backport][stable-10] cloudflare_dns: handle exhausted response stream in case of http error (#9823)
cloudflare_dns: handle exhausted response stream in case of http error (#9818)

* cloudflare_dns: handle exhausted response stream in case of http error

* Update changelogs/fragments/9818-cloudflare-dns-exhausted-response.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 3b6efd5cbc)

Co-authored-by: Kristian Heljas <11139388+kristianheljas@users.noreply.github.com>
2025-03-03 07:24:12 +01:00
patchback[bot]
aea60a8dd6 [PR #9812/cf147b9f backport][stable-10] misc typo fix (#9816)
misc typo fix (#9812)

Signed-off-by: Abhijeet Kasurde <Akasurde@redhat.com>
(cherry picked from commit cf147b9fca)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2025-03-01 11:31:08 +01:00
patchback[bot]
195ac4d7e6 [PR #9809/e39320c3 backport][stable-10] proxmox: fix status getter (#9817)
proxmox: fix status getter (#9809)

* proxmox: fix status getter

get_lxc_status was missing a selection of the 'status' key

* proxmox: add changelog fragment

* proxmox: fix changelog fragment

(cherry picked from commit e39320c354)

Co-authored-by: JL Euler <Lithimlin@users.noreply.github.com>
2025-03-01 11:30:52 +01:00
patchback[bot]
91d515bd1e [PR #9768/4c11902f backport][stable-10] keycloak_realm: remove realm id requirement (#9810)
keycloak_realm: remove realm id requirement (#9768)

* remove realm id requirement

* replace id with realm

* replace id with realm in documentation

* add changelog fragment

* Update changelogs/fragments/9768-keycloak_realm-remove-id-requirement.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/9768-keycloak_realm-remove-id-requirement.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

* add comment to get_realm_by_id

* Update plugins/module_utils/identity/keycloak/keycloak.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 4c11902fdc)

Co-authored-by: gruenbauer@b1-systems.de <gruenbauer@b1-systems.de>
2025-02-27 21:59:36 +01:00
patchback[bot]
7d8f5559e2 [PR #9457/98b328c5 backport][stable-10] apache2_mod_proxy: big revamp (#9806)
apache2_mod_proxy: big revamp (#9457)

* apache2_mod_proxy: big revamp

* fix case when state=null

* fix logic for change detection

(cherry picked from commit 98b328c539)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-26 22:05:03 +01:00
patchback[bot]
9e68816db9 [PR #9805/dd4268e0 backport][stable-10] CI: Add macOS 15.3 (#9808)
CI: Add macOS 15.3 (#9805)

* Add macOS 15.3.

* Install setuptools on macOS 15.

(cherry picked from commit dd4268e0d9)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-26 22:04:52 +01:00
Felix Fontein
fc1ba5152c Next expected release will be 10.5.0. 2025-02-24 07:15:53 +01:00
Felix Fontein
205e28d2fe Release 10.4.0. 2025-02-24 06:47:35 +01:00
patchback[bot]
27629b6497 [PR #9787/e8e3e5c2 backport][stable-10] Allow Xen Host and/or Xen VM names instead of their UUIDs (#9801)
Allow Xen Host and/or Xen VM names instead of their UUIDs (#9787)

* Allow using Xen Host and/or Xen VM names instead of their UUIDs for inventory

* xen_orchestra inventory plugin allow using vm and host names instead of UUID inventory

* Update changelog fragment with correct PR number

* Set missing inventory attributes in unit test

* Add version_added suggestion as per github comments

* Description update.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit e8e3e5c2b0)

Co-authored-by: rt-vnx <riordan.toms@vonex.com.au>
2025-02-24 06:18:09 +01:00
patchback[bot]
5735c5a045 [PR #9764/8425464c backport][stable-10] Add new systemd_info module (#9800)
Add new systemd_info module (#9764)

* add systemd_info module

* fix object results

* apply review changes

* apply module change and add doc_fragments

* removed use_unsafe_shell and doc_fragments/systemd

* fix unitname description doc

* fixed doc, replaced systemctl show syntax, added base prop result doc

* fix documentation

* fix RV values in description

* fix RV() description values

* add get_bin_path try/fail and remove list()

* fix doc, removed try block

* add Archlinux in integration test

(cherry picked from commit 8425464c0a)

Co-authored-by: Nocchia <133043574+NomakCooper@users.noreply.github.com>
2025-02-23 17:52:07 +01:00
patchback[bot]
ceb051851e [PR #9796/217a1883 backport][stable-10] locale_gen: enable tests for Arch Linux, make sure they don't even try to run on RHEL and Fedora VMs (#9798)
locale_gen: enable tests for Arch Linux, make sure they don't even try to run on RHEL and Fedora VMs (#9796)

Enable locale_gen tests for Arch Linux, make sure they don't even try to run on RHEL and Fedora VMs.

(cherry picked from commit 217a18839d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-23 15:27:08 +01:00
patchback[bot]
a17083ea84 [PR #9657/2b6f4ba2 backport][stable-10] lldp: Handling attributes that are defined multiple times (#9799)
lldp: Handling attributes that are defined multiple times (#9657)

* lldp: Ignoring values for keys already defined

This fixes crashes when the lldpctl output has lines for unknown tlvs that
redefine a key in the middle of the nested dict data structure.

* lldp: handling attributes that are defined multiple times

- Fix crash caused by certain lldpctl output where an attribute is defined as branch and leaf
- Adds multivalues parameter to control behavior when lldpctl outputs an attribute multiple times

* lldp: using isinstance instead of type

* Link to Github PR

Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

* lldp: only push value to subkey in multivalues mode

To provide backwards compatibility values that are defined as a
attribute and also as a path element are only pushed to the 'value'
subkey when using the new multivalues mode.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 2b6f4ba299)

Co-authored-by: Julian Wecke <julian@net23.de>
2025-02-23 15:26:57 +01:00
patchback[bot]
d03fdc8093 [PR #9684/961c9b7f backport][stable-10] Ssh config other options (#9794)
Ssh config other options (#9684)

* Add other_options support to ssh_config module

* Changelog fragment

* Fix missing and modified stuff

* Minor changes

* Update fragment with PR URL

* Fix PEP8 issue

* Fix idempotency issue

* Update changelogs/fragments/ssh_config_add_other_options.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/ssh_config.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/ssh_config.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Incorporate suggestions

* Missed removing str conversion

* PEP8

* Update plugins/modules/ssh_config.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add fail condition, fix codestyle

* Force lower case key values only

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 961c9b7f4c)

Co-authored-by: Stephen Bradshaw <stephen.mark.bradshaw@gmail.com>
2025-02-22 09:20:31 +01:00
patchback[bot]
469209a17f [PR #9788/bb2c45b5 backport][stable-10] json_query filter docs: fix typo cluster2 when cluster1 is mentioned (#9793)
json_query filter docs: fix typo cluster2 when cluster1 is mentioned (#9788)

Typo cluster2 but cluster1 is mentioned

(cherry picked from commit bb2c45b5bb)

Co-authored-by: Kloppi313 <36038231+Kloppi313@users.noreply.github.com>
2025-02-21 20:50:45 +01:00
patchback[bot]
72ea96cc74 [PR #9774/ddc1ea6a backport][stable-10] Fix proxy settings for elasticsearch_plugin.py (#9786)
Fix proxy settings for elasticsearch_plugin.py (#9774)

elasticsearch_plugin: fix error when setting proxy settings

Co-authored-by: Tim Hovius <w.hovius@rechtspraak.nl>
(cherry picked from commit ddc1ea6ae4)

Co-authored-by: Tim Hovius <timhovius@gmail.com>
2025-02-20 22:27:16 +01:00
patchback[bot]
b2c34d1afe [PR #9778/203c1ecf backport][stable-10] redhat_registration: use 'enable_content' D-Bus option when available (#9784)
redhat_registration: use 'enable_content' D-Bus option when available (#9778)

This makes sure that subscription-manager always enables the content for
the system right after the registration.

This is particular important on EL 10+ and Fedora 41+.

(cherry picked from commit 203c1ecfec)

Co-authored-by: Pino Toscano <ptoscano@redhat.com>
2025-02-20 22:27:03 +01:00
patchback[bot]
f4fca86f82 [PR #9106/105ae056 backport][stable-10] bugfix - Prevent passwordstore lookup to create subkey when create == false (#9780)
bugfix - Prevent passwordstore lookup to create subkey when create == false (#9106)

Fixes #9105

Apply suggestion

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 105ae0566a)

Co-authored-by: Manuel Luzarreta <mluzarreta.pro@pm.me>
2025-02-19 22:30:24 +01:00
patchback[bot]
78c8fa0d49 [PR #9775/8e36fd48 backport][stable-10] apache2_mod_proxy: follow-up for #9762, forgot one place with find_all/findAll (#9776)
apache2_mod_proxy: follow-up for #9762, forgot one place with find_all/findAll (#9775)

Follow-up for #9762, forgot one place.

(cherry picked from commit 8e36fd4847)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-18 21:53:16 +01:00
patchback[bot]
d3650f27b0 [PR #9762/a3fd357d backport][stable-10] Make apache2_mod_proxy work with Python 3, half-way modern Apache 2 versions, and add basic tests (#9771)
Make apache2_mod_proxy work with Python 3, half-way modern Apache 2 versions, and add basic tests (#9762)

* Move Apache 2 installation to setup role.

* Make module work with Python 3.

* Add basic tests.

* Add changelog fragment.

* Simplify change.

* Pass referer.

(cherry picked from commit a3fd357d81)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-18 20:30:09 +01:00
patchback[bot]
7b901f9caa [PR #9760/d696bb7b backport][stable-10] proxmox inventory: proposal for #9710 (caching) (#9770)
proxmox inventory: proposal for #9710 (caching) (#9760)

* Proposal for #9710

* Fixed comments

* Fixed trailing whitespace

* Fixed changelog fragment

(cherry picked from commit d696bb7b89)

Co-authored-by: Dirk S. <iqt4@users.noreply.github.com>
2025-02-17 19:26:05 +01:00
patchback[bot]
35d6ab10bb [PR #9743/94e15110 backport][stable-10] incus_connection: Allow non-root users to connect to an instance (#9765)
incus_connection: Allow non-root users to connect to an instance (#9743)

* feat: add remote_user option to incus connection

* feat: add changelog fragment

* fix: formatting

(cherry picked from commit 94e1511005)

Co-authored-by: Peter Siegel <33677897+yeetypete@users.noreply.github.com>
2025-02-17 07:55:37 +01:00
patchback[bot]
d811807e1f [PR #9753/fa7876bb backport][stable-10] Jira: add SSL client certificate support for authentication (#9763)
Jira: add SSL client certificate support for authentication (#9753)

* jira: add ssl client certificate support for authentification

* fix code bugs from first CI run

* fix fstring not compatible with older python and chhange urlopen module call

* removed duplicated post,put,get method

* fix urllib module detection Python2/ Python3

* edit HTTP Request back to fetch_url

* add changelog fragment

* fix python line spacing

* Update plugins/modules/jira.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/jira.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* edit documentation certificate auth not mutually exclusive

* Update changelogs/fragments/9753-jira-add-client-certificate-auth.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* edit documentation for client certificate auth and token

* add no_log for client_cert and client_key

* removed no_log for client_cert and client_key

---------

Co-authored-by: domin <domin@MacBookPro.fritz.box>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit fa7876bb40)

Co-authored-by: Dominik <47948163+weristdominik@users.noreply.github.com>
2025-02-16 21:37:34 +01:00
Felix Fontein
dedd625700 Prepare 10.4.0 release. 2025-02-16 20:27:32 +01:00
patchback[bot]
10e41862cb [PR #9754/b80fa80c backport][stable-10] clc_*: deprecation (#9761)
clc_*: deprecation (#9754)

* clc_*: deprecation

* Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit b80fa80c90)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-16 20:06:48 +01:00
patchback[bot]
3d418d9ede [PR #9739/b2e2d2d3 backport][stable-10] keycloak_client: compare desired and before dicts directly in checkmode (#9759)
keycloak_client: compare desired and before dicts directly in checkmode (#9739)

* compare desired and before dicts directly in checkmode

* fix authorizationServicesEnabled being dropped by kc if unset

* only add authorizationsServicesEnabled=false if before_client exists

* add changelog fragment

* Update changelog.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit b2e2d2d37b)

Co-authored-by: gruenbauer@b1-systems.de <gruenbauer@b1-systems.de>
2025-02-16 12:38:04 +01:00
patchback[bot]
ebb150c3f9 [PR #9728/410999df backport][stable-10] bitwarden lookup: add options to filter by collection_name and validate number of results (#9757)
bitwarden lookup: add options to filter by collection_name and validate number of results (#9728)

* feat(lookups/bitwarden): add collection_name filter

* feat(lookups/bitwarden): add result_count check

* docs(lookups/bitwarden): add changelog fragment

* Update changelogs/fragments/9728-bitwarden-collection-name-filter.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* fix(lookups/bitwarden): fix result_count check for multiple terms

* fix(lookups/bitwarden): Enforce mutual exclusion of 'collection_name' and 'collection_id'

* formatting(lookups/bitwarden): remove trailing whitespace

* Update plugins/lookup/bitwarden.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update plugins/lookup/bitwarden.py

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* formatting(lookups/bitwarden): remove trailing whitespace

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 410999dffa)

Co-authored-by: Jonas <jonas.switala@frequentis.com>
2025-02-16 12:24:57 +01:00
patchback[bot]
df28c80946 [PR #9755/ba252294 backport][stable-10] profitbricks: fix typo in deprecation text (#9756)
profitbricks: fix typo in deprecation text (#9755)

(cherry picked from commit ba25229482)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-16 11:32:54 +01:00
patchback[bot]
403152d91a [PR #9653/64d78585 backport][stable-10] proxmox_kvm Allow vm hibernation (#9752)
proxmox_kvm Allow vm hibernation (#9653)

* Allow vm hibernation

* add changelog fragment

* pylint and pep8 tests failed

* forgot period

* added introducing version number to module description

(cherry picked from commit 64d785858e)

Co-authored-by: ff05 <71757437+ff05@users.noreply.github.com>
2025-02-15 13:41:32 +01:00
patchback[bot]
75e35bfa6c [PR #9659/06df717b backport][stable-10] lxd_connection: Allow non-root users to connect to an instance (#9751)
lxd_connection: Allow non-root users to connect to an instance (#9659)

* fix: add support for non-root user

* fix: show correct info for connection

* fix: use build_exec_command to execute as nonroot

* unset default user

* feat: add options for setting remote user and become method

* fix: add root as default remote_user

* fix: remove ansible_ssh_user from remote_user vars

* fix: use single quotes inside f-string

* fix: ensure lxc exec comes first

* fix: line length

* fix: use -c flag with su

* Update plugins/connection/lxd.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/connection/lxd.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/connection/lxd.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* doc: add changelog fragment

* fix: use underscore for module name in fragment

* Update 9659-lxd_connection-nonroot-user.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* fix: add put command

* feat: add get_remote_uid_gid placeholder function

* feat: complete placeholder _get_remote_uid_gid function

* fix: better logging

* fix: ensure default values are of type str

* fix: use ints for uid and gid

* fix: print put command

* fix: format

* fix: display msg for PUT

* fix: add comment about defaults

* fix: format

* fix: use os module to get uid and gid

* Revert "fix: use os module to get uid and gid"

This reverts commit bb2ba14b8f.

* Update plugins/connection/lxd.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* fix: omit uid, gid args in lxd file push if root

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 06df717bc6)

Co-authored-by: Peter Siegel <33677897+yeetypete@users.noreply.github.com>
2025-02-15 13:41:24 +01:00
patchback[bot]
fa846e9677 [PR #9727/910c57aa backport][stable-10] keycloak: repair integration tests by removing jinja2 templating from conditionals (#9726) (#9748)
keycloak: repair integration tests by removing jinja2 templating from conditionals (#9726) (#9727)

* fix: remove jinja2 templating from conditionals in keycloak_role module integration tests (#9726)

* fix: remove jinja2 templating in conditional in keycloak clientsecret info integration test (#9726)

This test needs a further fix; see #9744. Left for a future PR for now.

* fix: remove jinja2 templating in conditional in keycloak clientsecret regenerate integration test (#9726)

* chore: remove jinja2 templating in conditional in keycloak user federation integration test (#9726)

These instances of templating were not causing failures,
but this removes the warnings.

* chore: remove jinja2 templating in conditional in keycloak user rolemapping integration test (#9726)

These instances of templating were not causing failures,
but this removes the warnings.

* docs: add changelog fragment (#9726)

* docs: repair changelog fragment yaml (#9726)

* docs: actually repair changelog fragment yaml (#9726)

* chore: remove changelog fragment for test only pr (#9726)

(cherry picked from commit 910c57aaa0)

Co-authored-by: Mark Armstrong <markparmstrong@gmail.com>
2025-02-15 12:31:44 +01:00
patchback[bot]
db62a36d6e [PR #9676/9d0bd1d4 backport][stable-10] Test helper guide (#9749)
Test helper guide (#9676)

(cherry picked from commit 9d0bd1d4d9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-15 12:30:54 +01:00
patchback[bot]
e3dae0b646 [PR #9736/8e324881 backport][stable-10] rename test helper (#9745)
rename test helper (#9736)

* rename test helper

* update ignore lines

(cherry picked from commit 8e324881a6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-15 08:25:27 +01:00
patchback[bot]
9aaf8e4825 [PR #9733/085bcb22 backport][stable-10] profitbricks: deprecation (#9740)
profitbricks: deprecation (#9733)

* profitbricks: deprecation

* add changelog frag

(cherry picked from commit 085bcb22a2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-13 20:39:51 +01:00
patchback[bot]
cf0a233d7b [PR #9729/7af5e158 backport][stable-10] Add FullPowerCycle to Power commands (#9730)
Add `FullPowerCycle` to Power commands (#9729)

* Add `FullPowerCycle` to Power commands

* Add changelog fragment

* Rename command

* Fix line length for redfish_command options

(cherry picked from commit 7af5e158b8)

Co-authored-by: Scott Seekamp <sseekamp@coreweave.com>
2025-02-11 22:23:51 +01:00
patchback[bot]
cebd5bb3c8 [PR #9651/fdd1331e backport][stable-10] Implement #9650 Add parameter hooks to inventory plugin iocage (#9731)
Implement #9650 Add parameter hooks to inventory plugin iocage (#9651)

* Add parameter hooks to inventory plugin iocage.

* Add changelog fragment.

* Update plugins/inventory/iocage.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Parameter renamed to hooks_results

* Fix DOCUMENTATION YAML 4-space indentation.

* Fix DOCUMENTATION YAML 2-space indentation.

* Update changelogs/fragments/9651-iocage-inventory-hooks.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add note about activated pool mountpoint.

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit fdd1331e4a)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2025-02-11 22:23:42 +01:00
patchback[bot]
d452e903f8 [PR #9722/d756aeb6 backport][stable-10] CI: Cleanup AZP config similarly to ansible-core did some years ago (#9725)
CI: Cleanup AZP config similarly to ansible-core did some years ago (#9722)

Cleanup AZP config similarly to ansible-core did some years ago.

(cherry picked from commit d756aeb6ce)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-10 23:14:00 +01:00
patchback[bot]
c76ef6ba99 [PR #9694/d5add1ed backport][stable-10] ipa_host: Maintain the host certificates (#9721)
ipa_host: Maintain the host certificates (#9694)

* ipa_host: Maintain the host certificates

Fix #9693

* Add changelog fragment

* Fix changelog message

* Fix changelog message again

(cherry picked from commit d5add1ed9f)

Co-authored-by: sedrubal <sedrubal@users.noreply.github.com>
2025-02-10 22:08:17 +01:00
patchback[bot]
52bd7cdb2d [PR #6264/1f92a699 backport][stable-10] zfs: fix multi-line value in user-defined property (#9718)
zfs: fix multi-line value in user-defined property (#6264)

* zfs: fix multi-line value in user-defined property

* zfs: fix multi-line value in user-defined property

* Update changelogs/fragments/6264-zfs-multiline-property-value.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/zfs.py

Co-authored-by: sam-lunt <samuel.j.lunt@gmail.com>

* rename self.properties -> self.extra_zfs_properties

---------

Co-authored-by: Vita Batrla <vita.batrla@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: sam-lunt <samuel.j.lunt@gmail.com>
(cherry picked from commit 1f92a69992)

Co-authored-by: Vita Batrla <34657903+batrla@users.noreply.github.com>
2025-02-10 22:05:04 +01:00
patchback[bot]
da3ba1e7be [PR #9698/1beee879 backport][stable-10] lvg: Add parameter to disable removal of extra physical volumes (#9717)
lvg: Add parameter to disable removal of extra physical volumes (#9698)

* Add parameter to disable removal of extra physical volumes

Signed-off-by: Massl123 <Massl123@users.noreply.github.com>

* Set PR number in changelog fragment

Signed-off-by: Massl123 <Massl123@users.noreply.github.com>

* Fix tests

Signed-off-by: Massl123 <Massl123@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

* Add comment in pvs

Signed-off-by: Massl123 <Massl123@users.noreply.github.com>

---------

Signed-off-by: Massl123 <Massl123@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1beee87961)

Co-authored-by: Marcel Freundl <Massl123@users.noreply.github.com>
2025-02-10 22:04:51 +01:00
patchback[bot]
cb46453b78 [PR #9697/165106d2 backport][stable-10] zfs_facts: set parameter "type" as a list (#9716)
zfs_facts: set parameter "type" as a list (#9697)

* zfs_facts: set parameter "type" as a list

Plus minor readability improvements

* add changelog frag

* Update plugins/modules/zfs_facts.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 165106d2bd)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-10 22:04:41 +01:00
patchback[bot]
a784e66a2c [PR #9658/a842a268 backport][stable-10] Update nmcli.py to support VRF commands (#9715)
Update nmcli.py to support VRF commands (#9658)

Adding VRF support and documentation to the nmcli module

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
(cherry picked from commit a842a26849)

Co-authored-by: Andreas Karis <akaris@redhat.com>
2025-02-10 22:04:32 +01:00
patchback[bot]
52cc1881d8 [PR #9625/4e0de41a backport][stable-10] onepassword_doc: fix 1Password Connect support (#9719)
onepassword_doc: fix 1Password Connect support (#9625)

Fix 1Password Connect support for onepassword_doc.

(cherry picked from commit 4e0de41a85)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-10 22:04:24 +01:00
Felix Fontein
5c7076e0bc The next expected release will be 10.4.0. 2025-02-10 21:49:34 +01:00
Felix Fontein
fc752f3143 Release 10.3.1. 2025-02-10 21:23:52 +01:00
Felix Fontein
4637c265fa Prepare 10.3.1 release. 2025-02-10 20:05:52 +01:00
patchback[bot]
33e980039b [PR #9665/75ffae43 backport][stable-10] More resilient brew formulae name handling (#9714)
More resilient brew formulae name handling (#9665)

* Remove update_homebrew=False (it's the default)

* Fix handling of irregular cases (brew does lowercase normalization)

* Fix handling of tap with no public fallback

* Add changelog fragment

* Add missing cleanup step

* Fix typo

* Check re-install and re-uninstall too

(cherry picked from commit 75ffae43e6)

Co-authored-by: Thibaut Decombe <68703331+UnknownPlatypus@users.noreply.github.com>
2025-02-10 19:18:00 +01:00
patchback[bot]
e49775765d [PR #9695/191a4d8f backport][stable-10] xml: ensure the stream object is closed in main() (#9712)
xml: ensure the stream object is closed in main() (#9695)

* ensure the stream object is closed in main()

* add changelog frag

* Update plugins/modules/xml.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/xml.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 191a4d8f63)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-09 14:27:17 +01:00
patchback[bot]
c2590cfcd8 [PR #9705/efe0c464 backport][stable-10] Disable failing copr tests (#9709)
Disable failing copr tests (#9705)

Disable failing copr tests.

(cherry picked from commit efe0c464ff)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-09 12:44:53 +01:00
Felix Fontein
4282b6ed16 Fix typo.
(cherry picked from commit d6943c9838)
2025-02-09 08:10:54 +01:00
patchback[bot]
3c77c8ec3c [PR #9691/41caa9a2 backport][stable-10] keycloak module utils replace missing return in get_role_composites (#9703)
keycloak module utils replace missing return in `get_role_composites` (#9691)

* fix: replace missing return (#9678)

* chore: add changelog fragment (#9678)

* chore: update changelog fragment (#9678)

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 41caa9a22c)

Co-authored-by: Mark Armstrong <markparmstrong@gmail.com>
2025-02-08 21:46:52 +01:00
patchback[bot]
07e4e4a782 [PR #9699/10c15d31 backport][stable-10] filesystem tests: reiserfsprogs is no longer available on Arch Linux (#9702)
filesystem tests: reiserfsprogs is no longer available on Arch Linux (#9699)

reiserfsprogs is no longer available on Arch Linux.

(cherry picked from commit 10c15d31f7)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-08 20:25:41 +01:00
patchback[bot]
d881a59ed7 [PR #9686/0b4337c1 backport][stable-10] Also disable snap_alias tests for RHEL 8.8 (#9689)
Also disable snap_alias tests for RHEL 8.8 (#9686)

Also disable snap_alias tests for RHEL 8.8.

(cherry picked from commit 0b4337c13d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-04 22:29:25 +01:00
patchback[bot]
338328341e [PR #9679/54eec2cb backport][stable-10] Disable snap tests on RHEL 8.8 (#9682)
Disable snap tests on RHEL 8.8 (#9679)

Disable snap tests on RHEL 8.8.

(cherry picked from commit 54eec2cb09)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-02-03 10:56:51 +01:00
patchback[bot]
6e48528b22 [PR #9675/4a31c753 backport][stable-10] test helper: remove magically finding the testcasemock in the test module (#9677)
test helper: remove magically finding the testcasemock in the test module (#9675)

(cherry picked from commit 4a31c753e7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-03 07:03:39 +01:00
patchback[bot]
f545c300d9 [PR #9672/7a6125b9 backport][stable-10] test helper: improvements (#9673)
test helper: improvements (#9672)

(cherry picked from commit 7a6125b99a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-02 10:50:11 +01:00
patchback[bot]
df496e37c0 [PR #9644/250dc113 backport][stable-10] Fb keycloak client improvement (#9671)
Fb keycloak client improvement (#9644)

* Fix for failed test

TASK [keycloak_client : Assert changes not detected in last two tasks (desire when same, and check)] ***
task path: /root/ansible_collections/community/general/tests/output/.tmp/integration/keycloak_client-p3ttqf7d-ÅÑŚÌβŁÈ/tests/integration/targets/keycloak_client/tasks/main.yml:79
fatal: [testhost]: FAILED! => {
    "assertion": "check_client_when_present_and_same is not changed",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}

* Improved test data to test more scenarios, e.g documentation uses True in examples

* Normalize values in config

* add changelog

* Apply suggestions from code review

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update tests/integration/targets/keycloak_client/vars/main.yml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

* Update changelogs/fragments/9644-kc_client-test-improvement-and-fix.yaml

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>

---------

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
(cherry picked from commit 250dc1139c)

Co-authored-by: amPrimeSign <146177975+amPrimeSign@users.noreply.github.com>
2025-02-01 22:46:14 +01:00
patchback[bot]
c35f13084d [PR #9666/c0f57b5c backport][stable-10] test helper: add support for check and diff modes (#9669)
test helper: add support for check and diff modes (#9666)

(cherry picked from commit c0f57b5c62)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-01 18:49:35 +01:00
patchback[bot]
4d4e626f95 [PR #9664/439da9e6 backport][stable-10] test helper unit tests: reformat YAML files (#9667)
test helper unit tests: reformat YAML files (#9664)

(cherry picked from commit 439da9e6da)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-01 17:01:24 +01:00
patchback[bot]
faa913d566 [PR #9176/47637cde backport][stable-10] locale_gen: add testcase for de_CH.utf8 (#9668)
locale_gen: add testcase for de_CH.utf8 (#9176)

(cherry picked from commit 47637cdec7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-01 17:00:26 +01:00
patchback[bot]
7e4a39964e [PR #9662/4d384bd7 backport][stable-10] test helper: fix parameter passing in creation static method (#9663)
test helper: fix parameter passing in creation static method (#9662)

(cherry picked from commit 4d384bd74a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-02-01 15:01:57 +01:00
patchback[bot]
c6aecd18f4 [PR #9660/5f157aac backport][stable-10] lvol: fix the force parameter's description (#9661)
lvol: fix the force parameter's description (#9660)

(cherry picked from commit 5f157aac15)

Co-authored-by: Conner Crosby <cavcrosby@gmail.com>
2025-02-01 15:01:45 +01:00
patchback[bot]
c5bdb1501e [PR #9649/19d00496 backport][stable-10] cloudflare_dns: fix crash when deleting a DNS record or when updating a record with solo=true (#9655)
cloudflare_dns: fix crash when deleting a DNS record or when updating a record with solo=true (#9649)

* cloudflare_dns: fix crash when deleting a DNS record or when updating a record with solo=true

On 2025-01-27, Cloudflare removed the 'zone_id' field from the DNS record API responses. This caused a KeyError in the delete_dns_records method, which previously relied on rr['zone_id'].

This commit ensures the zone ID is retrieved via _get_zone_id() rather than using the no-longer-provided 'zone_id' field in the record response.

Reference: https://developers.cloudflare.com/dns/changelog/#2025-01-27

* Add changelog fragment

* Update changelogs/fragments/9649-cloudflare_dns-fix-crash-when-deleting-record.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/9649-cloudflare_dns-fix-crash-when-deleting-record.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 19d0049698)

Co-authored-by: valievkarim <valievkarim@gmail.com>
2025-01-31 10:57:23 +01:00
patchback[bot]
163bfd0f37 [PR #9645/37a9413a backport][stable-10] proxmox: fix pubkey translation and usage in update (#9648)
proxmox: fix pubkey translation and usage in update (#9645)

* proxmox: fix: pubkey translation and usage in update

* proxmox fix: add changelog

* proxmox: fix backticks in changelog

(cherry picked from commit 37a9413a80)

Co-authored-by: JL Euler <Lithimlin@users.noreply.github.com>
2025-01-29 20:42:19 +01:00
patchback[bot]
0331798f84 [PR #9633/8749da77 backport][stable-10] onepassword_ssh_key: avoid inheriting from OnePassCLIv2 (#9639)
onepassword_ssh_key: avoid inheriting from OnePassCLIv2 (#9633)

* Avoid inheriting from OnePassCLIv2.

* Add changelog fragment.

(cherry picked from commit 8749da7756)

Co-authored-by: Felix Fontein <felix@fontein.de>
2025-01-27 07:27:43 +01:00
Felix Fontein
2c7940c5de Fix classification of changelog fragment. 2025-01-27 07:06:49 +01:00
Felix Fontein
4ef5c3c11a The next expected release will be 10.4.0. 2025-01-27 07:03:31 +01:00
442 changed files with 14574 additions and 9077 deletions

View File

@@ -43,8 +43,6 @@ variables:
value: ansible_collections/community/general
- name: coverageBranches
value: main
- name: pipelinesCoverage
value: coverage
- name: entryPoint
value: tests/utils/shippable/shippable.sh
- name: fetchDepth
@@ -72,7 +70,6 @@ stages:
- test: 2
- test: 3
- test: 4
- test: extra
- stage: Sanity_2_18
displayName: Sanity 2.18
dependsOn: []
@@ -190,14 +187,14 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- name: macOS 14.3
test: macos/14.3
- name: macOS 15.3
test: macos/15.3
- name: RHEL 9.5
test: rhel/9.5
- name: FreeBSD 14.2
test: freebsd/14.2
- name: FreeBSD 13.4
test: freebsd/13.4
- name: FreeBSD 13.5
test: freebsd/13.5
groups:
- 1
- 2
@@ -210,6 +207,8 @@ stages:
parameters:
testFormat: 2.18/{0}
targets:
- name: macOS 14.3
test: macos/14.3
- name: RHEL 9.4
test: rhel/9.4
- name: FreeBSD 14.1

View File

@@ -28,16 +28,6 @@ jobs:
- bash: .azure-pipelines/scripts/report-coverage.sh
displayName: Generate Coverage Report
condition: gt(variables.coverageFileCount, 0)
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
# Azure Pipelines only accepts a single coverage data file.
# That means only Python or PowerShell coverage can be uploaded, but not both.
# Set the "pipelinesCoverage" variable to determine which type is uploaded.
# Use "coverage" for Python and "coverage-powershell" for PowerShell.
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
displayName: Publish to Azure Pipelines
condition: gt(variables.coverageFileCount, 0)
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
displayName: Publish to codecov.io
condition: gt(variables.coverageFileCount, 0)

12
.github/BOTMETA.yml vendored
View File

@@ -119,6 +119,8 @@ files:
$connections/saltstack.py:
labels: saltstack
maintainers: mscherer
$connections/wsl.py:
maintainers: rgl
$connections/zone.py:
maintainers: $team_ansible_core
$doc_fragments/:
@@ -378,6 +380,8 @@ files:
$module_utils/oracle/oci_utils.py:
labels: cloud
maintainers: $team_oracle
$module_utils/pacemaker.py:
maintainers: munchtoast
$module_utils/pipx.py:
labels: pipx
maintainers: russoz
@@ -402,6 +406,8 @@ files:
maintainers: russoz
$module_utils/ssh.py:
maintainers: russoz
$module_utils/systemd.py:
maintainers: NomakCooper
$module_utils/storage/hpe3par/hpe3par.py:
maintainers: farhan7500 gautamphegde
$module_utils/utm_utils.py:
@@ -1054,6 +1060,8 @@ files:
maintainers: fraff
$modules/pacemaker_cluster.py:
maintainers: matbu
$modules/pacemaker_resource.py:
maintainers: munchtoast
$modules/packet_:
maintainers: nurfet-becirevic t0mk
$modules/packet_device.py:
@@ -1364,6 +1372,8 @@ files:
maintainers: konstruktoid
$modules/systemd_creds_encrypt.py:
maintainers: konstruktoid
$modules/systemd_info.py:
maintainers: NomakCooper
$modules/sysupgrade.py:
maintainers: precurse
$modules/taiga_issue.py:
@@ -1543,6 +1553,8 @@ files:
maintainers: baldwinSPC nurfet-becirevic t0mk teebes
docs/docsite/rst/guide_scaleway.rst:
maintainers: $team_scaleway
docs/docsite/rst/guide_uthelper.rst:
maintainers: russoz
docs/docsite/rst/guide_vardict.rst:
maintainers: russoz
docs/docsite/rst/test_guide.rst:

View File

@@ -45,6 +45,8 @@ jobs:
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
pull-request-change-detection: 'true'
testing-type: sanity
pre-test-cmd: >-
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
units:
# Ansible-test on various stable branches does not yet work well with cgroups v2.
@@ -171,6 +173,8 @@ jobs:
;
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.crypto.git ../../community/crypto
;
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.docker.git ../../community/docker
;
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
pull-request-change-detection: 'true'
target: ${{ matrix.target }}

View File

@@ -1,20 +0,0 @@
---
# 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
name: import-galaxy
'on':
# Run CI against all pushes (direct commits, also merged PRs) to main, and all Pull Requests
push:
branches:
- main
- stable-*
pull_request:
jobs:
import-galaxy:
permissions:
contents: read
name: Test to import built collection artifact with Galaxy importer
uses: ansible-community/github-action-test-galaxy-import/.github/workflows/test-galaxy-import.yml@main

28
.github/workflows/nox.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
---
# 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
name: nox
'on':
push:
branches:
- main
- stable-*
pull_request:
# Run CI once per day (at 08:00 UTC)
schedule:
- cron: '0 8 * * *'
workflow_dispatch:
jobs:
nox:
runs-on: ubuntu-latest
name: "Run extra sanity tests"
steps:
- name: Check out collection
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run nox
uses: ansible-community/antsibull-nox@main

View File

@@ -1,35 +0,0 @@
---
# 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
name: Verify REUSE
on:
push:
branches:
- main
- stable-*
pull_request:
types: [opened, synchronize, reopened]
branches:
- main
- stable-*
# Run CI once per day (at 07:30 UTC)
schedule:
- cron: '30 7 * * *'
jobs:
check:
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || '' }}
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v5

View File

@@ -1,5 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: changelogs/fragments/*
Copyright: Ansible Project
License: GPL-3.0-or-later

View File

@@ -2,68 +2,286 @@
**Topics**
- <a href="#v10-3-0">v10\.3\.0</a>
- <a href="#v10-6-0">v10\.6\.0</a>
- <a href="#release-summary">Release Summary</a>
- <a href="#major-changes">Major Changes</a>
- <a href="#minor-changes">Minor Changes</a>
- <a href="#deprecated-features">Deprecated Features</a>
- <a href="#security-fixes">Security Fixes</a>
- <a href="#bugfixes">Bugfixes</a>
- <a href="#known-issues">Known Issues</a>
- <a href="#new-plugins">New Plugins</a>
- <a href="#connection">Connection</a>
- <a href="#filter">Filter</a>
- <a href="#lookup">Lookup</a>
- <a href="#new-modules">New Modules</a>
- <a href="#v10-2-0">v10\.2\.0</a>
- <a href="#v10-5-0">v10\.5\.0</a>
- <a href="#release-summary-1">Release Summary</a>
- <a href="#minor-changes-1">Minor Changes</a>
- <a href="#deprecated-features-1">Deprecated Features</a>
- <a href="#security-fixes-1">Security Fixes</a>
- <a href="#bugfixes-1">Bugfixes</a>
- <a href="#new-plugins-1">New Plugins</a>
- <a href="#inventory">Inventory</a>
- <a href="#new-modules-1">New Modules</a>
- <a href="#v10-1-0">v10\.1\.0</a>
- <a href="#new-modules">New Modules</a>
- <a href="#v10-4-0">v10\.4\.0</a>
- <a href="#release-summary-2">Release Summary</a>
- <a href="#minor-changes-2">Minor Changes</a>
- <a href="#deprecated-features-2">Deprecated Features</a>
- <a href="#deprecated-features-1">Deprecated Features</a>
- <a href="#bugfixes-2">Bugfixes</a>
- <a href="#new-plugins-2">New Plugins</a>
- <a href="#filter-1">Filter</a>
- <a href="#new-modules-2">New Modules</a>
- <a href="#v10-0-1">v10\.0\.1</a>
- <a href="#new-modules-1">New Modules</a>
- <a href="#v10-3-1">v10\.3\.1</a>
- <a href="#release-summary-3">Release Summary</a>
- <a href="#bugfixes-3">Bugfixes</a>
- <a href="#v10-0-0">v10\.0\.0</a>
- <a href="#release-summary-4">Release Summary</a>
- <a href="#minor-changes-3">Minor Changes</a>
- <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
- <a href="#deprecated-features-3">Deprecated Features</a>
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
- <a href="#bugfixes-3">Bugfixes</a>
- <a href="#v10-3-0">v10\.3\.0</a>
- <a href="#release-summary-4">Release Summary</a>
- <a href="#minor-changes-4">Minor Changes</a>
- <a href="#deprecated-features-2">Deprecated Features</a>
- <a href="#security-fixes">Security Fixes</a>
- <a href="#bugfixes-4">Bugfixes</a>
- <a href="#known-issues">Known Issues</a>
- <a href="#new-plugins-1">New Plugins</a>
- <a href="#connection-1">Connection</a>
- <a href="#filter">Filter</a>
- <a href="#lookup">Lookup</a>
- <a href="#new-modules-2">New Modules</a>
- <a href="#v10-2-0">v10\.2\.0</a>
- <a href="#release-summary-5">Release Summary</a>
- <a href="#minor-changes-5">Minor Changes</a>
- <a href="#deprecated-features-3">Deprecated Features</a>
- <a href="#security-fixes-1">Security Fixes</a>
- <a href="#bugfixes-5">Bugfixes</a>
- <a href="#new-plugins-2">New Plugins</a>
- <a href="#inventory">Inventory</a>
- <a href="#new-modules-3">New Modules</a>
- <a href="#v10-1-0">v10\.1\.0</a>
- <a href="#release-summary-6">Release Summary</a>
- <a href="#minor-changes-6">Minor Changes</a>
- <a href="#deprecated-features-4">Deprecated Features</a>
- <a href="#bugfixes-6">Bugfixes</a>
- <a href="#new-plugins-3">New Plugins</a>
- <a href="#filter-1">Filter</a>
- <a href="#new-modules-4">New Modules</a>
- <a href="#v10-0-1">v10\.0\.1</a>
- <a href="#release-summary-7">Release Summary</a>
- <a href="#bugfixes-7">Bugfixes</a>
- <a href="#v10-0-0">v10\.0\.0</a>
- <a href="#release-summary-8">Release Summary</a>
- <a href="#minor-changes-7">Minor Changes</a>
- <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
- <a href="#deprecated-features-5">Deprecated Features</a>
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
- <a href="#bugfixes-8">Bugfixes</a>
- <a href="#known-issues-1">Known Issues</a>
- <a href="#new-plugins-4">New Plugins</a>
- <a href="#filter-2">Filter</a>
- <a href="#test">Test</a>
- <a href="#new-modules-3">New Modules</a>
- <a href="#new-modules-5">New Modules</a>
This changelog describes changes after version 9\.0\.0\.
<a id="v10-3-0"></a>
## v10\.3\.0
<a id="v10-6-0"></a>
## v10\.6\.0
<a id="release-summary"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="major-changes"></a>
### Major Changes
* keycloak\_\* modules \- <code>refresh\_token</code> parameter added\. When multiple authentication parameters are provided \(<code>token</code>\, <code>refresh\_token</code>\, and <code>auth\_username</code>/<code>auth\_password</code>\)\, modules will now automatically retry requests upon authentication errors \(401\)\, using in order the token\, refresh token\, and username/password \([https\://github\.com/ansible\-collections/community\.general/pull/9494](https\://github\.com/ansible\-collections/community\.general/pull/9494)\)\.
<a id="minor-changes"></a>
### Minor Changes
* apache2\_module \- added workaround for new PHP module name\, from <code>php7\_module</code> to <code>php\_module</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9951](https\://github\.com/ansible\-collections/community\.general/pull/9951)\)\.
* gitlab\_project \- add option <code>build\_timeout</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9960](https\://github\.com/ansible\-collections/community\.general/pull/9960)\)\.
* gitlab\_project\_members \- extend choices parameter <code>access\_level</code> by missing upstream valid value <code>owner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9953](https\://github\.com/ansible\-collections/community\.general/pull/9953)\)\.
* hpilo\_boot \- add option to get an idempotent behavior while powering on server\, resulting in success instead of failure when using <code>state\: boot\_once</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9646](https\://github\.com/ansible\-collections/community\.general/pull/9646)\)\.
* idrac\_redfish\_command\, idrac\_redfish\_config\, idrac\_redfish\_info \- add <code>validate\_certs</code>\, <code>ca\_path</code>\, and <code>ciphers</code> options to configure TLS/SSL \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* ilo\_redfish\_command\, ilo\_redfish\_config\, ilo\_redfish\_info \- add <code>validate\_certs</code>\, <code>ca\_path</code>\, and <code>ciphers</code> options to configure TLS/SSL \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* keycloak module\_utils \- user groups can now be referenced by their name\, like <code>staff</code>\, or their path\, like <code>/staff/engineering</code>\. The path syntax allows users to reference subgroups\, which is not possible otherwise \([https\://github\.com/ansible\-collections/community\.general/pull/9898](https\://github\.com/ansible\-collections/community\.general/pull/9898)\)\.
* keycloak\_user module \- user groups can now be referenced by their name\, like <code>staff</code>\, or their path\, like <code>/staff/engineering</code>\. The path syntax allows users to reference subgroups\, which is not possible otherwise \([https\://github\.com/ansible\-collections/community\.general/pull/9898](https\://github\.com/ansible\-collections/community\.general/pull/9898)\)\.
* nmcli \- add support for Infiniband MAC setting when <code>type</code> is <code>infiniband</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9962](https\://github\.com/ansible\-collections/community\.general/pull/9962)\)\.
* one\_vm \- update allowed values for <code>updateconf</code> to include new parameters as per the latest OpenNebula API documentation\.
Added parameters\:
- <code>OS</code>\: <code>FIRMWARE</code>\;
- <code>CPU\_MODEL</code>\: <code>MODEL</code>\, <code>FEATURES</code>\;
- <code>FEATURES</code>\: <code>VIRTIO\_BLK\_QUEUES</code>\, <code>VIRTIO\_SCSI\_QUEUES</code>\, <code>IOTHREADS</code>\;
- <code>GRAPHICS</code>\: <code>PORT</code>\, <code>COMMAND</code>\;
- <code>VIDEO</code>\: <code>ATS</code>\, <code>IOMMU</code>\, <code>RESOLUTION</code>\, <code>TYPE</code>\, <code>VRAM</code>\;
- <code>RAW</code>\: <code>VALIDATE</code>\;
- <code>BACKUP\_CONFIG</code>\: <code>FS\_FREEZE</code>\, <code>KEEP\_LAST</code>\, <code>BACKUP\_VOLATILE</code>\, <code>MODE</code>\, <code>INCREMENT\_MODE</code>\.
\([https\://github\.com/ansible\-collections/community\.general/pull/9959](https\://github\.com/ansible\-collections/community\.general/pull/9959)\)\.
* proxmox and proxmox\_kvm modules \- allow uppercase characters in VM/container tags \([https\://github\.com/ansible\-collections/community\.general/issues/9895](https\://github\.com/ansible\-collections/community\.general/issues/9895)\, [https\://github\.com/ansible\-collections/community\.general/pull/10024](https\://github\.com/ansible\-collections/community\.general/pull/10024)\)\.
* puppet \- improve parameter formatting\, no impact to user \([https\://github\.com/ansible\-collections/community\.general/pull/10014](https\://github\.com/ansible\-collections/community\.general/pull/10014)\)\.
* redfish module utils \- add <code>REDFISH\_COMMON\_ARGUMENT\_SPEC</code>\, a corresponding <code>redfish</code> docs fragment\, and support for its <code>validate\_certs</code>\, <code>ca\_path</code>\, and <code>ciphers</code> options \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* redfish\_command\, redfish\_config\, redfish\_info \- add <code>validate\_certs</code> and <code>ca\_path</code> options to configure TLS/SSL \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* rocketchat \- fix duplicate JSON conversion for Rocket\.Chat \< 7\.4\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9965](https\://github\.com/ansible\-collections/community\.general/pull/9965)\)\.
* wdc\_redfish\_command\, wdc\_redfish\_info \- add <code>validate\_certs</code>\, <code>ca\_path</code>\, and <code>ciphers</code> options to configure TLS/SSL \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* xcc\_redfish\_command \- add <code>validate\_certs</code>\, <code>ca\_path</code>\, and <code>ciphers</code> options to configure TLS/SSL \([https\://github\.com/ansible\-collections/community\.general/issues/3686](https\://github\.com/ansible\-collections/community\.general/issues/3686)\, [https\://github\.com/ansible\-collections/community\.general/pull/9964](https\://github\.com/ansible\-collections/community\.general/pull/9964)\)\.
* zypper \- adds <code>skip\_post\_errors</code> that allows to skip RPM post\-install errors \(Zypper return code 107\) \([https\://github\.com/ansible\-collections/community\.general/issues/9972](https\://github\.com/ansible\-collections/community\.general/issues/9972)\)\.
<a id="deprecated-features"></a>
### Deprecated Features
* manifold lookup plugin \- plugin is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/10028](https\://github\.com/ansible\-collections/community\.general/pull/10028)\)\.
* stackpath\_compute inventory plugin \- plugin is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/10026](https\://github\.com/ansible\-collections/community\.general/pull/10026)\)\.
<a id="bugfixes"></a>
### Bugfixes
* dependent look plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
* diy callback plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
* github\_deploy\_key \- check that key really exists on 422 to avoid masking other errors \([https\://github\.com/ansible\-collections/community\.general/issues/6718](https\://github\.com/ansible\-collections/community\.general/issues/6718)\, [https\://github\.com/ansible\-collections/community\.general/pull/10011](https\://github\.com/ansible\-collections/community\.general/pull/10011)\)\.
* hashids and unicode\_normalize filter plugins \- avoid deprecated <code>AnsibleFilterTypeError</code> on ansible\-core 2\.19 \([https\://github\.com/ansible\-collections/community\.general/pull/9992](https\://github\.com/ansible\-collections/community\.general/pull/9992)\)\.
* homebrew \- emit a useful error message if <code>brew info</code> reports a package tap is <code>null</code> \([https\://github\.com/ansible\-collections/community\.general/pull/10013](https\://github\.com/ansible\-collections/community\.general/pull/10013)\, [https\://github\.com/ansible\-collections/community\.general/issues/10012](https\://github\.com/ansible\-collections/community\.general/issues/10012)\)\.
* java\_cert \- the module no longer fails if the optional parameters <code>pkcs12\_alias</code> and <code>cert\_alias</code> are not provided \([https\://github\.com/ansible\-collections/community\.general/pull/9970](https\://github\.com/ansible\-collections/community\.general/pull/9970)\)\.
* keycloak\_authentication \- fix authentification config duplication for Keycloak \< 26\.2\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9987](https\://github\.com/ansible\-collections/community\.general/pull/9987)\)\.
* keycloak\_client \- fix the idempotency regression by normalizing the Keycloak response for <code>after\_client</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9905](https\://github\.com/ansible\-collections/community\.general/issues/9905)\, [https\://github\.com/ansible\-collections/community\.general/pull/9976](https\://github\.com/ansible\-collections/community\.general/pull/9976)\)\.
* proxmox inventory plugin \- fix <code>ansible\_host</code> staying empty for certain Proxmox nodes \([https\://github\.com/ansible\-collections/community\.general/issues/5906](https\://github\.com/ansible\-collections/community\.general/issues/5906)\, [https\://github\.com/ansible\-collections/community\.general/pull/9952](https\://github\.com/ansible\-collections/community\.general/pull/9952)\)\.
* proxmox\_disk \- fail gracefully if <code>storage</code> is required but not provided by the user \([https\://github\.com/ansible\-collections/community\.general/issues/9941](https\://github\.com/ansible\-collections/community\.general/issues/9941)\, [https\://github\.com/ansible\-collections/community\.general/pull/9963](https\://github\.com/ansible\-collections/community\.general/pull/9963)\)\.
* reveal\_ansible\_type filter plugin and ansible\_type test plugin \- make compatible with ansible\-core\'s Data Tagging feature \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
* sysrc \- no longer always reporting <code>changed\=true</code> when <code>state\=absent</code>\. This fixes the method <code>exists\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/issues/10004](https\://github\.com/ansible\-collections/community\.general/issues/10004)\, [https\://github\.com/ansible\-collections/community\.general/pull/10005](https\://github\.com/ansible\-collections/community\.general/pull/10005)\)\.
* yaml callback plugin \- use ansible\-core internals to avoid breakage with Data Tagging \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
<a id="known-issues"></a>
### Known Issues
* reveal\_ansible\_type filter plugin and ansible\_type test plugin \- note that ansible\-core\'s Data Tagging feature implements new aliases\, such as <code>\_AnsibleTaggedStr</code> for <code>str</code>\, <code>\_AnsibleTaggedInt</code> for <code>int</code>\, and <code>\_AnsibleTaggedFloat</code> for <code>float</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9833](https\://github\.com/ansible\-collections/community\.general/pull/9833)\)\.
<a id="new-plugins"></a>
### New Plugins
<a id="connection"></a>
#### Connection
* community\.general\.wsl \- Run tasks in WSL distribution using wsl\.exe CLI via SSH\.
<a id="v10-5-0"></a>
## v10\.5\.0
<a id="release-summary-1"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-1"></a>
### Minor Changes
* CmdRunner module utils \- the convenience method <code>cmd\_runner\_fmt\.as\_fixed\(\)</code> now accepts multiple arguments as a list \([https\://github\.com/ansible\-collections/community\.general/pull/9893](https\://github\.com/ansible\-collections/community\.general/pull/9893)\)\.
* apache2\_mod\_proxy \- code simplification\, no change in functionality \([https\://github\.com/ansible\-collections/community\.general/pull/9457](https\://github\.com/ansible\-collections/community\.general/pull/9457)\)\.
* consul\_token \- fix idempotency when <code>policies</code> or <code>roles</code> are supplied by name \([https\://github\.com/ansible\-collections/community\.general/issues/9841](https\://github\.com/ansible\-collections/community\.general/issues/9841)\, [https\://github\.com/ansible\-collections/community\.general/pull/9845](https\://github\.com/ansible\-collections/community\.general/pull/9845)\)\.
* keycloak\_realm \- remove ID requirement when creating a realm to allow Keycloak generating its own realm ID \([https\://github\.com/ansible\-collections/community\.general/pull/9768](https\://github\.com/ansible\-collections/community\.general/pull/9768)\)\.
* nmap inventory plugin \- adds <code>dns\_servers</code> option for specifying DNS servers for name resolution\. Accepts hostnames or IP addresses in the same format as the <code>exclude</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9849](https\://github\.com/ansible\-collections/community\.general/pull/9849)\)\.
* proxmox\_kvm \- add missing audio hardware device handling \([https\://github\.com/ansible\-collections/community\.general/issues/5192](https\://github\.com/ansible\-collections/community\.general/issues/5192)\, [https\://github\.com/ansible\-collections/community\.general/pull/9847](https\://github\.com/ansible\-collections/community\.general/pull/9847)\)\.
* redfish\_config \- add command <code>SetPowerRestorePolicy</code> to set the desired power state of the system when power is restored \([https\://github\.com/ansible\-collections/community\.general/pull/9837](https\://github\.com/ansible\-collections/community\.general/pull/9837)\)\.
* redfish\_info \- add command <code>GetPowerRestorePolicy</code> to get the desired power state of the system when power is restored \([https\://github\.com/ansible\-collections/community\.general/pull/9824](https\://github\.com/ansible\-collections/community\.general/pull/9824)\)\.
* rocketchat \- option <code>is\_pre740</code> has been added to control the format of the payload\. For Rocket\.Chat 7\.4\.0 or newer\, it must be set to <code>false</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9882](https\://github\.com/ansible\-collections/community\.general/pull/9882)\)\.
* slack callback plugin \- add <code>http\_agent</code> option to enable the user to set a custom user agent for slack callback plugin \([https\://github\.com/ansible\-collections/community\.general/issues/9813](https\://github\.com/ansible\-collections/community\.general/issues/9813)\, [https\://github\.com/ansible\-collections/community\.general/pull/9836](https\://github\.com/ansible\-collections/community\.general/pull/9836)\)\.
* systemd\_info \- add wildcard expression support in <code>unitname</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9821](https\://github\.com/ansible\-collections/community\.general/pull/9821)\)\.
* systemd\_info \- extend support to timer units \([https\://github\.com/ansible\-collections/community\.general/pull/9891](https\://github\.com/ansible\-collections/community\.general/pull/9891)\)\.
* vmadm \- add new options <code>flexible\_disk\_size</code> and <code>owner\_uuid</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9892](https\://github\.com/ansible\-collections/community\.general/pull/9892)\)\.
<a id="bugfixes-1"></a>
### Bugfixes
* cloudlare\_dns \- handle exhausted response stream in case of HTTP errors to show nice error message to the user \([https\://github\.com/ansible\-collections/community\.general/issues/9782](https\://github\.com/ansible\-collections/community\.general/issues/9782)\, [https\://github\.com/ansible\-collections/community\.general/pull/9818](https\://github\.com/ansible\-collections/community\.general/pull/9818)\)\.
* dnf\_versionlock \- add support for dnf5 \([https\://github\.com/ansible\-collections/community\.general/issues/9556](https\://github\.com/ansible\-collections/community\.general/issues/9556)\)\.
* homebrew \- fix crash when package names include tap \([https\://github\.com/ansible\-collections/community\.general/issues/9777](https\://github\.com/ansible\-collections/community\.general/issues/9777)\, [https\://github\.com/ansible\-collections/community\.general/pull/9803](https\://github\.com/ansible\-collections/community\.general/pull/9803)\)\.
* homebrew\_cask \- handle unusual brew version strings \([https\://github\.com/ansible\-collections/community\.general/issues/8432](https\://github\.com/ansible\-collections/community\.general/issues/8432)\, [https\://github\.com/ansible\-collections/community\.general/pull/9881](https\://github\.com/ansible\-collections/community\.general/pull/9881)\)\.
* nmcli \- enable changing only the order of DNS servers or search suffixes \([https\://github\.com/ansible\-collections/community\.general/issues/8724](https\://github\.com/ansible\-collections/community\.general/issues/8724)\, [https\://github\.com/ansible\-collections/community\.general/pull/9880](https\://github\.com/ansible\-collections/community\.general/pull/9880)\)\.
* proxmox \- add missing key selection of <code>\'status\'</code> key to <code>get\_lxc\_status</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9696](https\://github\.com/ansible\-collections/community\.general/issues/9696)\, [https\://github\.com/ansible\-collections/community\.general/pull/9809](https\://github\.com/ansible\-collections/community\.general/pull/9809)\)\.
* proxmox\_vm\_info \- the module no longer expects that the key <code>template</code> exists in a dictionary returned by Proxmox \([https\://github\.com/ansible\-collections/community\.general/issues/9875](https\://github\.com/ansible\-collections/community\.general/issues/9875)\, [https\://github\.com/ansible\-collections/community\.general/pull/9910](https\://github\.com/ansible\-collections/community\.general/pull/9910)\)\.
* sudoers \- display stdout and stderr raised while failed validation \([https\://github\.com/ansible\-collections/community\.general/issues/9674](https\://github\.com/ansible\-collections/community\.general/issues/9674)\, [https\://github\.com/ansible\-collections/community\.general/pull/9871](https\://github\.com/ansible\-collections/community\.general/pull/9871)\)\.
<a id="new-modules"></a>
### New Modules
* community\.general\.pacemaker\_resource \- Manage pacemaker resources\.
<a id="v10-4-0"></a>
## v10\.4\.0
<a id="release-summary-2"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-2"></a>
### Minor Changes
* bitwarden lookup plugin \- add new option <code>collection\_name</code> to filter results by collection name\, and new option <code>result\_count</code> to validate number of results \([https\://github\.com/ansible\-collections/community\.general/pull/9728](https\://github\.com/ansible\-collections/community\.general/pull/9728)\)\.
* incus connection plugin \- adds <code>remote\_user</code> and <code>incus\_become\_method</code> parameters for allowing a non\-root user to connect to an Incus instance \([https\://github\.com/ansible\-collections/community\.general/pull/9743](https\://github\.com/ansible\-collections/community\.general/pull/9743)\)\.
* iocage inventory plugin \- the new parameter <code>hooks\_results</code> of the plugin is a list of files inside a jail that provide configuration parameters for the inventory\. The inventory plugin reads the files from the jails and put the contents into the items of created variable <code>iocage\_hooks</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9650](https\://github\.com/ansible\-collections/community\.general/issues/9650)\, [https\://github\.com/ansible\-collections/community\.general/pull/9651](https\://github\.com/ansible\-collections/community\.general/pull/9651)\)\.
* jira \- adds <code>client\_cert</code> and <code>client\_key</code> parameters for supporting client certificate authentification when connecting to Jira \([https\://github\.com/ansible\-collections/community\.general/pull/9753](https\://github\.com/ansible\-collections/community\.general/pull/9753)\)\.
* lldp \- adds <code>multivalues</code> parameter to control behavior when lldpctl outputs an attribute multiple times \([https\://github\.com/ansible\-collections/community\.general/pull/9657](https\://github\.com/ansible\-collections/community\.general/pull/9657)\)\.
* lvg \- add <code>remove\_extra\_pvs</code> parameter to control if ansible should remove physical volumes which are not in the <code>pvs</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/9698](https\://github\.com/ansible\-collections/community\.general/pull/9698)\)\.
* lxd connection plugin \- adds <code>remote\_user</code> and <code>lxd\_become\_method</code> parameters for allowing a non\-root user to connect to an LXD instance \([https\://github\.com/ansible\-collections/community\.general/pull/9659](https\://github\.com/ansible\-collections/community\.general/pull/9659)\)\.
* nmcli \- adds VRF support with new <code>type</code> value <code>vrf</code> and new <code>slave\_type</code> value <code>vrf</code> as well as new <code>table</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/9658](https\://github\.com/ansible\-collections/community\.general/pull/9658)\, [https\://github\.com/ansible\-collections/community\.general/issues/8014](https\://github\.com/ansible\-collections/community\.general/issues/8014)\)\.
* proxmox\_kvm \- allow hibernation and suspending of VMs \([https\://github\.com/ansible\-collections/community\.general/issues/9620](https\://github\.com/ansible\-collections/community\.general/issues/9620)\, [https\://github\.com/ansible\-collections/community\.general/pull/9653](https\://github\.com/ansible\-collections/community\.general/pull/9653)\)\.
* redfish\_command \- add <code>PowerFullPowerCycle</code> to power command options \([https\://github\.com/ansible\-collections/community\.general/pull/9729](https\://github\.com/ansible\-collections/community\.general/pull/9729)\)\.
* ssh\_config \- add <code>other\_options</code> option \([https\://github\.com/ansible\-collections/community\.general/issues/8053](https\://github\.com/ansible\-collections/community\.general/issues/8053)\, [https\://github\.com/ansible\-collections/community\.general/pull/9684](https\://github\.com/ansible\-collections/community\.general/pull/9684)\)\.
* xen\_orchestra inventory plugin \- add <code>use\_vm\_uuid</code> and <code>use\_host\_uuid</code> boolean options to allow switching over to using VM/Xen name labels instead of UUIDs as item names \([https\://github\.com/ansible\-collections/community\.general/pull/9787](https\://github\.com/ansible\-collections/community\.general/pull/9787)\)\.
<a id="deprecated-features-1"></a>
### Deprecated Features
* profitbricks \- module is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9733](https\://github\.com/ansible\-collections/community\.general/pull/9733)\)\.
* profitbricks\_datacenter \- module is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9733](https\://github\.com/ansible\-collections/community\.general/pull/9733)\)\.
* profitbricks\_nic \- module is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9733](https\://github\.com/ansible\-collections/community\.general/pull/9733)\)\.
* profitbricks\_volume \- module is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9733](https\://github\.com/ansible\-collections/community\.general/pull/9733)\)\.
* profitbricks\_volume\_attachments \- module is deprecated and will be removed in community\.general 11\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9733](https\://github\.com/ansible\-collections/community\.general/pull/9733)\)\.
<a id="bugfixes-2"></a>
### Bugfixes
* apache2\_mod\_proxy \- make compatible with Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9762](https\://github\.com/ansible\-collections/community\.general/pull/9762)\)\.
* apache2\_mod\_proxy \- passing the cluster\'s page as referer for the member\'s pages\. This makes the module actually work again for halfway modern Apache versions\. According to some comments founds on the net the referer was required since at least 2019 for some versions of Apache 2 \([https\://github\.com/ansible\-collections/community\.general/pull/9762](https\://github\.com/ansible\-collections/community\.general/pull/9762)\)\.
* elasticsearch\_plugin \- fix <code>ERROR\: D is not a recognized option</code> issue when configuring proxy settings \([https\://github\.com/ansible\-collections/community\.general/pull/9774](https\://github\.com/ansible\-collections/community\.general/pull/9774)\, [https\://github\.com/ansible\-collections/community\.general/issues/9773](https\://github\.com/ansible\-collections/community\.general/issues/9773)\)\.
* ipa\_host \- module revoked existing host certificates even if <code>user\_certificate</code> was not given \([https\://github\.com/ansible\-collections/community\.general/pull/9694](https\://github\.com/ansible\-collections/community\.general/pull/9694)\)\.
* keycloak\_client \- in check mode\, detect whether the lists in before client \(for example redirect URI list\) contain items that the lists in the desired client do not contain \([https\://github\.com/ansible\-collections/community\.general/pull/9739](https\://github\.com/ansible\-collections/community\.general/pull/9739)\)\.
* lldp \- fix crash caused by certain lldpctl output where an attribute is defined as branch and leaf \([https\://github\.com/ansible\-collections/community\.general/pull/9657](https\://github\.com/ansible\-collections/community\.general/pull/9657)\)\.
* onepassword\_doc lookup plugin \- ensure that 1Password Connect support also works for this plugin \([https\://github\.com/ansible\-collections/community\.general/pull/9625](https\://github\.com/ansible\-collections/community\.general/pull/9625)\)\.
* passwordstore lookup plugin \- fix subkey creation even when <code>create\=false</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9105](https\://github\.com/ansible\-collections/community\.general/issues/9105)\, [https\://github\.com/ansible\-collections/community\.general/pull/9106](https\://github\.com/ansible\-collections/community\.general/pull/9106)\)\.
* proxmox inventory plugin \- plugin did not update cache correctly after <code>meta\: refresh\_inventory</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9710](https\://github\.com/ansible\-collections/community\.general/issues/9710)\, [https\://github\.com/ansible\-collections/community\.general/pull/9760](https\://github\.com/ansible\-collections/community\.general/pull/9760)\)\.
* redhat\_subscription \- use the \"enable\_content\" option \(when available\) when
registering using D\-Bus\, to ensure that subscription\-manager enables the
content on registration\; this is particular important on EL 10\+ and Fedora
41\+
\([https\://github\.com/ansible\-collections/community\.general/pull/9778](https\://github\.com/ansible\-collections/community\.general/pull/9778)\)\.
* zfs \- fix handling of multi\-line values of user\-defined ZFS properties \([https\://github\.com/ansible\-collections/community\.general/pull/6264](https\://github\.com/ansible\-collections/community\.general/pull/6264)\)\.
* zfs\_facts \- parameter <code>type</code> now accepts multple values as documented \([https\://github\.com/ansible\-collections/community\.general/issues/5909](https\://github\.com/ansible\-collections/community\.general/issues/5909)\, [https\://github\.com/ansible\-collections/community\.general/pull/9697](https\://github\.com/ansible\-collections/community\.general/pull/9697)\)\.
<a id="new-modules-1"></a>
### New Modules
* community\.general\.systemd\_info \- Gather C\(systemd\) unit info\.
<a id="v10-3-1"></a>
## v10\.3\.1
<a id="release-summary-3"></a>
### Release Summary
Bugfix release\.
<a id="minor-changes-3"></a>
### Minor Changes
* onepassword\_ssh\_key \- refactor to move code to lookup class \([https\://github\.com/ansible\-collections/community\.general/pull/9633](https\://github\.com/ansible\-collections/community\.general/pull/9633)\)\.
<a id="bugfixes-3"></a>
### Bugfixes
* cloudflare\_dns \- fix crash when deleting a DNS record or when updating a record with <code>solo\=true</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9652](https\://github\.com/ansible\-collections/community\.general/issues/9652)\, [https\://github\.com/ansible\-collections/community\.general/pull/9649](https\://github\.com/ansible\-collections/community\.general/pull/9649)\)\.
* homebrew \- make package name parsing more resilient \([https\://github\.com/ansible\-collections/community\.general/pull/9665](https\://github\.com/ansible\-collections/community\.general/pull/9665)\, [https\://github\.com/ansible\-collections/community\.general/issues/9641](https\://github\.com/ansible\-collections/community\.general/issues/9641)\)\.
* keycloak module utils \- replaces missing return in get\_role\_composites method which caused it to return None instead of composite roles \([https\://github\.com/ansible\-collections/community\.general/issues/9678](https\://github\.com/ansible\-collections/community\.general/issues/9678)\, [https\://github\.com/ansible\-collections/community\.general/pull/9691](https\://github\.com/ansible\-collections/community\.general/pull/9691)\)\.
* keycloak\_client \- fix and improve existing tests\. The module showed a diff without actual changes\, solved by improving the <code>normalise\_cr\(\)</code> function \([https\://github\.com/ansible\-collections/community\.general/pull/9644](https\://github\.com/ansible\-collections/community\.general/pull/9644)\)\.
* proxmox \- adds the <code>pubkey</code> parameter \(back to\) the <code>update</code> state \([https\://github\.com/ansible\-collections/community\.general/issues/9642](https\://github\.com/ansible\-collections/community\.general/issues/9642)\, [https\://github\.com/ansible\-collections/community\.general/pull/9645](https\://github\.com/ansible\-collections/community\.general/pull/9645)\)\.
* proxmox \- fixes a typo in the translation of the <code>pubkey</code> parameter to proxmox\' <code>ssh\-public\-keys</code> \([https\://github\.com/ansible\-collections/community\.general/issues/9642](https\://github\.com/ansible\-collections/community\.general/issues/9642)\, [https\://github\.com/ansible\-collections/community\.general/pull/9645](https\://github\.com/ansible\-collections/community\.general/pull/9645)\)\.
* xml \- ensure file descriptor is closed \([https\://github\.com/ansible\-collections/community\.general/pull/9695](https\://github\.com/ansible\-collections/community\.general/pull/9695)\)\.
<a id="v10-3-0"></a>
## v10\.3\.0
<a id="release-summary-4"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-4"></a>
### Minor Changes
* MH module utils \- delegate <code>debug</code> to the underlying <code>AnsibleModule</code> instance or issues a warning if an attribute already exists with that name \([https\://github\.com/ansible\-collections/community\.general/pull/9577](https\://github\.com/ansible\-collections/community\.general/pull/9577)\)\.
* apache2\_mod\_proxy \- better handling regexp extraction \([https\://github\.com/ansible\-collections/community\.general/pull/9609](https\://github\.com/ansible\-collections/community\.general/pull/9609)\)\.
* apache2\_mod\_proxy \- change type of <code>state</code> to a list of strings\. No change for the users \([https\://github\.com/ansible\-collections/community\.general/pull/9600](https\://github\.com/ansible\-collections/community\.general/pull/9600)\)\.
@@ -110,6 +328,7 @@ Regular bugfix and feature release\.
* jira \- transition operation now has <code>status\_id</code> to directly reference wanted transition \([https\://github\.com/ansible\-collections/community\.general/pull/9602](https\://github\.com/ansible\-collections/community\.general/pull/9602)\)\.
* json\_query filter plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9585](https\://github\.com/ansible\-collections/community\.general/pull/9585)\)\.
* keep\_keys filter plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9585](https\://github\.com/ansible\-collections/community\.general/pull/9585)\)\.
* keycloak\_\* modules \- <code>refresh\_token</code> parameter added\. When multiple authentication parameters are provided \(<code>token</code>\, <code>refresh\_token</code>\, and <code>auth\_username</code>/<code>auth\_password</code>\)\, modules will now automatically retry requests upon authentication errors \(401\)\, using in order the token\, refresh token\, and username/password \([https\://github\.com/ansible\-collections/community\.general/pull/9494](https\://github\.com/ansible\-collections/community\.general/pull/9494)\)\.
* known\_hosts \- open file using <code>open\(\)</code> as a context manager \([https\://github\.com/ansible\-collections/community\.general/pull/9579](https\://github\.com/ansible\-collections/community\.general/pull/9579)\)\.
* ksu become plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9583](https\://github\.com/ansible\-collections/community\.general/pull/9583)\)\.
* linode inventory plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9584](https\://github\.com/ansible\-collections/community\.general/pull/9584)\)\.
@@ -183,7 +402,7 @@ Regular bugfix and feature release\.
* yaml callback plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9583](https\://github\.com/ansible\-collections/community\.general/pull/9583)\)\.
* zone connection plugin \- adjust standard preamble for Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/9584](https\://github\.com/ansible\-collections/community\.general/pull/9584)\)\.
<a id="deprecated-features"></a>
<a id="deprecated-features-2"></a>
### Deprecated Features
* MH module utils \- attribute <code>debug</code> definition in subclasses of MH is now deprecated\, as that name will become a delegation to <code>AnsibleModule</code> in community\.general 12\.0\.0\, and any such attribute will be overridden by that delegation in that version \([https\://github\.com/ansible\-collections/community\.general/pull/9577](https\://github\.com/ansible\-collections/community\.general/pull/9577)\)\.
@@ -194,7 +413,7 @@ Regular bugfix and feature release\.
* keycloak\_client \- Sanitize <code>saml\.encryption\.private\.key</code> so it does not show in the logs \([https\://github\.com/ansible\-collections/community\.general/pull/9621](https\://github\.com/ansible\-collections/community\.general/pull/9621)\)\.
<a id="bugfixes"></a>
<a id="bugfixes-4"></a>
### Bugfixes
* homebrew \- fix incorrect handling of homebrew modules when a tap is requested \([https\://github\.com/ansible\-collections/community\.general/pull/9546](https\://github\.com/ansible\-collections/community\.general/pull/9546)\, [https\://github\.com/ansible\-collections/community\.general/issues/9533](https\://github\.com/ansible\-collections/community\.general/issues/9533)\)\.
@@ -210,10 +429,10 @@ Regular bugfix and feature release\.
thus unsubscribing will fail
\([https\://github\.com/ansible\-collections/community\.general/pull/9578](https\://github\.com/ansible\-collections/community\.general/pull/9578)\)\.
<a id="new-plugins"></a>
<a id="new-plugins-1"></a>
### New Plugins
<a id="connection"></a>
<a id="connection-1"></a>
#### Connection
* community\.general\.proxmox\_pct\_remote \- Run tasks in Proxmox LXC container instances using pct CLI via SSH\.
@@ -230,7 +449,7 @@ Regular bugfix and feature release\.
* community\.general\.onepassword\_ssh\_key \- Fetch SSH keys stored in 1Password\.
<a id="new-modules"></a>
<a id="new-modules-2"></a>
### New Modules
* community\.general\.proxmox\_backup\_info \- Retrieve information on Proxmox scheduled backups\.
@@ -238,12 +457,12 @@ Regular bugfix and feature release\.
<a id="v10-2-0"></a>
## v10\.2\.0
<a id="release-summary-1"></a>
<a id="release-summary-5"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-1"></a>
<a id="minor-changes-5"></a>
### Minor Changes
* bitwarden lookup plugin \- use f\-strings instead of interpolations or <code>format</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9324](https\://github\.com/ansible\-collections/community\.general/pull/9324)\)\.
@@ -374,7 +593,7 @@ Regular bugfix and feature release\.
* zypper \- add <code>quiet</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9270](https\://github\.com/ansible\-collections/community\.general/pull/9270)\)\.
* zypper \- add <code>simple\_errors</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9270](https\://github\.com/ansible\-collections/community\.general/pull/9270)\)\.
<a id="deprecated-features-1"></a>
<a id="deprecated-features-3"></a>
### Deprecated Features
* atomic\_container \- module is deprecated and will be removed in community\.general 13\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/9487](https\://github\.com/ansible\-collections/community\.general/pull/9487)\)\.
@@ -397,7 +616,7 @@ Regular bugfix and feature release\.
* keycloak\_authentication \- API calls did not properly set the <code>priority</code> during update resulting in incorrectly sorted authentication flows\. This apparently only affects Keycloak 25 or newer \([https\://github\.com/ansible\-collections/community\.general/pull/9263](https\://github\.com/ansible\-collections/community\.general/pull/9263)\)\.
<a id="bugfixes-1"></a>
<a id="bugfixes-5"></a>
### Bugfixes
* dig lookup plugin \- correctly handle <code>NoNameserver</code> exception \([https\://github\.com/ansible\-collections/community\.general/pull/9363](https\://github\.com/ansible\-collections/community\.general/pull/9363)\, [https\://github\.com/ansible\-collections/community\.general/issues/9362](https\://github\.com/ansible\-collections/community\.general/issues/9362)\)\.
@@ -409,7 +628,7 @@ Regular bugfix and feature release\.
* qubes connection plugin \- fix the printing of debug information \([https\://github\.com/ansible\-collections/community\.general/pull/9334](https\://github\.com/ansible\-collections/community\.general/pull/9334)\)\.
* redfish\_utils module utils \- Fix <code>VerifyBiosAttributes</code> command on multi system resource nodes \([https\://github\.com/ansible\-collections/community\.general/pull/9234](https\://github\.com/ansible\-collections/community\.general/pull/9234)\)\.
<a id="new-plugins-1"></a>
<a id="new-plugins-2"></a>
### New Plugins
<a id="inventory"></a>
@@ -417,7 +636,7 @@ Regular bugfix and feature release\.
* community\.general\.iocage \- iocage inventory source\.
<a id="new-modules-1"></a>
<a id="new-modules-3"></a>
### New Modules
* community\.general\.android\_sdk \- Manages Android SDK packages\.
@@ -428,12 +647,12 @@ Regular bugfix and feature release\.
<a id="v10-1-0"></a>
## v10\.1\.0
<a id="release-summary-2"></a>
<a id="release-summary-6"></a>
### Release Summary
Regular bugfix and feature release\.
<a id="minor-changes-2"></a>
<a id="minor-changes-6"></a>
### Minor Changes
* alternatives \- add <code>family</code> parameter that allows to utilize the <code>\-\-family</code> option available in RedHat version of update\-alternatives \([https\://github\.com/ansible\-collections/community\.general/issues/5060](https\://github\.com/ansible\-collections/community\.general/issues/5060)\, [https\://github\.com/ansible\-collections/community\.general/pull/9096](https\://github\.com/ansible\-collections/community\.general/pull/9096)\)\.
@@ -454,13 +673,13 @@ Regular bugfix and feature release\.
* scaleway\_lb \- minor simplification in the code \([https\://github\.com/ansible\-collections/community\.general/pull/9189](https\://github\.com/ansible\-collections/community\.general/pull/9189)\)\.
* ssh\_config \- add <code>dynamicforward</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/9192](https\://github\.com/ansible\-collections/community\.general/pull/9192)\)\.
<a id="deprecated-features-2"></a>
<a id="deprecated-features-4"></a>
### Deprecated Features
* opkg \- deprecate value <code>\"\"</code> for parameter <code>force</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9172](https\://github\.com/ansible\-collections/community\.general/pull/9172)\)\.
* redfish\_utils module utils \- deprecate method <code>RedfishUtils\.\_init\_session\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/pull/9190](https\://github\.com/ansible\-collections/community\.general/pull/9190)\)\.
<a id="bugfixes-2"></a>
<a id="bugfixes-6"></a>
### Bugfixes
* dnf\_config\_manager \- fix hanging when prompting to import GPG keys \([https\://github\.com/ansible\-collections/community\.general/pull/9124](https\://github\.com/ansible\-collections/community\.general/pull/9124)\, [https\://github\.com/ansible\-collections/community\.general/issues/8830](https\://github\.com/ansible\-collections/community\.general/issues/8830)\)\.
@@ -472,7 +691,7 @@ Regular bugfix and feature release\.
* keycloak\_clientscope\_type \- sort the default and optional clientscope lists to improve the diff \([https\://github\.com/ansible\-collections/community\.general/pull/9202](https\://github\.com/ansible\-collections/community\.general/pull/9202)\)\.
* slack \- fail if Slack API response is not OK with error message \([https\://github\.com/ansible\-collections/community\.general/pull/9198](https\://github\.com/ansible\-collections/community\.general/pull/9198)\)\.
<a id="new-plugins-2"></a>
<a id="new-plugins-3"></a>
### New Plugins
<a id="filter-1"></a>
@@ -480,7 +699,7 @@ Regular bugfix and feature release\.
* community\.general\.accumulate \- Produce a list of accumulated sums of the input list contents\.
<a id="new-modules-2"></a>
<a id="new-modules-4"></a>
### New Modules
* community\.general\.decompress \- Decompresses compressed files\.
@@ -489,12 +708,12 @@ Regular bugfix and feature release\.
<a id="v10-0-1"></a>
## v10\.0\.1
<a id="release-summary-3"></a>
<a id="release-summary-7"></a>
### Release Summary
Bugfix release for inclusion in Ansible 11\.0\.0rc1\.
<a id="bugfixes-3"></a>
<a id="bugfixes-7"></a>
### Bugfixes
* keycloak\_client \- fix diff by removing code that turns the attributes dict which contains additional settings into a list \([https\://github\.com/ansible\-collections/community\.general/pull/9077](https\://github\.com/ansible\-collections/community\.general/pull/9077)\)\.
@@ -504,12 +723,12 @@ Bugfix release for inclusion in Ansible 11\.0\.0rc1\.
<a id="v10-0-0"></a>
## v10\.0\.0
<a id="release-summary-4"></a>
<a id="release-summary-8"></a>
### Release Summary
This is release 10\.0\.0 of <code>community\.general</code>\, released on 2024\-11\-04\.
<a id="minor-changes-3"></a>
<a id="minor-changes-7"></a>
### Minor Changes
* CmdRunner module util \- argument formats can be specified as plain functions without calling <code>cmd\_runner\_fmt\.as\_func\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/pull/8479](https\://github\.com/ansible\-collections/community\.general/pull/8479)\)\.
@@ -714,7 +933,7 @@ This is release 10\.0\.0 of <code>community\.general</code>\, released on 2024\-
* irc \- the defaults of <code>use\_tls</code> and <code>validate\_certs</code> changed from <code>false</code> to <code>true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/8918](https\://github\.com/ansible\-collections/community\.general/pull/8918)\)\.
* rhsm\_repository \- the states <code>present</code> and <code>absent</code> have been removed\. Use <code>enabled</code> and <code>disabled</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/8918](https\://github\.com/ansible\-collections/community\.general/pull/8918)\)\.
<a id="deprecated-features-3"></a>
<a id="deprecated-features-5"></a>
### Deprecated Features
* CmdRunner module util \- setting the value of the <code>ignore\_none</code> parameter within a <code>CmdRunner</code> context is deprecated and that feature should be removed in community\.general 12\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/8479](https\://github\.com/ansible\-collections/community\.general/pull/8479)\)\.
@@ -739,7 +958,7 @@ This is release 10\.0\.0 of <code>community\.general</code>\, released on 2024\-
* proxmox\_kvm \- removed the <code>proxmox\_default\_behavior</code> option\. Explicitly specify the old default values if you were using <code>proxmox\_default\_behavior\=compatibility</code>\, otherwise simply remove it \([https\://github\.com/ansible\-collections/community\.general/pull/8918](https\://github\.com/ansible\-collections/community\.general/pull/8918)\)\.
* redhat\_subscriptions \- removed the <code>pool</code> option\. Use <code>pool\_ids</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/8918](https\://github\.com/ansible\-collections/community\.general/pull/8918)\)\.
<a id="bugfixes-4"></a>
<a id="bugfixes-8"></a>
### Bugfixes
* bitwarden lookup plugin \- fix <code>KeyError</code> in <code>search\_field</code> \([https\://github\.com/ansible\-collections/community\.general/issues/8549](https\://github\.com/ansible\-collections/community\.general/issues/8549)\, [https\://github\.com/ansible\-collections/community\.general/pull/8557](https\://github\.com/ansible\-collections/community\.general/pull/8557)\)\.
@@ -819,12 +1038,12 @@ This is release 10\.0\.0 of <code>community\.general</code>\, released on 2024\-
* snap\_alias \- use new <code>VarDict</code> to prevent deprecation warning \([https\://github\.com/ansible\-collections/community\.general/issues/8410](https\://github\.com/ansible\-collections/community\.general/issues/8410)\, [https\://github\.com/ansible\-collections/community\.general/pull/8411](https\://github\.com/ansible\-collections/community\.general/pull/8411)\)\.
* udm\_user \- the module now tries to use <code>legacycrypt</code> on Python 3\.13\+ \([https\://github\.com/ansible\-collections/community\.general/issues/4690](https\://github\.com/ansible\-collections/community\.general/issues/4690)\, [https\://github\.com/ansible\-collections/community\.general/pull/8987](https\://github\.com/ansible\-collections/community\.general/pull/8987)\)\.
<a id="known-issues"></a>
<a id="known-issues-1"></a>
### Known Issues
* jenkins\_node \- the module is not able to update offline message when node is already offline due to internally using toggleOffline API \([https\://github\.com/ansible\-collections/community\.general/pull/9084](https\://github\.com/ansible\-collections/community\.general/pull/9084)\)\.
<a id="new-plugins-3"></a>
<a id="new-plugins-4"></a>
### New Plugins
<a id="filter-2"></a>
@@ -840,7 +1059,7 @@ This is release 10\.0\.0 of <code>community\.general</code>\, released on 2024\-
* community\.general\.ansible\_type \- Validate input type\.
<a id="new-modules-3"></a>
<a id="new-modules-5"></a>
### New Modules
* community\.general\.bootc\_manage \- Bootc Switch and Upgrade\.

View File

@@ -6,7 +6,7 @@ Community General Release Notes
This changelog describes changes after version 9.0.0.
v10.3.0
v10.6.0
=======
Release Summary
@@ -14,10 +14,206 @@ Release Summary
Regular bugfix and feature release.
Major Changes
Minor Changes
-------------
- keycloak_* modules - ``refresh_token`` parameter added. When multiple authentication parameters are provided (``token``, ``refresh_token``, and ``auth_username``/``auth_password``), modules will now automatically retry requests upon authentication errors (401), using in order the token, refresh token, and username/password (https://github.com/ansible-collections/community.general/pull/9494).
- apache2_module - added workaround for new PHP module name, from ``php7_module`` to ``php_module`` (https://github.com/ansible-collections/community.general/pull/9951).
- gitlab_project - add option ``build_timeout`` (https://github.com/ansible-collections/community.general/pull/9960).
- gitlab_project_members - extend choices parameter ``access_level`` by missing upstream valid value ``owner`` (https://github.com/ansible-collections/community.general/pull/9953).
- hpilo_boot - add option to get an idempotent behavior while powering on server, resulting in success instead of failure when using ``state: boot_once`` option (https://github.com/ansible-collections/community.general/pull/9646).
- idrac_redfish_command, idrac_redfish_config, idrac_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- ilo_redfish_command, ilo_redfish_config, ilo_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- keycloak module_utils - user groups can now be referenced by their name, like ``staff``, or their path, like ``/staff/engineering``. The path syntax allows users to reference subgroups, which is not possible otherwise (https://github.com/ansible-collections/community.general/pull/9898).
- keycloak_user module - user groups can now be referenced by their name, like ``staff``, or their path, like ``/staff/engineering``. The path syntax allows users to reference subgroups, which is not possible otherwise (https://github.com/ansible-collections/community.general/pull/9898).
- nmcli - add support for Infiniband MAC setting when ``type`` is ``infiniband`` (https://github.com/ansible-collections/community.general/pull/9962).
- one_vm - update allowed values for ``updateconf`` to include new parameters as per the latest OpenNebula API documentation.
Added parameters:
* ``OS``: ``FIRMWARE``;
* ``CPU_MODEL``: ``MODEL``, ``FEATURES``;
* ``FEATURES``: ``VIRTIO_BLK_QUEUES``, ``VIRTIO_SCSI_QUEUES``, ``IOTHREADS``;
* ``GRAPHICS``: ``PORT``, ``COMMAND``;
* ``VIDEO``: ``ATS``, ``IOMMU``, ``RESOLUTION``, ``TYPE``, ``VRAM``;
* ``RAW``: ``VALIDATE``;
* ``BACKUP_CONFIG``: ``FS_FREEZE``, ``KEEP_LAST``, ``BACKUP_VOLATILE``, ``MODE``, ``INCREMENT_MODE``.
(https://github.com/ansible-collections/community.general/pull/9959).
- proxmox and proxmox_kvm modules - allow uppercase characters in VM/container tags (https://github.com/ansible-collections/community.general/issues/9895, https://github.com/ansible-collections/community.general/pull/10024).
- puppet - improve parameter formatting, no impact to user (https://github.com/ansible-collections/community.general/pull/10014).
- redfish module utils - add ``REDFISH_COMMON_ARGUMENT_SPEC``, a corresponding ``redfish`` docs fragment, and support for its ``validate_certs``, ``ca_path``, and ``ciphers`` options (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- redfish_command, redfish_config, redfish_info - add ``validate_certs`` and ``ca_path`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- rocketchat - fix duplicate JSON conversion for Rocket.Chat < 7.4.0 (https://github.com/ansible-collections/community.general/pull/9965).
- wdc_redfish_command, wdc_redfish_info - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- xcc_redfish_command - add ``validate_certs``, ``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686, https://github.com/ansible-collections/community.general/pull/9964).
- zypper - adds ``skip_post_errors`` that allows to skip RPM post-install errors (Zypper return code 107) (https://github.com/ansible-collections/community.general/issues/9972).
Deprecated Features
-------------------
- manifold lookup plugin - plugin is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/10028).
- stackpath_compute inventory plugin - plugin is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/10026).
Bugfixes
--------
- dependent look plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
- diy callback plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
- github_deploy_key - check that key really exists on 422 to avoid masking other errors (https://github.com/ansible-collections/community.general/issues/6718, https://github.com/ansible-collections/community.general/pull/10011).
- hashids and unicode_normalize filter plugins - avoid deprecated ``AnsibleFilterTypeError`` on ansible-core 2.19 (https://github.com/ansible-collections/community.general/pull/9992).
- homebrew - emit a useful error message if ``brew info`` reports a package tap is ``null`` (https://github.com/ansible-collections/community.general/pull/10013, https://github.com/ansible-collections/community.general/issues/10012).
- java_cert - the module no longer fails if the optional parameters ``pkcs12_alias`` and ``cert_alias`` are not provided (https://github.com/ansible-collections/community.general/pull/9970).
- keycloak_authentication - fix authentification config duplication for Keycloak < 26.2.0 (https://github.com/ansible-collections/community.general/pull/9987).
- keycloak_client - fix the idempotency regression by normalizing the Keycloak response for ``after_client`` (https://github.com/ansible-collections/community.general/issues/9905, https://github.com/ansible-collections/community.general/pull/9976).
- proxmox inventory plugin - fix ``ansible_host`` staying empty for certain Proxmox nodes (https://github.com/ansible-collections/community.general/issues/5906, https://github.com/ansible-collections/community.general/pull/9952).
- proxmox_disk - fail gracefully if ``storage`` is required but not provided by the user (https://github.com/ansible-collections/community.general/issues/9941, https://github.com/ansible-collections/community.general/pull/9963).
- reveal_ansible_type filter plugin and ansible_type test plugin - make compatible with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
- sysrc - no longer always reporting ``changed=true`` when ``state=absent``. This fixes the method ``exists()`` (https://github.com/ansible-collections/community.general/issues/10004, https://github.com/ansible-collections/community.general/pull/10005).
- yaml callback plugin - use ansible-core internals to avoid breakage with Data Tagging (https://github.com/ansible-collections/community.general/pull/9833).
Known Issues
------------
- reveal_ansible_type filter plugin and ansible_type test plugin - note that ansible-core's Data Tagging feature implements new aliases, such as ``_AnsibleTaggedStr`` for ``str``, ``_AnsibleTaggedInt`` for ``int``, and ``_AnsibleTaggedFloat`` for ``float`` (https://github.com/ansible-collections/community.general/pull/9833).
New Plugins
-----------
Connection
~~~~~~~~~~
- community.general.wsl - Run tasks in WSL distribution using wsl.exe CLI via SSH.
v10.5.0
=======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
- CmdRunner module utils - the convenience method ``cmd_runner_fmt.as_fixed()`` now accepts multiple arguments as a list (https://github.com/ansible-collections/community.general/pull/9893).
- apache2_mod_proxy - code simplification, no change in functionality (https://github.com/ansible-collections/community.general/pull/9457).
- consul_token - fix idempotency when ``policies`` or ``roles`` are supplied by name (https://github.com/ansible-collections/community.general/issues/9841, https://github.com/ansible-collections/community.general/pull/9845).
- keycloak_realm - remove ID requirement when creating a realm to allow Keycloak generating its own realm ID (https://github.com/ansible-collections/community.general/pull/9768).
- nmap inventory plugin - adds ``dns_servers`` option for specifying DNS servers for name resolution. Accepts hostnames or IP addresses in the same format as the ``exclude`` option (https://github.com/ansible-collections/community.general/pull/9849).
- proxmox_kvm - add missing audio hardware device handling (https://github.com/ansible-collections/community.general/issues/5192, https://github.com/ansible-collections/community.general/pull/9847).
- redfish_config - add command ``SetPowerRestorePolicy`` to set the desired power state of the system when power is restored (https://github.com/ansible-collections/community.general/pull/9837).
- redfish_info - add command ``GetPowerRestorePolicy`` to get the desired power state of the system when power is restored (https://github.com/ansible-collections/community.general/pull/9824).
- rocketchat - option ``is_pre740`` has been added to control the format of the payload. For Rocket.Chat 7.4.0 or newer, it must be set to ``false`` (https://github.com/ansible-collections/community.general/pull/9882).
- slack callback plugin - add ``http_agent`` option to enable the user to set a custom user agent for slack callback plugin (https://github.com/ansible-collections/community.general/issues/9813, https://github.com/ansible-collections/community.general/pull/9836).
- systemd_info - add wildcard expression support in ``unitname`` option (https://github.com/ansible-collections/community.general/pull/9821).
- systemd_info - extend support to timer units (https://github.com/ansible-collections/community.general/pull/9891).
- vmadm - add new options ``flexible_disk_size`` and ``owner_uuid`` (https://github.com/ansible-collections/community.general/pull/9892).
Bugfixes
--------
- cloudlare_dns - handle exhausted response stream in case of HTTP errors to show nice error message to the user (https://github.com/ansible-collections/community.general/issues/9782, https://github.com/ansible-collections/community.general/pull/9818).
- dnf_versionlock - add support for dnf5 (https://github.com/ansible-collections/community.general/issues/9556).
- homebrew - fix crash when package names include tap (https://github.com/ansible-collections/community.general/issues/9777, https://github.com/ansible-collections/community.general/pull/9803).
- homebrew_cask - handle unusual brew version strings (https://github.com/ansible-collections/community.general/issues/8432, https://github.com/ansible-collections/community.general/pull/9881).
- nmcli - enable changing only the order of DNS servers or search suffixes (https://github.com/ansible-collections/community.general/issues/8724, https://github.com/ansible-collections/community.general/pull/9880).
- proxmox - add missing key selection of ``'status'`` key to ``get_lxc_status`` (https://github.com/ansible-collections/community.general/issues/9696, https://github.com/ansible-collections/community.general/pull/9809).
- proxmox_vm_info - the module no longer expects that the key ``template`` exists in a dictionary returned by Proxmox (https://github.com/ansible-collections/community.general/issues/9875, https://github.com/ansible-collections/community.general/pull/9910).
- sudoers - display stdout and stderr raised while failed validation (https://github.com/ansible-collections/community.general/issues/9674, https://github.com/ansible-collections/community.general/pull/9871).
New Modules
-----------
- community.general.pacemaker_resource - Manage pacemaker resources.
v10.4.0
=======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
- bitwarden lookup plugin - add new option ``collection_name`` to filter results by collection name, and new option ``result_count`` to validate number of results (https://github.com/ansible-collections/community.general/pull/9728).
- incus connection plugin - adds ``remote_user`` and ``incus_become_method`` parameters for allowing a non-root user to connect to an Incus instance (https://github.com/ansible-collections/community.general/pull/9743).
- iocage inventory plugin - the new parameter ``hooks_results`` of the plugin is a list of files inside a jail that provide configuration parameters for the inventory. The inventory plugin reads the files from the jails and put the contents into the items of created variable ``iocage_hooks`` (https://github.com/ansible-collections/community.general/issues/9650, https://github.com/ansible-collections/community.general/pull/9651).
- jira - adds ``client_cert`` and ``client_key`` parameters for supporting client certificate authentification when connecting to Jira (https://github.com/ansible-collections/community.general/pull/9753).
- lldp - adds ``multivalues`` parameter to control behavior when lldpctl outputs an attribute multiple times (https://github.com/ansible-collections/community.general/pull/9657).
- lvg - add ``remove_extra_pvs`` parameter to control if ansible should remove physical volumes which are not in the ``pvs`` parameter (https://github.com/ansible-collections/community.general/pull/9698).
- lxd connection plugin - adds ``remote_user`` and ``lxd_become_method`` parameters for allowing a non-root user to connect to an LXD instance (https://github.com/ansible-collections/community.general/pull/9659).
- nmcli - adds VRF support with new ``type`` value ``vrf`` and new ``slave_type`` value ``vrf`` as well as new ``table`` parameter (https://github.com/ansible-collections/community.general/pull/9658, https://github.com/ansible-collections/community.general/issues/8014).
- proxmox_kvm - allow hibernation and suspending of VMs (https://github.com/ansible-collections/community.general/issues/9620, https://github.com/ansible-collections/community.general/pull/9653).
- redfish_command - add ``PowerFullPowerCycle`` to power command options (https://github.com/ansible-collections/community.general/pull/9729).
- ssh_config - add ``other_options`` option (https://github.com/ansible-collections/community.general/issues/8053, https://github.com/ansible-collections/community.general/pull/9684).
- xen_orchestra inventory plugin - add ``use_vm_uuid`` and ``use_host_uuid`` boolean options to allow switching over to using VM/Xen name labels instead of UUIDs as item names (https://github.com/ansible-collections/community.general/pull/9787).
Deprecated Features
-------------------
- profitbricks - module is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_datacenter - module is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_nic - module is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_volume - module is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_volume_attachments - module is deprecated and will be removed in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
Bugfixes
--------
- apache2_mod_proxy - make compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/9762).
- apache2_mod_proxy - passing the cluster's page as referer for the member's pages. This makes the module actually work again for halfway modern Apache versions. According to some comments founds on the net the referer was required since at least 2019 for some versions of Apache 2 (https://github.com/ansible-collections/community.general/pull/9762).
- elasticsearch_plugin - fix ``ERROR: D is not a recognized option`` issue when configuring proxy settings (https://github.com/ansible-collections/community.general/pull/9774, https://github.com/ansible-collections/community.general/issues/9773).
- ipa_host - module revoked existing host certificates even if ``user_certificate`` was not given (https://github.com/ansible-collections/community.general/pull/9694).
- keycloak_client - in check mode, detect whether the lists in before client (for example redirect URI list) contain items that the lists in the desired client do not contain (https://github.com/ansible-collections/community.general/pull/9739).
- lldp - fix crash caused by certain lldpctl output where an attribute is defined as branch and leaf (https://github.com/ansible-collections/community.general/pull/9657).
- onepassword_doc lookup plugin - ensure that 1Password Connect support also works for this plugin (https://github.com/ansible-collections/community.general/pull/9625).
- passwordstore lookup plugin - fix subkey creation even when ``create=false`` (https://github.com/ansible-collections/community.general/issues/9105, https://github.com/ansible-collections/community.general/pull/9106).
- proxmox inventory plugin - plugin did not update cache correctly after ``meta: refresh_inventory`` (https://github.com/ansible-collections/community.general/issues/9710, https://github.com/ansible-collections/community.general/pull/9760).
- redhat_subscription - use the "enable_content" option (when available) when
registering using D-Bus, to ensure that subscription-manager enables the
content on registration; this is particular important on EL 10+ and Fedora
41+
(https://github.com/ansible-collections/community.general/pull/9778).
- zfs - fix handling of multi-line values of user-defined ZFS properties (https://github.com/ansible-collections/community.general/pull/6264).
- zfs_facts - parameter ``type`` now accepts multple values as documented (https://github.com/ansible-collections/community.general/issues/5909, https://github.com/ansible-collections/community.general/pull/9697).
New Modules
-----------
- community.general.systemd_info - Gather C(systemd) unit info.
v10.3.1
=======
Release Summary
---------------
Bugfix release.
Minor Changes
-------------
- onepassword_ssh_key - refactor to move code to lookup class (https://github.com/ansible-collections/community.general/pull/9633).
Bugfixes
--------
- cloudflare_dns - fix crash when deleting a DNS record or when updating a record with ``solo=true`` (https://github.com/ansible-collections/community.general/issues/9652, https://github.com/ansible-collections/community.general/pull/9649).
- homebrew - make package name parsing more resilient (https://github.com/ansible-collections/community.general/pull/9665, https://github.com/ansible-collections/community.general/issues/9641).
- keycloak module utils - replaces missing return in get_role_composites method which caused it to return None instead of composite roles (https://github.com/ansible-collections/community.general/issues/9678, https://github.com/ansible-collections/community.general/pull/9691).
- keycloak_client - fix and improve existing tests. The module showed a diff without actual changes, solved by improving the ``normalise_cr()`` function (https://github.com/ansible-collections/community.general/pull/9644).
- proxmox - adds the ``pubkey`` parameter (back to) the ``update`` state (https://github.com/ansible-collections/community.general/issues/9642, https://github.com/ansible-collections/community.general/pull/9645).
- proxmox - fixes a typo in the translation of the ``pubkey`` parameter to proxmox' ``ssh-public-keys`` (https://github.com/ansible-collections/community.general/issues/9642, https://github.com/ansible-collections/community.general/pull/9645).
- xml - ensure file descriptor is closed (https://github.com/ansible-collections/community.general/pull/9695).
v10.3.0
=======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
@@ -68,6 +264,7 @@ Minor Changes
- jira - transition operation now has ``status_id`` to directly reference wanted transition (https://github.com/ansible-collections/community.general/pull/9602).
- json_query filter plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9585).
- keep_keys filter plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9585).
- keycloak_* modules - ``refresh_token`` parameter added. When multiple authentication parameters are provided (``token``, ``refresh_token``, and ``auth_username``/``auth_password``), modules will now automatically retry requests upon authentication errors (401), using in order the token, refresh token, and username/password (https://github.com/ansible-collections/community.general/pull/9494).
- known_hosts - open file using ``open()`` as a context manager (https://github.com/ansible-collections/community.general/pull/9579).
- ksu become plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9583).
- linode inventory plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9584).

View File

@@ -9,6 +9,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
[![Documentation](https://img.shields.io/badge/docs-brightgreen.svg)](https://docs.ansible.com/ansible/latest/collections/community/general/)
[![Build Status](https://dev.azure.com/ansible/community.general/_apis/build/status/CI?branchName=stable-10)](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
[![EOL CI](https://github.com/ansible-collections/community.general/actions/workflows/ansible-test.yml/badge.svg?branch=stable-10)](https://github.com/ansible-collections/community.general/actions)
[![Nox CI](https://github.com/ansible-collections/community.general/actions/workflows/nox.yml/badge.svg?branch=stable-10)](https://github.com/ansible-collections/community.general/actions)
[![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.general)](https://codecov.io/gh/ansible-collections/community.general)
[![REUSE status](https://api.reuse.software/badge/github.com/ansible-collections/community.general)](https://api.reuse.software/info/github.com/ansible-collections/community.general)

11
REUSE.toml Normal file
View File

@@ -0,0 +1,11 @@
# 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
version = 1
[[annotations]]
path = "changelogs/fragments/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "Ansible Project"
SPDX-License-Identifier = "GPL-3.0-or-later"

48
antsibull-nox.toml Normal file
View File

@@ -0,0 +1,48 @@
# 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
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
[collection_sources]
"ansible.posix" = "git+https://github.com/ansible-collections/ansible.posix.git,main"
"community.crypto" = "git+https://github.com/ansible-collections/community.crypto.git,main"
"community.docker" = "git+https://github.com/ansible-collections/community.docker.git,main"
"community.internal_test_tools" = "git+https://github.com/ansible-collections/community.internal_test_tools.git,main"
[sessions]
[sessions.docs_check]
validate_collection_refs="all"
[sessions.license_check]
[sessions.extra_checks]
run_no_unwanted_files = true
no_unwanted_files_module_extensions = [".py"]
no_unwanted_files_yaml_extensions = [".yml"]
run_action_groups = true
[[sessions.extra_checks.action_groups_config]]
name = "consul"
pattern = "^consul_.*$"
exclusions = [
"consul_acl_bootstrap",
"consul_kv",
]
doc_fragment = "community.general.consul.actiongroup_consul"
[[sessions.extra_checks.action_groups_config]]
name = "keycloak"
pattern = "^keycloak_.*$"
exclusions = [
"keycloak_realm_info",
]
doc_fragment = "community.general.keycloak.actiongroup_keycloak"
[[sessions.extra_checks.action_groups_config]]
name = "proxmox"
pattern = "^proxmox(_.*)?$"
exclusions = []
doc_fragment = "community.general.proxmox.actiongroup_proxmox"
[sessions.build_import_check]
run_galaxy_importer = true

View File

@@ -1228,11 +1228,6 @@ releases:
'
- proxmox - removes default value ``false`` of ``update`` parameter. This
will be changed to a default of ``true`` in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9225).
major_changes:
- keycloak_* modules - ``refresh_token`` parameter added. When multiple authentication
parameters are provided (``token``, ``refresh_token``, and ``auth_username``/``auth_password``),
modules will now automatically retry requests upon authentication errors
(401), using in order the token, refresh token, and username/password (https://github.com/ansible-collections/community.general/pull/9494).
minor_changes:
- MH module utils - delegate ``debug`` to the underlying ``AnsibleModule``
instance or issues a warning if an attribute already exists with that name
@@ -1295,6 +1290,10 @@ releases:
wanted transition (https://github.com/ansible-collections/community.general/pull/9602).
- json_query filter plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9585).
- keep_keys filter plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9585).
- keycloak_* modules - ``refresh_token`` parameter added. When multiple authentication
parameters are provided (``token``, ``refresh_token``, and ``auth_username``/``auth_password``),
modules will now automatically retry requests upon authentication errors
(401), using in order the token, refresh token, and username/password (https://github.com/ansible-collections/community.general/pull/9494).
- known_hosts - open file using ``open()`` as a context manager (https://github.com/ansible-collections/community.general/pull/9579).
- ksu become plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9583).
- linode inventory plugin - adjust standard preamble for Python 3 (https://github.com/ansible-collections/community.general/pull/9584).
@@ -1436,3 +1435,369 @@ releases:
name: onepassword_ssh_key
namespace: null
release_date: '2025-01-27'
10.3.1:
changes:
bugfixes:
- cloudflare_dns - fix crash when deleting a DNS record or when updating a
record with ``solo=true`` (https://github.com/ansible-collections/community.general/issues/9652,
https://github.com/ansible-collections/community.general/pull/9649).
- homebrew - make package name parsing more resilient (https://github.com/ansible-collections/community.general/pull/9665,
https://github.com/ansible-collections/community.general/issues/9641).
- keycloak module utils - replaces missing return in get_role_composites method
which caused it to return None instead of composite roles (https://github.com/ansible-collections/community.general/issues/9678,
https://github.com/ansible-collections/community.general/pull/9691).
- keycloak_client - fix and improve existing tests. The module showed a diff
without actual changes, solved by improving the ``normalise_cr()`` function
(https://github.com/ansible-collections/community.general/pull/9644).
- proxmox - adds the ``pubkey`` parameter (back to) the ``update`` state (https://github.com/ansible-collections/community.general/issues/9642,
https://github.com/ansible-collections/community.general/pull/9645).
- proxmox - fixes a typo in the translation of the ``pubkey`` parameter to
proxmox' ``ssh-public-keys`` (https://github.com/ansible-collections/community.general/issues/9642,
https://github.com/ansible-collections/community.general/pull/9645).
- xml - ensure file descriptor is closed (https://github.com/ansible-collections/community.general/pull/9695).
minor_changes:
- onepassword_ssh_key - refactor to move code to lookup class (https://github.com/ansible-collections/community.general/pull/9633).
release_summary: Bugfix release.
fragments:
- 10.3.1.yml
- 9633-onepassword_ssh_key.yml
- 9644-kc_client-test-improvement-and-fix.yaml
- 9645-proxmox-fix-pubkey.yml
- 9649-cloudflare_dns-fix-crash-when-deleting-record.yml
- 9665-more-resilient-handling-of-homebrew-packages-names.yml
- 9691-keycloak-module-utils-replace-missing-return-in-get_role_composites.yml
- 9695-xml-close-file.yml
release_date: '2025-02-10'
10.4.0:
changes:
bugfixes:
- apache2_mod_proxy - make compatible with Python 3 (https://github.com/ansible-collections/community.general/pull/9762).
- apache2_mod_proxy - passing the cluster's page as referer for the member's
pages. This makes the module actually work again for halfway modern Apache
versions. According to some comments founds on the net the referer was required
since at least 2019 for some versions of Apache 2 (https://github.com/ansible-collections/community.general/pull/9762).
- 'elasticsearch_plugin - fix ``ERROR: D is not a recognized option`` issue
when configuring proxy settings (https://github.com/ansible-collections/community.general/pull/9774,
https://github.com/ansible-collections/community.general/issues/9773).'
- ipa_host - module revoked existing host certificates even if ``user_certificate``
was not given (https://github.com/ansible-collections/community.general/pull/9694).
- keycloak_client - in check mode, detect whether the lists in before client
(for example redirect URI list) contain items that the lists in the desired
client do not contain (https://github.com/ansible-collections/community.general/pull/9739).
- lldp - fix crash caused by certain lldpctl output where an attribute is
defined as branch and leaf (https://github.com/ansible-collections/community.general/pull/9657).
- onepassword_doc lookup plugin - ensure that 1Password Connect support also
works for this plugin (https://github.com/ansible-collections/community.general/pull/9625).
- passwordstore lookup plugin - fix subkey creation even when ``create=false``
(https://github.com/ansible-collections/community.general/issues/9105, https://github.com/ansible-collections/community.general/pull/9106).
- 'proxmox inventory plugin - plugin did not update cache correctly after
``meta: refresh_inventory`` (https://github.com/ansible-collections/community.general/issues/9710,
https://github.com/ansible-collections/community.general/pull/9760).'
- 'redhat_subscription - use the "enable_content" option (when available)
when
registering using D-Bus, to ensure that subscription-manager enables the
content on registration; this is particular important on EL 10+ and Fedora
41+
(https://github.com/ansible-collections/community.general/pull/9778).
'
- zfs - fix handling of multi-line values of user-defined ZFS properties (https://github.com/ansible-collections/community.general/pull/6264).
- zfs_facts - parameter ``type`` now accepts multple values as documented
(https://github.com/ansible-collections/community.general/issues/5909, https://github.com/ansible-collections/community.general/pull/9697).
deprecated_features:
- profitbricks - module is deprecated and will be removed in community.general
11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_datacenter - module is deprecated and will be removed in community.general
11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_nic - module is deprecated and will be removed in community.general
11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_volume - module is deprecated and will be removed in community.general
11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
- profitbricks_volume_attachments - module is deprecated and will be removed
in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/9733).
minor_changes:
- bitwarden lookup plugin - add new option ``collection_name`` to filter results
by collection name, and new option ``result_count`` to validate number of
results (https://github.com/ansible-collections/community.general/pull/9728).
- incus connection plugin - adds ``remote_user`` and ``incus_become_method``
parameters for allowing a non-root user to connect to an Incus instance
(https://github.com/ansible-collections/community.general/pull/9743).
- iocage inventory plugin - the new parameter ``hooks_results`` of the plugin
is a list of files inside a jail that provide configuration parameters for
the inventory. The inventory plugin reads the files from the jails and put
the contents into the items of created variable ``iocage_hooks`` (https://github.com/ansible-collections/community.general/issues/9650,
https://github.com/ansible-collections/community.general/pull/9651).
- jira - adds ``client_cert`` and ``client_key`` parameters for supporting
client certificate authentification when connecting to Jira (https://github.com/ansible-collections/community.general/pull/9753).
- lldp - adds ``multivalues`` parameter to control behavior when lldpctl outputs
an attribute multiple times (https://github.com/ansible-collections/community.general/pull/9657).
- lvg - add ``remove_extra_pvs`` parameter to control if ansible should remove
physical volumes which are not in the ``pvs`` parameter (https://github.com/ansible-collections/community.general/pull/9698).
- lxd connection plugin - adds ``remote_user`` and ``lxd_become_method`` parameters
for allowing a non-root user to connect to an LXD instance (https://github.com/ansible-collections/community.general/pull/9659).
- nmcli - adds VRF support with new ``type`` value ``vrf`` and new ``slave_type``
value ``vrf`` as well as new ``table`` parameter (https://github.com/ansible-collections/community.general/pull/9658,
https://github.com/ansible-collections/community.general/issues/8014).
- proxmox_kvm - allow hibernation and suspending of VMs (https://github.com/ansible-collections/community.general/issues/9620,
https://github.com/ansible-collections/community.general/pull/9653).
- redfish_command - add ``PowerFullPowerCycle`` to power command options (https://github.com/ansible-collections/community.general/pull/9729).
- ssh_config - add ``other_options`` option (https://github.com/ansible-collections/community.general/issues/8053,
https://github.com/ansible-collections/community.general/pull/9684).
- xen_orchestra inventory plugin - add ``use_vm_uuid`` and ``use_host_uuid``
boolean options to allow switching over to using VM/Xen name labels instead
of UUIDs as item names (https://github.com/ansible-collections/community.general/pull/9787).
release_summary: Regular bugfix and feature release.
fragments:
- 10.4.0.yaml
- 6264-zfs-multiline-property-value.yml
- 9106-passwordstore-fix-subkey-creation-even-when-create-==-false.yml
- 9625-onepassword_doc.yml
- 9651-iocage-inventory-hooks.yml
- 9653-proxmox-kvm-allow-vm-hibernation.yml
- 9657-lldp-handling-attributes-defined-multiple-times.yml
- 9658-add-vrf-commands-to-nmcli-module.yml
- 9659-lxd_connection-nonroot-user.yml
- 9694-ipa-host-certificate-revoked.yml
- 9697-zfs-facts-type.yml
- 9698-lvg-remove-extra-pvs-parameter.yml
- 9728-bitwarden-collection-name-filter.yml
- 9729-redfish-fullpowercycle-command.yml
- 9733-profitbrick-deprecation.yml
- 9739-keycloak_client-compare-before-desired-directly.yml
- 9743-incus_connection-nonroot-user.yml
- 9753-jira-add-client-certificate-auth.yml
- 9760-proxmox-inventory.yml
- 9762-apache2_mod_proxy.yml
- 9774-fix-elasticsearch_plugin-proxy-settings.yml
- 9778-redhat_subscription-ensure-to-enable-content.yml
- 9787-xoa_allow_using_names_in_inventory.yml
- ssh_config_add_other_options.yml
modules:
- description: Gather C(systemd) unit info.
name: systemd_info
namespace: ''
release_date: '2025-02-24'
10.5.0:
changes:
bugfixes:
- cloudlare_dns - handle exhausted response stream in case of HTTP errors
to show nice error message to the user (https://github.com/ansible-collections/community.general/issues/9782,
https://github.com/ansible-collections/community.general/pull/9818).
- dnf_versionlock - add support for dnf5 (https://github.com/ansible-collections/community.general/issues/9556).
- homebrew - fix crash when package names include tap (https://github.com/ansible-collections/community.general/issues/9777,
https://github.com/ansible-collections/community.general/pull/9803).
- homebrew_cask - handle unusual brew version strings (https://github.com/ansible-collections/community.general/issues/8432,
https://github.com/ansible-collections/community.general/pull/9881).
- nmcli - enable changing only the order of DNS servers or search suffixes
(https://github.com/ansible-collections/community.general/issues/8724, https://github.com/ansible-collections/community.general/pull/9880).
- proxmox - add missing key selection of ``'status'`` key to ``get_lxc_status``
(https://github.com/ansible-collections/community.general/issues/9696, https://github.com/ansible-collections/community.general/pull/9809).
- proxmox_vm_info - the module no longer expects that the key ``template``
exists in a dictionary returned by Proxmox (https://github.com/ansible-collections/community.general/issues/9875,
https://github.com/ansible-collections/community.general/pull/9910).
- sudoers - display stdout and stderr raised while failed validation (https://github.com/ansible-collections/community.general/issues/9674,
https://github.com/ansible-collections/community.general/pull/9871).
minor_changes:
- CmdRunner module utils - the convenience method ``cmd_runner_fmt.as_fixed()``
now accepts multiple arguments as a list (https://github.com/ansible-collections/community.general/pull/9893).
- apache2_mod_proxy - code simplification, no change in functionality (https://github.com/ansible-collections/community.general/pull/9457).
- consul_token - fix idempotency when ``policies`` or ``roles`` are supplied
by name (https://github.com/ansible-collections/community.general/issues/9841,
https://github.com/ansible-collections/community.general/pull/9845).
- keycloak_realm - remove ID requirement when creating a realm to allow Keycloak
generating its own realm ID (https://github.com/ansible-collections/community.general/pull/9768).
- nmap inventory plugin - adds ``dns_servers`` option for specifying DNS servers
for name resolution. Accepts hostnames or IP addresses in the same format
as the ``exclude`` option (https://github.com/ansible-collections/community.general/pull/9849).
- proxmox_kvm - add missing audio hardware device handling (https://github.com/ansible-collections/community.general/issues/5192,
https://github.com/ansible-collections/community.general/pull/9847).
- redfish_config - add command ``SetPowerRestorePolicy`` to set the desired
power state of the system when power is restored (https://github.com/ansible-collections/community.general/pull/9837).
- redfish_info - add command ``GetPowerRestorePolicy`` to get the desired
power state of the system when power is restored (https://github.com/ansible-collections/community.general/pull/9824).
- rocketchat - option ``is_pre740`` has been added to control the format of
the payload. For Rocket.Chat 7.4.0 or newer, it must be set to ``false``
(https://github.com/ansible-collections/community.general/pull/9882).
- slack callback plugin - add ``http_agent`` option to enable the user to
set a custom user agent for slack callback plugin (https://github.com/ansible-collections/community.general/issues/9813,
https://github.com/ansible-collections/community.general/pull/9836).
- systemd_info - add wildcard expression support in ``unitname`` option (https://github.com/ansible-collections/community.general/pull/9821).
- systemd_info - extend support to timer units (https://github.com/ansible-collections/community.general/pull/9891).
- vmadm - add new options ``flexible_disk_size`` and ``owner_uuid`` (https://github.com/ansible-collections/community.general/pull/9892).
release_summary: Regular bugfix and feature release.
fragments:
- 10.5.0.yml
- 9457-apache2-mod-proxy-revamp.yml
- 9768-keycloak_realm-remove-id-requirement.yaml
- 9777-homebrew-fix-crash-when-packages-include-tap.yml
- 9809-proxmox-fix-status-getter.yml
- 9818-cloudflare-dns-exhausted-response.yml
- 9821-systemd_info-add-wildcards.yml
- 9824-redfish-implement-obtaining-powerrestorepolicy.yml
- 9836-option-for-http-agent-for-user-to-callback-slack.yml
- 9837-redfish-implement-setting-powerrestorepolicy.yml
- 9845-consul_token_idempotency.yml
- 9847-Adding_audio_device-support_to_proxmox_kvm.yml
- 9849-nmap_dns_servers.yml
- 9875-proxmox-dont-expect-key-template-to-exist.yml
- 9880-nmcli-fix-reorder-same-dns-nameservers-search-suffixes.yml
- 9882-fix-payload-to-match-rocketchat-740-requirement.yml
- 9891-systemd_info-add_timer.yml
- 9892-vmadm-add-new-options.yml
- 9893-cmdrunner-as-fixed-args.yml
- dnf_versionlock.yml
- homebrew_cask.yml
- sudoers.yml
modules:
- description: Manage pacemaker resources.
name: pacemaker_resource
namespace: ''
release_date: '2025-03-24'
10.6.0:
changes:
bugfixes:
- dependent look plugin - make compatible with ansible-core's Data Tagging
feature (https://github.com/ansible-collections/community.general/pull/9833).
- diy callback plugin - make compatible with ansible-core's Data Tagging feature
(https://github.com/ansible-collections/community.general/pull/9833).
- "github_deploy_key - check that key really exists on 422\_to avoid masking\
\ other errors (https://github.com/ansible-collections/community.general/issues/6718,\
\ https://github.com/ansible-collections/community.general/pull/10011)."
- hashids and unicode_normalize filter plugins - avoid deprecated ``AnsibleFilterTypeError``
on ansible-core 2.19 (https://github.com/ansible-collections/community.general/pull/9992).
- homebrew - emit a useful error message if ``brew info`` reports a package
tap is ``null`` (https://github.com/ansible-collections/community.general/pull/10013,
https://github.com/ansible-collections/community.general/issues/10012).
- java_cert - the module no longer fails if the optional parameters ``pkcs12_alias``
and ``cert_alias`` are not provided (https://github.com/ansible-collections/community.general/pull/9970).
- keycloak_authentication - fix authentification config duplication for Keycloak
< 26.2.0 (https://github.com/ansible-collections/community.general/pull/9987).
- keycloak_client - fix the idempotency regression by normalizing the Keycloak
response for ``after_client`` (https://github.com/ansible-collections/community.general/issues/9905,
https://github.com/ansible-collections/community.general/pull/9976).
- proxmox inventory plugin - fix ``ansible_host`` staying empty for certain
Proxmox nodes (https://github.com/ansible-collections/community.general/issues/5906,
https://github.com/ansible-collections/community.general/pull/9952).
- proxmox_disk - fail gracefully if ``storage`` is required but not provided
by the user (https://github.com/ansible-collections/community.general/issues/9941,
https://github.com/ansible-collections/community.general/pull/9963).
- reveal_ansible_type filter plugin and ansible_type test plugin - make compatible
with ansible-core's Data Tagging feature (https://github.com/ansible-collections/community.general/pull/9833).
- sysrc - no longer always reporting ``changed=true`` when ``state=absent``.
This fixes the method ``exists()`` (https://github.com/ansible-collections/community.general/issues/10004,
https://github.com/ansible-collections/community.general/pull/10005).
- yaml callback plugin - use ansible-core internals to avoid breakage with
Data Tagging (https://github.com/ansible-collections/community.general/pull/9833).
deprecated_features:
- manifold lookup plugin - plugin is deprecated and will be removed in community.general
11.0.0 (https://github.com/ansible-collections/community.general/pull/10028).
- stackpath_compute inventory plugin - plugin is deprecated and will be removed
in community.general 11.0.0 (https://github.com/ansible-collections/community.general/pull/10026).
known_issues:
- reveal_ansible_type filter plugin and ansible_type test plugin - note that
ansible-core's Data Tagging feature implements new aliases, such as ``_AnsibleTaggedStr``
for ``str``, ``_AnsibleTaggedInt`` for ``int``, and ``_AnsibleTaggedFloat``
for ``float`` (https://github.com/ansible-collections/community.general/pull/9833).
minor_changes:
- apache2_module - added workaround for new PHP module name, from ``php7_module``
to ``php_module`` (https://github.com/ansible-collections/community.general/pull/9951).
- gitlab_project - add option ``build_timeout`` (https://github.com/ansible-collections/community.general/pull/9960).
- gitlab_project_members - extend choices parameter ``access_level`` by missing
upstream valid value ``owner`` (https://github.com/ansible-collections/community.general/pull/9953).
- 'hpilo_boot - add option to get an idempotent behavior while powering on
server, resulting in success instead of failure when using ``state: boot_once``
option (https://github.com/ansible-collections/community.general/pull/9646).'
- idrac_redfish_command, idrac_redfish_config, idrac_redfish_info - add ``validate_certs``,
``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- ilo_redfish_command, ilo_redfish_config, ilo_redfish_info - add ``validate_certs``,
``ca_path``, and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- keycloak module_utils - user groups can now be referenced by their name,
like ``staff``, or their path, like ``/staff/engineering``. The path syntax
allows users to reference subgroups, which is not possible otherwise (https://github.com/ansible-collections/community.general/pull/9898).
- keycloak_user module - user groups can now be referenced by their name,
like ``staff``, or their path, like ``/staff/engineering``. The path syntax
allows users to reference subgroups, which is not possible otherwise (https://github.com/ansible-collections/community.general/pull/9898).
- nmcli - add support for Infiniband MAC setting when ``type`` is ``infiniband``
(https://github.com/ansible-collections/community.general/pull/9962).
- 'one_vm - update allowed values for ``updateconf`` to include new parameters
as per the latest OpenNebula API documentation.
Added parameters:
* ``OS``: ``FIRMWARE``;
* ``CPU_MODEL``: ``MODEL``, ``FEATURES``;
* ``FEATURES``: ``VIRTIO_BLK_QUEUES``, ``VIRTIO_SCSI_QUEUES``, ``IOTHREADS``;
* ``GRAPHICS``: ``PORT``, ``COMMAND``;
* ``VIDEO``: ``ATS``, ``IOMMU``, ``RESOLUTION``, ``TYPE``, ``VRAM``;
* ``RAW``: ``VALIDATE``;
* ``BACKUP_CONFIG``: ``FS_FREEZE``, ``KEEP_LAST``, ``BACKUP_VOLATILE``,
``MODE``, ``INCREMENT_MODE``.
(https://github.com/ansible-collections/community.general/pull/9959).'
- proxmox and proxmox_kvm modules - allow uppercase characters in VM/container
tags (https://github.com/ansible-collections/community.general/issues/9895,
https://github.com/ansible-collections/community.general/pull/10024).
- puppet - improve parameter formatting, no impact to user (https://github.com/ansible-collections/community.general/pull/10014).
- redfish module utils - add ``REDFISH_COMMON_ARGUMENT_SPEC``, a corresponding
``redfish`` docs fragment, and support for its ``validate_certs``, ``ca_path``,
and ``ciphers`` options (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- redfish_command, redfish_config, redfish_info - add ``validate_certs`` and
``ca_path`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- rocketchat - fix duplicate JSON conversion for Rocket.Chat < 7.4.0 (https://github.com/ansible-collections/community.general/pull/9965).
- wdc_redfish_command, wdc_redfish_info - add ``validate_certs``, ``ca_path``,
and ``ciphers`` options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- xcc_redfish_command - add ``validate_certs``, ``ca_path``, and ``ciphers``
options to configure TLS/SSL (https://github.com/ansible-collections/community.general/issues/3686,
https://github.com/ansible-collections/community.general/pull/9964).
- zypper - adds ``skip_post_errors`` that allows to skip RPM post-install
errors (Zypper return code 107) (https://github.com/ansible-collections/community.general/issues/9972).
release_summary: Regular bugfix and feature release.
fragments:
- 10.6.0.yml
- 10005-fix-method-exists-in-sysrc.yml
- 10011-github_deploy_key-check-key-present.yml
- 10012-improve-error-handling-homebrew-missing-tap.yml
- 10014-puppet-improve-param.yml
- 10026-stackpath-compute-deprecation.yml
- 10028-manifold-deprecation.yml
- 9646-hpilo-fix-idempotency.yml
- 9833-data-tagging.yml
- 9895-proxmox_tags_with_uppercase_chars.yml
- 9898-keycloak_user-supports-subgroups.yaml
- 9951-mod-php-identifier.yml
- 9952-proxmox-inventory-plugin-improve-ansible_host.yml
- 9953-gitlab-project-members-support-owner-level.yml
- 9959-update-opennebula-onevm-updateconf-params.yml
- 9960-gitlab_project-add-build_timeout-option.yml
- 9962-nmcli-add-infiniband-mac-support.yml
- 9963-proxmox_disk-storage.yml
- 9964-redfish-tls.yml
- 9965-fix-duplicate-jsonify-payload-for-rocketchat-pre740.yml
- 9970-pkcs12_alias_cert_alias_optional.yml
- 9972-zypper-skip-post-errors.yml
- 9976-keycloak_client-fix-idempotency-regression.yml
- 9987-keycloak-auth-flow-fix-config.yaml
- 9992-filtertypeerror.yml
plugins:
connection:
- description: Run tasks in WSL distribution using wsl.exe CLI via SSH.
name: wsl
namespace: null
release_date: '2025-04-21'

View File

@@ -20,3 +20,4 @@ sections:
- guide_vardict
- guide_cmdrunner
- guide_modulehelper
- guide_uthelper

View File

@@ -65,7 +65,7 @@ All three statements are equivalent and give:
.. note:: Be aware that in most cases, filter calls without any argument require ``flatten=true``, otherwise the input is returned as result. The reason for this is, that the input is considered as a variable argument and is wrapped by an additional outer list. ``flatten=true`` ensures that this list is removed before the input is processed by the filter logic.
The filters ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
The filters :ansplugin:`community.general.lists_difference#filter` or :ansplugin:`community.general.lists_symmetric_difference#filter` can be used in the same way as the filters in the examples above. They calculate the difference or the symmetric difference between two or more lists and preserve the item order.
For example, the symmetric difference of ``A``, ``B`` and ``C`` may be written as:

View File

@@ -124,7 +124,7 @@ To get a hash map with all ports and names of a cluster:
var: item
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
vars:
server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].{name: name, port: port}"
To extract ports from all clusters with name starting with 'server1':

View File

@@ -267,24 +267,54 @@ In these descriptions ``value`` refers to the single parameter passed to the for
+------------+-------------------------+
- ``cmd_runner_fmt.as_fixed()``
This method receives one parameter ``arg``, the function expects no ``value`` - if one
is provided then it is ignored.
The function returns ``arg`` as-is.
This method defines one or more fixed arguments that are returned by the generated function
regardless whether ``value`` is passed to it or not.
- Creation:
``cmd_runner_fmt.as_fixed("--version")``
This method accepts these arguments in one of three forms:
* one scalar parameter ``arg``, which will be returned as ``[arg]`` by the function, or
* one sequence parameter, such as a list, ``arg``, which will be returned by the function as ``arg[0]``, or
* multiple parameters ``args``, which will be returned as ``args`` directly by the function.
See the examples below for each one of those forms. And, stressing that the generated function expects no ``value`` - if one
is provided then it is ignored.
- Creation (one scalar argument):
* ``cmd_runner_fmt.as_fixed("--version")``
- Examples:
+---------+-----------------------+
| Value | Outcome |
+=========+=======================+
| | ``["--version"]`` |
+---------+-----------------------+
| 57 | ``["--version"]`` |
+---------+-----------------------+
+---------+--------------------------------------+
| Value | Outcome |
+=========+======================================+
| | * ``["--version"]`` |
+---------+--------------------------------------+
| 57 | * ``["--version"]`` |
+---------+--------------------------------------+
- Creation (one sequence argument):
* ``cmd_runner_fmt.as_fixed(["--list", "--json"])``
- Examples:
+---------+--------------------------------------+
| Value | Outcome |
+=========+======================================+
| | * ``["--list", "--json"]`` |
+---------+--------------------------------------+
| True | * ``["--list", "--json"]`` |
+---------+--------------------------------------+
- Creation (multiple arguments):
* ``cmd_runner_fmt.as_fixed("--one", "--two", "--three")``
- Examples:
+---------+--------------------------------------+
| Value | Outcome |
+=========+======================================+
| | * ``["--one", "--two", "--three"]`` |
+---------+--------------------------------------+
| False | * ``["--one", "--two", "--three"]`` |
+---------+--------------------------------------+
- Note:
This is the only special case in which a value can be missing for the formatting function.
The example also comes from the code in `Quickstart`_.
The first example here comes from the code in `Quickstart`_.
In that case, the module has code to determine the command's version so that it can assert compatibility.
There is no *value* to be passed for that CLI argument.

View File

@@ -0,0 +1,394 @@
..
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_uthelper:
UTHelper Guide
==============
Introduction
^^^^^^^^^^^^
``UTHelper`` was written to reduce the boilerplate code used in unit tests for modules.
It was originally written to handle tests of modules that run external commands using ``AnsibleModule.run_command()``.
At the time of writing (Feb 2025) that remains the only type of tests you can use
``UTHelper`` for, but it aims to provide support for other types of interactions.
Until now, there are many different ways to implement unit tests that validate a module based on the execution of external commands. See some examples:
* `test_apk.py <https://github.com/ansible-collections/community.general/blob/10.3.0/tests/unit/plugins/modules/test_apk.py>`_ - A very simple one
* `test_bootc_manage.py <https://github.com/ansible-collections/community.general/blob/10.3.0/tests/unit/plugins/modules/test_bootc_manage.py>`_ -
This one has more test cases, but do notice how the code is repeated amongst them.
* `test_modprobe.py <https://github.com/ansible-collections/community.general/blob/10.3.0/tests/unit/plugins/modules/test_modprobe.py>`_ -
This one has 15 tests in it, but to achieve that it declares 8 classes repeating quite a lot of code.
As you can notice, there is no consistency in the way these tests are executed -
they all do the same thing eventually, but each one is written in a very distinct way.
``UTHelper`` aims to:
* provide a consistent idiom to define unit tests
* reduce the code to a bare minimal, and
* define tests as data instead
* allow the test cases definition to be expressed not only as a Python data structure but also as YAML content
Quickstart
""""""""""
To use UTHelper, your test module will need only a bare minimal of code:
.. code-block:: python
# tests/unit/plugin/modules/test_ansible_module.py
from ansible_collections.community.general.plugins.modules import ansible_module
from .uthelper import UTHelper, RunCommandMock
UTHelper.from_module(ansible_module, __name__, mocks=[RunCommandMock])
Then, in the test specification file, you have:
.. code-block:: yaml
# tests/unit/plugin/modules/test_ansible_module.yaml
test_cases:
- id: test_ansible_module
flags:
diff: true
input:
state: present
name: Roger the Shrubber
output:
shrubbery:
looks: nice
price: not too expensive
changed: true
diff:
before:
shrubbery: null
after:
shrubbery:
looks: nice
price: not too expensive
mocks:
run_command:
- command: [/testbin/shrubber, --version]
rc: 0
out: "2.80.0\n"
err: ''
- command: [/testbin/shrubber, --make-shrubbery]
rc: 0
out: 'Shrubbery created'
err: ''
.. note::
If you prefer to pick a different YAML file for the test cases, or if you prefer to define them in plain Python,
you can use the convenience methods ``UTHelper.from_file()`` and ``UTHelper.from_spec()``, respectively.
See more details below.
Using ``UTHelper``
^^^^^^^^^^^^^^^^^^
Test Module
"""""""""""
``UTHelper`` is **strictly for unit tests**. To use it, you import the ``.uthelper.UTHelper`` class.
As mentioned in different parts of this guide, there are three different mechanisms to load the test cases.
.. seealso::
See the UTHelper class reference below for API details on the three different mechanisms.
The easies and most recommended way of using ``UTHelper`` is literally the example shown.
See a real world example at
`test_gconftool2.py <https://github.com/ansible-collections/community.general/blob/10.3.0/tests/unit/plugins/modules/test_gconftool2.py>`_.
The ``from_module()`` method will pick the filename of the test module up (in the example above, ``tests/unit/plugins/modules/test_gconftool2.py``)
and it will search for ``tests/unit/plugins/modules/test_gconftool2.yaml`` (or ``.yml`` if that is not found).
In that file it will expect to find the test specification expressed in YAML format, conforming to the structure described below LINK LINK LINK.
If you prefer to read the test specifications a different file path, use ``from_file()`` passing the file handle for the YAML file.
And, if for any reason you prefer or need to pass the data structure rather than dealing with YAML files, use the ``from_spec()`` method.
A real world example for that can be found at
`test_snap.py <https://github.com/ansible-collections/community.general/blob/main/tests/unit/plugins/modules/test_snap.py>`_.
Test Specification
""""""""""""""""""
The structure of the test specification data is described below.
Top level
---------
At the top level there are two accepted keys:
- ``anchors: dict``
Optional. Placeholder for you to define YAML anchors that can be repeated in the test cases.
Its contents are never accessed directly by test Helper.
- ``test_cases: list``
Mandatory. List of test cases, see below for definition.
Test cases
----------
You write the test cases with five elements:
- ``id: str``
Mandatory. Used to identify the test case.
- ``flags: dict``
Optional. Flags controling the behavior of the test case. All flags are optional. Accepted flags:
* ``check: bool``: set to ``true`` if the module is to be executed in **check mode**.
* ``diff: bool``: set to ``true`` if the module is to be executed in **diff mode**.
* ``skip: str``: set the test case to be skipped, providing the message for ``pytest.skip()``.
* ``xfail: str``: set the test case to expect failure, providing the message for ``pytest.xfail()``.
- ``input: dict``
Optional. Parameters for the Ansible module, it can be empty.
- ``output: dict``
Optional. Expected return values from the Ansible module.
All RV names are used here are expected to be found in the module output, but not all RVs in the output must be here.
It can include special RVs such as ``changed`` and ``diff``.
It can be empty.
- ``mocks: dict``
Optional. Mocked interactions, ``run_command`` being the only one supported for now.
Each key in this dictionary refers to one subclass of ``TestCaseMock`` and its
structure is dictated by the ``TestCaseMock`` subclass implementation.
All keys are expected to be named using snake case, as in ``run_command``.
The ``TestCaseMock`` subclass is responsible for defining the name used in the test specification.
The structure for that specification is dependent on the implementing class.
See more details below for the implementation of ``RunCommandMock``
Example using YAML
------------------
We recommend you use ``UTHelper`` reading the test specifications from a YAML file.
See an example below of how one actually looks like (excerpt from ``test_opkg.yaml``):
.. code-block:: yaml
---
anchors:
environ: &env-def {environ_update: {LANGUAGE: C, LC_ALL: C}, check_rc: false}
test_cases:
- id: install_zlibdev
input:
name: zlib-dev
state: present
output:
msg: installed 1 package(s)
mocks:
run_command:
- command: [/testbin/opkg, --version]
environ: *env-def
rc: 0
out: ''
err: ''
- command: [/testbin/opkg, list-installed, zlib-dev]
environ: *env-def
rc: 0
out: ''
err: ''
- command: [/testbin/opkg, install, zlib-dev]
environ: *env-def
rc: 0
out: |
Installing zlib-dev (1.2.11-6) to root...
Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib-dev_1.2.11-6_mips_24kc.ipk
Installing zlib (1.2.11-6) to root...
Downloading https://downloads.openwrt.org/releases/22.03.0/packages/mips_24kc/base/zlib_1.2.11-6_mips_24kc.ipk
Configuring zlib.
Configuring zlib-dev.
err: ''
- command: [/testbin/opkg, list-installed, zlib-dev]
environ: *env-def
rc: 0
out: |
zlib-dev - 1.2.11-6
err: ''
- id: install_zlibdev_present
input:
name: zlib-dev
state: present
output:
msg: package(s) already present
mocks:
run_command:
- command: [/testbin/opkg, --version]
environ: *env-def
rc: 0
out: ''
err: ''
- command: [/testbin/opkg, list-installed, zlib-dev]
environ: *env-def
rc: 0
out: |
zlib-dev - 1.2.11-6
err: ''
TestCaseMocks Specifications
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``TestCaseMock`` subclass is free to define the expected data structure.
RunCommandMock Specification
""""""""""""""""""""""""""""
``RunCommandMock`` mocks can be specified with the key ``run_command`` and it expects a ``list`` in which elements follow the structure:
- ``command: Union[list, str]``
Mandatory. The command that is expected to be executed by the module. It corresponds to the parameter ``args`` of the ``AnsibleModule.run_command()`` call.
It can be either a list or a string, though the list form is generally recommended.
- ``environ: dict``
Mandatory. All other parameters passed to the ``AnsibleModule.run_command()`` call.
Most commonly used are ``environ_update`` and ``check_rc``.
Must include all parameters the Ansible module uses in the ``AnsibleModule.run_command()`` call, otherwise the test will fail.
- ``rc: int``
Mandatory. The return code for the command execution.
As per usual in bash scripting, a value of ``0`` means success, whereas any other number is an error code.
- ``out: str``
Mandatory. The *stdout* result of the command execution, as one single string containing zero or more lines.
- ``err: str``
Mandatory. The *stderr* result of the command execution, as one single string containing zero or more lines.
``UTHelper`` Reference
^^^^^^^^^^^^^^^^^^^^^^
.. py:module:: .uthelper
.. py:class:: UTHelper
A class to encapsulate unit tests.
.. py:staticmethod:: from_spec(ansible_module, test_module, test_spec, mocks=None)
Creates an ``UTHelper`` instance from a given test specification.
:param ansible_module: The Ansible module to be tested.
:type ansible_module: module
:param test_module: The test module.
:type test_module: module
:param test_spec: The test specification.
:type test_spec: dict
:param mocks: List of ``TestCaseMocks`` to be used during testing. Currently only ``RunCommandMock`` exists.
:type mocks: list or None
:return: An ``UTHelper`` instance.
:rtype: UTHelper
Example usage of ``from_spec()``:
.. code-block:: python
import sys
from ansible_collections.community.general.plugins.modules import ansible_module
from .uthelper import UTHelper, RunCommandMock
TEST_SPEC = dict(
test_cases=[
...
]
)
helper = UTHelper.from_spec(ansible_module, sys.modules[__name__], TEST_SPEC, mocks=[RunCommandMock])
.. py:staticmethod:: from_file(ansible_module, test_module, test_spec_filehandle, mocks=None)
Creates an ``UTHelper`` instance from a test specification file.
:param ansible_module: The Ansible module to be tested.
:type ansible_module: module
:param test_module: The test module.
:type test_module: module
:param test_spec_filehandle: A file handle to an file stream handle providing the test specification in YAML format.
:type test_spec_filehandle: file
:param mocks: List of ``TestCaseMocks`` to be used during testing. Currently only ``RunCommandMock`` exists.
:type mocks: list or None
:return: An ``UTHelper`` instance.
:rtype: UTHelper
Example usage of ``from_file()``:
.. code-block:: python
import sys
from ansible_collections.community.general.plugins.modules import ansible_module
from .uthelper import UTHelper, RunCommandMock
with open("test_spec.yaml", "r") as test_spec_filehandle:
helper = UTHelper.from_file(ansible_module, sys.modules[__name__], test_spec_filehandle, mocks=[RunCommandMock])
.. py:staticmethod:: from_module(ansible_module, test_module_name, mocks=None)
Creates an ``UTHelper`` instance from a given Ansible module and test module.
:param ansible_module: The Ansible module to be tested.
:type ansible_module: module
:param test_module_name: The name of the test module. It works if passed ``__name__``.
:type test_module_name: str
:param mocks: List of ``TestCaseMocks`` to be used during testing. Currently only ``RunCommandMock`` exists.
:type mocks: list or None
:return: An ``UTHelper`` instance.
:rtype: UTHelper
Example usage of ``from_module()``:
.. code-block:: python
from ansible_collections.community.general.plugins.modules import ansible_module
from .uthelper import UTHelper, RunCommandMock
# Example usage
helper = UTHelper.from_module(ansible_module, __name__, mocks=[RunCommandMock])
Creating TestCaseMocks
^^^^^^^^^^^^^^^^^^^^^^
To create a new ``TestCaseMock`` you must extend that class and implement the relevant parts:
.. code-block:: python
class ShrubberyMock(TestCaseMock):
# this name is mandatory, it is the name used in the test specification
name = "shrubbery"
def setup(self, mocker):
# perform setup, commonly using mocker to patch some other piece of code
...
def check(self, test_case, results):
# verify the tst execution met the expectations of the test case
# for example the function was called as many times as it should
...
def fixtures(self):
# returns a dict mapping names to pytest fixtures that should be used for the test case
# for example, in RunCommandMock it creates a fixture that patches AnsibleModule.get_bin_path
...
Caveats
^^^^^^^
Known issues/opportunities for improvement:
* Only one ``UTHelper`` per test module: UTHelper injects a test function with a fixed name into the module's namespace,
so placing a second ``UTHelper`` instance is going to overwrite the function created by the first one.
* Order of elements in module's namespace is not consistent across executions in Python 3.5, so if adding more tests to the test module
might make Test Helper add its function before or after the other test functions.
In the community.general collection the CI processes uses ``pytest-xdist`` to paralellize and distribute the tests,
and it requires the order of the tests to be consistent.
.. versionadded:: 7.5.0

View File

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

View File

@@ -17,7 +17,7 @@ action_groups:
proxmox:
- proxmox
- proxmox_backup
- proxmox_backup_info
- proxmox_backup_info
- proxmox_disk
- proxmox_domain_info
- proxmox_group_info
@@ -98,6 +98,10 @@ plugin_routing:
redirect: community.google.gcp_storage_file
hashi_vault:
redirect: community.hashi_vault.hashi_vault
manifold:
deprecation:
removal_version: 11.0.0
warning_text: Company was acquired in 2021 and service was ceased afterwards.
nios:
redirect: infoblox.nios_modules.nios_lookup
nios_next_ip:
@@ -112,17 +116,53 @@ plugin_routing:
atomic_container:
deprecation:
removal_version: 13.0.0
warning_text: Poject Atomic was sunset by the end of 2019.
warning_text: Project Atomic was sunset by the end of 2019.
atomic_host:
deprecation:
removal_version: 13.0.0
warning_text: Poject Atomic was sunset by the end of 2019.
warning_text: Project Atomic was sunset by the end of 2019.
atomic_image:
deprecation:
removal_version: 13.0.0
warning_text: Poject Atomic was sunset by the end of 2019.
warning_text: Project Atomic was sunset by the end of 2019.
cisco_spark:
redirect: community.general.cisco_webex
clc_alert_policy:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_blueprint_package:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_firewall_policy:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_group:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_loadbalancer:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_modify_server:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_publicip:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_server:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
clc_server_snapshot:
deprecation:
removal_version: 11.0.0
warning_text: CenturyLink Cloud services went EOL in September 2023.
consul_acl:
tombstone:
removal_version: 10.0.0
@@ -603,6 +643,26 @@ plugin_routing:
redirect: community.postgresql.postgresql_user
postgresql_user_obj_stat_info:
redirect: community.postgresql.postgresql_user_obj_stat_info
profitbricks:
deprecation:
removal_version: 11.0.0
warning_text: Supporting library is unsupported since 2021.
profitbricks_datacenter:
deprecation:
removal_version: 11.0.0
warning_text: Supporting library is unsupported since 2021.
profitbricks_nic:
deprecation:
removal_version: 11.0.0
warning_text: Supporting library is unsupported since 2021.
profitbricks_volume:
deprecation:
removal_version: 11.0.0
warning_text: Supporting library is unsupported since 2021.
profitbricks_volume_attachments:
deprecation:
removal_version: 11.0.0
warning_text: Supporting library is unsupported since 2021.
purefa_facts:
tombstone:
removal_version: 3.0.0
@@ -908,6 +968,10 @@ plugin_routing:
redirect: community.docker.docker_swarm
kubevirt:
redirect: community.kubevirt.kubevirt
stackpath_compute:
deprecation:
removal_version: 11.0.0
warning_text: The company and the service were sunset in June 2024.
filter:
path_join:
# The ansible.builtin.path_join filter has been added in ansible-base 2.10.

38
noxfile.py Normal file
View File

@@ -0,0 +1,38 @@
# 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
# SPDX-FileCopyrightText: 2025 Felix Fontein <felix@fontein.de>
# /// script
# dependencies = ["nox>=2025.02.09", "antsibull-nox"]
# ///
import sys
import nox
try:
import antsibull_nox
except ImportError:
print("You need to install antsibull-nox in the same Python environment as nox.")
sys.exit(1)
antsibull_nox.load_antsibull_nox_toml()
@nox.session(name="aliases", python=False, default=True)
def aliases(session: nox.Session) -> None:
session.run("python", "tests/sanity/extra/aliases.py")
@nox.session(name="botmeta", default=True)
def botmeta(session: nox.Session) -> None:
session.install("PyYAML", "voluptuous")
session.run("python", "tests/sanity/extra/botmeta.py")
# Allow to run the noxfile with `python noxfile.py`, `pipx run noxfile.py`, or similar.
# Requires nox >= 2025.02.09
if __name__ == "__main__":
nox.main()

View File

@@ -785,6 +785,12 @@ from ansible.vars.manager import VariableManager
from ansible.plugins.callback.default import CallbackModule as Default
from ansible.module_utils.common.text.converters import to_text
try:
from ansible.template import trust_as_template # noqa: F401, pylint: disable=unused-import
SUPPORTS_DATA_TAGGING = True
except ImportError:
SUPPORTS_DATA_TAGGING = False
class DummyStdout(object):
def flush(self):
@@ -838,7 +844,10 @@ class CallbackModule(Default):
return _ret
def _using_diy(self, spec):
return (spec['msg'] is not None) and (spec['msg'] != spec['vars']['omit'])
sentinel = object()
omit = spec['vars'].get('omit', sentinel)
# With Data Tagging, omit is sentinel
return (spec['msg'] is not None) and (spec['msg'] != omit or omit is sentinel)
def _parent_has_callback(self):
return hasattr(super(CallbackModule, self), sys._getframe(1).f_code.co_name)
@@ -894,7 +903,7 @@ class CallbackModule(Default):
)
_ret.update(_all)
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: CallbackDIYDict()}))
_ret.update(_ret.get(self.DIY_NS, {self.DIY_NS: {} if SUPPORTS_DATA_TAGGING else CallbackDIYDict()}))
_ret[self.DIY_NS].update({'playbook': {}})
_playbook_attributes = ['entries', 'file_name', 'basedir']

View File

@@ -18,6 +18,11 @@ short_description: Sends play events to a Slack channel
description:
- This is an ansible callback plugin that sends status updates to a Slack channel during playbook execution.
options:
http_agent:
description:
- HTTP user agent to use for requests to Slack.
type: string
version_added: "10.5.0"
webhook_url:
required: true
description: Slack Webhook URL.
@@ -106,7 +111,7 @@ class CallbackModule(CallbackBase):
self.username = self.get_option('username')
self.show_invocation = (self._display.verbosity > 1)
self.validate_certs = self.get_option('validate_certs')
self.http_agent = self.get_option('http_agent')
if self.webhook_url is None:
self.disabled = True
self._display.warning('Slack Webhook URL was not provided. The '
@@ -132,8 +137,13 @@ class CallbackModule(CallbackBase):
self._display.debug(data)
self._display.debug(self.webhook_url)
try:
response = open_url(self.webhook_url, data=data, validate_certs=self.validate_certs,
headers=headers)
response = open_url(
self.webhook_url,
data=data,
validate_certs=self.validate_certs,
headers=headers,
http_agent=self.http_agent,
)
return response.read()
except Exception as e:
self._display.warning(f'Could not submit message to Slack: {e}')

View File

@@ -53,29 +53,77 @@ def should_use_block(value):
return False
class MyDumper(AnsibleDumper):
def represent_scalar(self, tag, value, style=None):
"""Uses block style for multi-line strings"""
if style is None:
if should_use_block(value):
style = '|'
# we care more about readable than accuracy, so...
# ...no trailing space
value = value.rstrip()
# ...and non-printable characters
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding
value = value.expandtabs()
# ...and odd bits of whitespace
value = re.sub(r'[\x0b\x0c\r]', '', value)
# ...as does trailing space
value = re.sub(r' +\n', '\n', value)
else:
style = self.default_style
node = yaml.representer.ScalarNode(tag, value, style=style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
return node
try:
class MyDumper(AnsibleDumper): # pylint: disable=inherit-non-class
def represent_scalar(self, tag, value, style=None):
"""Uses block style for multi-line strings"""
if style is None:
if should_use_block(value):
style = '|'
# we care more about readable than accuracy, so...
# ...no trailing space
value = value.rstrip()
# ...and non-printable characters
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding
value = value.expandtabs()
# ...and odd bits of whitespace
value = re.sub(r'[\x0b\x0c\r]', '', value)
# ...as does trailing space
value = re.sub(r' +\n', '\n', value)
else:
style = self.default_style
node = yaml.representer.ScalarNode(tag, value, style=style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
return node
except: # noqa: E722, pylint: disable=bare-except
# This happens with Data Tagging, see https://github.com/ansible/ansible/issues/84781
# Until there is a better solution we'll resort to using ansible-core internals.
from ansible._internal._yaml import _dumper
import typing as t
class MyDumper(_dumper._BaseDumper):
# This code is mostly taken from ansible._internal._yaml._dumper
@classmethod
def _register_representers(cls) -> None:
cls.add_multi_representer(_dumper.AnsibleTaggedObject, cls.represent_ansible_tagged_object)
cls.add_multi_representer(_dumper.Tripwire, cls.represent_tripwire)
cls.add_multi_representer(_dumper.c.Mapping, _dumper.SafeRepresenter.represent_dict)
cls.add_multi_representer(_dumper.c.Sequence, _dumper.SafeRepresenter.represent_list)
def represent_ansible_tagged_object(self, data):
if ciphertext := _dumper.VaultHelper.get_ciphertext(data, with_tags=False):
return self.represent_scalar('!vault', ciphertext, style='|')
return self.represent_data(_dumper.AnsibleTagHelper.as_native_type(data)) # automatically decrypts encrypted strings
def represent_tripwire(self, data: _dumper.Tripwire) -> t.NoReturn:
data.trip()
# The following function is the same as in the try/except
def represent_scalar(self, tag, value, style=None):
"""Uses block style for multi-line strings"""
if style is None:
if should_use_block(value):
style = '|'
# we care more about readable than accuracy, so...
# ...no trailing space
value = value.rstrip()
# ...and non-printable characters
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding
value = value.expandtabs()
# ...and odd bits of whitespace
value = re.sub(r'[\x0b\x0c\r]', '', value)
# ...as does trailing space
value = re.sub(r' +\n', '\n', value)
else:
style = self.default_style
node = yaml.representer.ScalarNode(tag, value, style=style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
return node
class CallbackModule(Default):

View File

@@ -32,6 +32,15 @@ options:
vars:
- name: ansible_executable
- name: ansible_incus_executable
incus_become_method:
description:
- Become command used to switch to a non-root user.
- Is only used when O(remote_user) is not V(root).
type: str
default: /bin/su
vars:
- name: incus_become_method
version_added: 10.4.0
remote:
description:
- The name of the Incus remote to use (per C(incus remote list)).
@@ -40,6 +49,22 @@ options:
default: local
vars:
- name: ansible_incus_remote
remote_user:
description:
- User to login/authenticate as.
- Can be set from the CLI via the C(--user) or C(-u) options.
type: string
default: root
vars:
- name: ansible_user
env:
- name: ANSIBLE_REMOTE_USER
ini:
- section: defaults
key: remote_user
keyword:
- name: remote_user
version_added: 10.4.0
project:
description:
- The name of the Incus project to use (per C(incus project list)).
@@ -64,7 +89,6 @@ class Connection(ConnectionBase):
transport = "incus"
has_pipelining = True
default_user = 'root'
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
@@ -79,10 +103,34 @@ class Connection(ConnectionBase):
super(Connection, self)._connect()
if not self._connected:
self._display.vvv("ESTABLISH Incus CONNECTION FOR USER: root",
self._display.vvv(f"ESTABLISH Incus CONNECTION FOR USER: {self.get_option('remote_user')}",
host=self._instance())
self._connected = True
def _build_command(self, cmd) -> str:
"""build the command to execute on the incus host"""
exec_cmd = [
self._incus_cmd,
"--project", self.get_option("project"),
"exec",
f"{self.get_option('remote')}:{self._instance()}",
"--"]
if self.get_option("remote_user") != "root":
self._display.vvv(
f"INFO: Running as non-root user: {self.get_option('remote_user')}, \
trying to run 'incus exec' with become method: {self.get_option('incus_become_method')}",
host=self._instance(),
)
exec_cmd.extend(
[self.get_option("incus_become_method"), self.get_option("remote_user"), "-c"]
)
exec_cmd.extend([self.get_option("executable"), "-c", cmd])
return exec_cmd
def _instance(self):
# Return only the leading part of the FQDN as the instance name
# as Incus instance names cannot be a FQDN.
@@ -95,13 +143,8 @@ class Connection(ConnectionBase):
self._display.vvv(f"EXEC {cmd}",
host=self._instance())
local_cmd = [
self._incus_cmd,
"--project", self.get_option("project"),
"exec",
f"{self.get_option('remote')}:{self._instance()}",
"--",
self._play_context.executable, "-c", cmd]
local_cmd = self._build_command(cmd)
self._display.vvvvv(f"EXEC {local_cmd}", host=self._instance())
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
@@ -120,6 +163,25 @@ class Connection(ConnectionBase):
return process.returncode, stdout, stderr
def _get_remote_uid_gid(self) -> tuple[int, int]:
"""Get the user and group ID of 'remote_user' from the instance."""
rc, uid_out, err = self.exec_command("/bin/id -u")
if rc != 0:
raise AnsibleError(
f"Failed to get remote uid for user {self.get_option('remote_user')}: {err}"
)
uid = uid_out.strip()
rc, gid_out, err = self.exec_command("/bin/id -g")
if rc != 0:
raise AnsibleError(
f"Failed to get remote gid for user {self.get_option('remote_user')}: {err}"
)
gid = gid_out.strip()
return int(uid), int(gid)
def put_file(self, in_path, out_path):
""" put a file from local to Incus """
super(Connection, self).put_file(in_path, out_path)
@@ -130,12 +192,35 @@ class Connection(ConnectionBase):
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
raise AnsibleFileNotFound(f"input path is not a file: {in_path}")
local_cmd = [
self._incus_cmd,
"--project", self.get_option("project"),
"file", "push", "--quiet",
in_path,
f"{self.get_option('remote')}:{self._instance()}/{out_path}"]
if self.get_option("remote_user") != "root":
uid, gid = self._get_remote_uid_gid()
local_cmd = [
self._incus_cmd,
"--project",
self.get_option("project"),
"file",
"push",
"--uid",
str(uid),
"--gid",
str(gid),
"--quiet",
in_path,
f"{self.get_option('remote')}:{self._instance()}/{out_path}",
]
else:
local_cmd = [
self._incus_cmd,
"--project",
self.get_option("project"),
"file",
"push",
"--quiet",
in_path,
f"{self.get_option('remote')}:{self._instance()}/{out_path}",
]
self._display.vvvvv(f"PUT {local_cmd}", host=self._instance())
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]

View File

@@ -32,6 +32,15 @@ options:
vars:
- name: ansible_executable
- name: ansible_lxd_executable
lxd_become_method:
description:
- Become command used to switch to a non-root user.
- Is only used when O(remote_user) is not V(root).
type: str
default: /bin/su
vars:
- name: lxd_become_method
version_added: 10.4.0
remote:
description:
- Name of the LXD remote to use.
@@ -40,6 +49,22 @@ options:
vars:
- name: ansible_lxd_remote
version_added: 2.0.0
remote_user:
description:
- User to login/authenticate as.
- Can be set from the CLI via the C(--user) or C(-u) options.
type: string
default: root
vars:
- name: ansible_user
env:
- name: ANSIBLE_REMOTE_USER
ini:
- section: defaults
key: remote_user
keyword:
- name: remote_user
version_added: 10.4.0
project:
description:
- Name of the LXD project to use.
@@ -63,7 +88,6 @@ class Connection(ConnectionBase):
transport = 'community.general.lxd'
has_pipelining = True
default_user = 'root'
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
@@ -73,9 +97,6 @@ class Connection(ConnectionBase):
except ValueError:
raise AnsibleError("lxc command not found in PATH")
if self._play_context.remote_user is not None and self._play_context.remote_user != 'root':
self._display.warning('lxd does not support remote_user, using default: root')
def _host(self):
""" translate remote_addr to lxd (short) hostname """
return self.get_option("remote_addr").split(".", 1)[0]
@@ -85,25 +106,40 @@ class Connection(ConnectionBase):
super(Connection, self)._connect()
if not self._connected:
self._display.vvv("ESTABLISH LXD CONNECTION FOR USER: root", host=self._host())
self._display.vvv(f"ESTABLISH LXD CONNECTION FOR USER: {self.get_option('remote_user')}", host=self._host())
self._connected = True
def _build_command(self, cmd) -> str:
"""build the command to execute on the lxd host"""
exec_cmd = [self._lxc_cmd]
if self.get_option("project"):
exec_cmd.extend(["--project", self.get_option("project")])
exec_cmd.extend(["exec", f"{self.get_option('remote')}:{self._host()}", "--"])
if self.get_option("remote_user") != "root":
self._display.vvv(
f"INFO: Running as non-root user: {self.get_option('remote_user')}, \
trying to run 'lxc exec' with become method: {self.get_option('lxd_become_method')}",
host=self._host(),
)
exec_cmd.extend(
[self.get_option("lxd_become_method"), self.get_option("remote_user"), "-c"]
)
exec_cmd.extend([self.get_option("executable"), "-c", cmd])
return exec_cmd
def exec_command(self, cmd, in_data=None, sudoable=True):
""" execute a command on the lxd host """
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
self._display.vvv(f"EXEC {cmd}", host=self._host())
local_cmd = [self._lxc_cmd]
if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"exec",
f"{self.get_option('remote')}:{self._host()}",
"--",
self.get_option("executable"), "-c", cmd
])
local_cmd = self._build_command(cmd)
self._display.vvvvv(f"EXEC {local_cmd}", host=self._host())
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@@ -125,6 +161,25 @@ class Connection(ConnectionBase):
return process.returncode, stdout, stderr
def _get_remote_uid_gid(self) -> tuple[int, int]:
"""Get the user and group ID of 'remote_user' from the instance."""
rc, uid_out, err = self.exec_command("/bin/id -u")
if rc != 0:
raise AnsibleError(
f"Failed to get remote uid for user {self.get_option('remote_user')}: {err}"
)
uid = uid_out.strip()
rc, gid_out, err = self.exec_command("/bin/id -g")
if rc != 0:
raise AnsibleError(
f"Failed to get remote gid for user {self.get_option('remote_user')}: {err}"
)
gid = gid_out.strip()
return int(uid), int(gid)
def put_file(self, in_path, out_path):
""" put a file from local to lxd """
super(Connection, self).put_file(in_path, out_path)
@@ -137,11 +192,32 @@ class Connection(ConnectionBase):
local_cmd = [self._lxc_cmd]
if self.get_option("project"):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"file", "push",
in_path,
f"{self.get_option('remote')}:{self._host()}/{out_path}"
])
if self.get_option("remote_user") != "root":
uid, gid = self._get_remote_uid_gid()
local_cmd.extend(
[
"file",
"push",
"--uid",
str(uid),
"--gid",
str(gid),
in_path,
f"{self.get_option('remote')}:{self._host()}/{out_path}",
]
)
else:
local_cmd.extend(
[
"file",
"push",
in_path,
f"{self.get_option('remote')}:{self._host()}/{out_path}",
]
)
self._display.vvvvv(f"PUT {local_cmd}", host=self._host())
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]

786
plugins/connection/wsl.py Normal file
View File

@@ -0,0 +1,786 @@
# -*- coding: utf-8 -*-
# Derived from ansible/plugins/connection/proxmox_pct_remote.py (c) 2024 Nils Stein (@mietzen) <github.nstein@mailbox.org>
# Derived from ansible/plugins/connection/paramiko_ssh.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
# Copyright (c) 2025 Rui Lopes (@rgl) <ruilopes.com>
# Copyright (c) 2025 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"""
author: Rui Lopes (@rgl) <ruilopes.com>
name: wsl
short_description: Run tasks in WSL distribution using wsl.exe CLI via SSH
requirements:
- paramiko
description:
- Run commands or put/fetch files to an existing WSL distribution using wsl.exe CLI via SSH.
- Uses the Python SSH implementation (Paramiko) to connect to the WSL host.
version_added: "10.6.0"
options:
remote_addr:
description:
- Address of the remote target.
default: inventory_hostname
type: string
vars:
- name: inventory_hostname
- name: ansible_host
- name: ansible_ssh_host
- name: ansible_paramiko_host
port:
description: Remote port to connect to.
type: int
default: 22
ini:
- section: defaults
key: remote_port
- section: paramiko_connection
key: remote_port
env:
- name: ANSIBLE_REMOTE_PORT
- name: ANSIBLE_REMOTE_PARAMIKO_PORT
vars:
- name: ansible_port
- name: ansible_ssh_port
- name: ansible_paramiko_port
keyword:
- name: port
remote_user:
description:
- User to login/authenticate as.
- Can be set from the CLI via the C(--user) or C(-u) options.
type: string
vars:
- name: ansible_user
- name: ansible_ssh_user
- name: ansible_paramiko_user
env:
- name: ANSIBLE_REMOTE_USER
- name: ANSIBLE_PARAMIKO_REMOTE_USER
ini:
- section: defaults
key: remote_user
- section: paramiko_connection
key: remote_user
keyword:
- name: remote_user
password:
description:
- Secret used to either login the SSH server or as a passphrase for SSH keys that require it.
- Can be set from the CLI via the C(--ask-pass) option.
type: string
vars:
- name: ansible_password
- name: ansible_ssh_pass
- name: ansible_ssh_password
- name: ansible_paramiko_pass
- name: ansible_paramiko_password
use_rsa_sha2_algorithms:
description:
- Whether or not to enable RSA SHA2 algorithms for pubkeys and hostkeys.
- On paramiko versions older than 2.9, this only affects hostkeys.
- For behavior matching paramiko<2.9 set this to V(false).
vars:
- name: ansible_paramiko_use_rsa_sha2_algorithms
ini:
- {key: use_rsa_sha2_algorithms, section: paramiko_connection}
env:
- {name: ANSIBLE_PARAMIKO_USE_RSA_SHA2_ALGORITHMS}
default: true
type: boolean
host_key_auto_add:
description: "Automatically add host keys to C(~/.ssh/known_hosts)."
env:
- name: ANSIBLE_PARAMIKO_HOST_KEY_AUTO_ADD
ini:
- key: host_key_auto_add
section: paramiko_connection
type: boolean
look_for_keys:
default: True
description: "Set to V(false) to disable searching for private key files in C(~/.ssh/)."
env:
- name: ANSIBLE_PARAMIKO_LOOK_FOR_KEYS
ini:
- {key: look_for_keys, section: paramiko_connection}
type: boolean
proxy_command:
default: ""
description:
- Proxy information for running the connection via a jumphost.
- This option is supported by paramiko version 1.9.0 or newer.
type: string
env:
- name: ANSIBLE_PARAMIKO_PROXY_COMMAND
ini:
- {key: proxy_command, section: paramiko_connection}
vars:
- name: ansible_paramiko_proxy_command
record_host_keys:
default: True
description: "Save the host keys to a file."
env:
- name: ANSIBLE_PARAMIKO_RECORD_HOST_KEYS
ini:
- section: paramiko_connection
key: record_host_keys
type: boolean
host_key_checking:
description: "Set this to V(false) if you want to avoid host key checking by the underlying tools Ansible uses to connect to the host."
type: boolean
default: true
env:
- name: ANSIBLE_HOST_KEY_CHECKING
- name: ANSIBLE_SSH_HOST_KEY_CHECKING
- name: ANSIBLE_PARAMIKO_HOST_KEY_CHECKING
ini:
- section: defaults
key: host_key_checking
- section: paramiko_connection
key: host_key_checking
vars:
- name: ansible_host_key_checking
- name: ansible_ssh_host_key_checking
- name: ansible_paramiko_host_key_checking
use_persistent_connections:
description: "Toggles the use of persistence for connections."
type: boolean
default: False
env:
- name: ANSIBLE_USE_PERSISTENT_CONNECTIONS
ini:
- section: defaults
key: use_persistent_connections
banner_timeout:
type: float
default: 30
description:
- Configures, in seconds, the amount of time to wait for the SSH
banner to be presented.
- This option is supported by paramiko version 1.15.0 or newer.
ini:
- section: paramiko_connection
key: banner_timeout
env:
- name: ANSIBLE_PARAMIKO_BANNER_TIMEOUT
timeout:
type: int
default: 10
description:
- Number of seconds until the plugin gives up on failing to establish a TCP connection.
- This option is supported by paramiko version 2.2.0 or newer.
ini:
- section: defaults
key: timeout
- section: ssh_connection
key: timeout
- section: paramiko_connection
key: timeout
env:
- name: ANSIBLE_TIMEOUT
- name: ANSIBLE_SSH_TIMEOUT
- name: ANSIBLE_PARAMIKO_TIMEOUT
vars:
- name: ansible_ssh_timeout
- name: ansible_paramiko_timeout
cli:
- name: timeout
lock_file_timeout:
type: int
default: 60
description: Number of seconds until the plugin gives up on trying to write a lock file when writing SSH known host keys.
vars:
- name: ansible_lock_file_timeout
env:
- name: ANSIBLE_LOCK_FILE_TIMEOUT
private_key_file:
description:
- Path to private key file to use for authentication.
type: path
ini:
- section: defaults
key: private_key_file
- section: paramiko_connection
key: private_key_file
env:
- name: ANSIBLE_PRIVATE_KEY_FILE
- name: ANSIBLE_PARAMIKO_PRIVATE_KEY_FILE
vars:
- name: ansible_private_key_file
- name: ansible_ssh_private_key_file
- name: ansible_paramiko_private_key_file
cli:
- name: private_key_file
option: "--private-key"
user_known_hosts_file:
description:
- Path to the user known hosts file.
- Used to verify the ssh hosts keys.
type: path
default: ~/.ssh/known_hosts
ini:
- section: paramiko_connection
key: user_known_hosts_file
vars:
- name: ansible_paramiko_user_known_hosts_file
wsl_distribution:
description:
- WSL distribution name
type: string
required: true
vars:
- name: wsl_distribution
wsl_user:
description:
- WSL distribution user
type: string
vars:
- name: wsl_user
become_user:
description:
- WSL distribution user
type: string
default: root
vars:
- name: become_user
- name: ansible_become_user
become:
description:
- whether to use the user defined by ansible_become_user.
type: bool
default: false
vars:
- name: become
- name: ansible_become
"""
EXAMPLES = r"""
# ------------------------
# Inventory: inventory.yml
# ------------------------
---
all:
children:
wsl:
hosts:
example-wsl-ubuntu:
ansible_host: 10.0.0.10
wsl_distribution: ubuntu
wsl_user: ubuntu
vars:
ansible_connection: community.general.wsl
ansible_user: vagrant
# ----------------------
# Playbook: playbook.yml
# ----------------------
---
- name: WSL Example
hosts: wsl
gather_facts: true
become: true
tasks:
- name: Ping
ansible.builtin.ping:
- name: Id (with become false)
become: false
changed_when: false
args:
executable: /bin/bash
ansible.builtin.shell: |
exec 2>&1
set -x
echo "$0"
pwd
id
- name: Id (with become true)
changed_when: false
args:
executable: /bin/bash
ansible.builtin.shell: |
exec 2>&1
set -x
echo "$0"
pwd
id
- name: Reboot
ansible.builtin.reboot:
boot_time_command: systemctl show -p ActiveEnterTimestamp init.scope
"""
import io
import os
import pathlib
import shlex
import socket
import tempfile
import typing as t
from ansible.errors import (
AnsibleAuthenticationFailure,
AnsibleConnectionFailure,
AnsibleError,
)
from ansible_collections.community.general.plugins.module_utils._filelock import FileLock, LockTimeout
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.compat.paramiko import PARAMIKO_IMPORT_ERR, paramiko
from ansible.module_utils.compat.version import LooseVersion
from ansible.playbook.play_context import PlayContext
from ansible.plugins.connection import ConnectionBase
from ansible.utils.display import Display
from ansible.utils.path import makedirs_safe
from binascii import hexlify
from subprocess import list2cmdline
if t.TYPE_CHECKING and paramiko:
from paramiko import MissingHostKeyPolicy
from paramiko.client import SSHClient
from paramiko.pkey import PKey
else:
MissingHostKeyPolicy: type = object
SSHClient: type = object
PKey: type = object
display = Display()
def authenticity_msg(hostname: str, ktype: str, fingerprint: str) -> str:
msg = f"""
paramiko: The authenticity of host '{hostname}' can't be established.
The {ktype} key fingerprint is {fingerprint}.
Are you sure you want to continue connecting (yes/no)?
"""
return msg
class MyAddPolicy(MissingHostKeyPolicy):
"""
Based on AutoAddPolicy in paramiko so we can determine when keys are added
and also prompt for input.
Policy for automatically adding the hostname and new host key to the
local L{HostKeys} object, and saving it. This is used by L{SSHClient}.
"""
def __init__(self, connection: Connection) -> None:
self.connection = connection
self._options = connection._options
def missing_host_key(self, client: SSHClient, hostname: str, key: PKey) -> None:
if all((self.connection.get_option('host_key_checking'), not self.connection.get_option('host_key_auto_add'))):
fingerprint = hexlify(key.get_fingerprint())
ktype = key.get_name()
if self.connection.get_option('use_persistent_connections') or self.connection.force_persistence:
# don't print the prompt string since the user cannot respond
# to the question anyway
raise AnsibleError(authenticity_msg(hostname, ktype, fingerprint)[1:92])
inp = to_text(
display.prompt_until(authenticity_msg(hostname, ktype, fingerprint), private=False),
errors='surrogate_or_strict'
)
if inp.lower() not in ['yes', 'y', '']:
raise AnsibleError('host connection rejected by user')
key._added_by_ansible_this_time = True
# existing implementation below:
client._host_keys.add(hostname, key.get_name(), key)
# host keys are actually saved in close() function below
# in order to control ordering.
class Connection(ConnectionBase):
""" SSH based connections (paramiko) to WSL """
transport = 'community.general.wsl'
_log_channel: str | None = None
def __init__(self, play_context: PlayContext, new_stdin: io.TextIOWrapper | None = None, *args: t.Any, **kwargs: t.Any):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
def _set_log_channel(self, name: str) -> None:
""" Mimic paramiko.SSHClient.set_log_channel """
self._log_channel = name
def _parse_proxy_command(self, port: int = 22) -> dict[str, t.Any]:
proxy_command = self.get_option('proxy_command') or None
sock_kwarg = {}
if proxy_command:
replacers: t.Dict[str, str] = {
'%h': self.get_option('remote_addr'),
'%p': str(port),
'%r': self.get_option('remote_user')
}
for find, replace in replacers.items():
proxy_command = proxy_command.replace(find, replace)
try:
sock_kwarg = {'sock': paramiko.ProxyCommand(proxy_command)}
display.vvv(f'CONFIGURE PROXY COMMAND FOR CONNECTION: {proxy_command}', host=self.get_option('remote_addr'))
except AttributeError:
display.warning('Paramiko ProxyCommand support unavailable. '
'Please upgrade to Paramiko 1.9.0 or newer. '
'Not using configured ProxyCommand')
return sock_kwarg
def _connect(self) -> Connection:
""" activates the connection object """
if paramiko is None:
raise AnsibleError(f'paramiko is not installed: {to_native(PARAMIKO_IMPORT_ERR)}')
port = self.get_option('port')
display.vvv(f'ESTABLISH PARAMIKO SSH CONNECTION FOR USER: {self.get_option("remote_user")} on PORT {to_text(port)} TO {self.get_option("remote_addr")}',
host=self.get_option('remote_addr'))
ssh = paramiko.SSHClient()
# Set pubkey and hostkey algorithms to disable, the only manipulation allowed currently
# is keeping or omitting rsa-sha2 algorithms
# default_keys: t.Tuple[str] = ()
paramiko_preferred_pubkeys = getattr(paramiko.Transport, '_preferred_pubkeys', ())
paramiko_preferred_hostkeys = getattr(paramiko.Transport, '_preferred_keys', ())
use_rsa_sha2_algorithms = self.get_option('use_rsa_sha2_algorithms')
disabled_algorithms: t.Dict[str, t.Iterable[str]] = {}
if not use_rsa_sha2_algorithms:
if paramiko_preferred_pubkeys:
disabled_algorithms['pubkeys'] = tuple(a for a in paramiko_preferred_pubkeys if 'rsa-sha2' in a)
if paramiko_preferred_hostkeys:
disabled_algorithms['keys'] = tuple(a for a in paramiko_preferred_hostkeys if 'rsa-sha2' in a)
# override paramiko's default logger name
if self._log_channel is not None:
ssh.set_log_channel(self._log_channel)
self.keyfile = os.path.expanduser(self.get_option('user_known_hosts_file'))
if self.get_option('host_key_checking'):
for ssh_known_hosts in ('/etc/ssh/ssh_known_hosts', '/etc/openssh/ssh_known_hosts', self.keyfile):
try:
ssh.load_system_host_keys(ssh_known_hosts)
break
except IOError:
pass # file was not found, but not required to function
except paramiko.hostkeys.InvalidHostKey as e:
raise AnsibleConnectionFailure(f'Invalid host key: {to_text(e.line)}')
try:
ssh.load_system_host_keys()
except paramiko.hostkeys.InvalidHostKey as e:
raise AnsibleConnectionFailure(f'Invalid host key: {to_text(e.line)}')
ssh_connect_kwargs = self._parse_proxy_command(port)
ssh.set_missing_host_key_policy(MyAddPolicy(self))
conn_password = self.get_option('password')
allow_agent = True
if conn_password is not None:
allow_agent = False
try:
key_filename = None
if self.get_option('private_key_file'):
key_filename = os.path.expanduser(self.get_option('private_key_file'))
# paramiko 2.2 introduced auth_timeout parameter
if LooseVersion(paramiko.__version__) >= LooseVersion('2.2.0'):
ssh_connect_kwargs['auth_timeout'] = self.get_option('timeout')
# paramiko 1.15 introduced banner timeout parameter
if LooseVersion(paramiko.__version__) >= LooseVersion('1.15.0'):
ssh_connect_kwargs['banner_timeout'] = self.get_option('banner_timeout')
ssh.connect(
self.get_option('remote_addr').lower(),
username=self.get_option('remote_user'),
allow_agent=allow_agent,
look_for_keys=self.get_option('look_for_keys'),
key_filename=key_filename,
password=conn_password,
timeout=self.get_option('timeout'),
port=port,
disabled_algorithms=disabled_algorithms,
**ssh_connect_kwargs,
)
except paramiko.ssh_exception.BadHostKeyException as e:
raise AnsibleConnectionFailure(f'host key mismatch for {to_text(e.hostname)}')
except paramiko.ssh_exception.AuthenticationException as e:
msg = f'Failed to authenticate: {e}'
raise AnsibleAuthenticationFailure(msg)
except Exception as e:
msg = to_text(e)
if u'PID check failed' in msg:
raise AnsibleError('paramiko version issue, please upgrade paramiko on the machine running ansible')
elif u'Private key file is encrypted' in msg:
msg = f'ssh {self.get_option("remote_user")}@{self.get_options("remote_addr")}:{port} : ' + \
f'{msg}\nTo connect as a different user, use -u <username>.'
raise AnsibleConnectionFailure(msg)
else:
raise AnsibleConnectionFailure(msg)
self.ssh = ssh
self._connected = True
return self
def _any_keys_added(self) -> bool:
for hostname, keys in self.ssh._host_keys.items():
for keytype, key in keys.items():
added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if added_this_time:
return True
return False
def _save_ssh_host_keys(self, filename: str) -> None:
"""
not using the paramiko save_ssh_host_keys function as we want to add new SSH keys at the bottom so folks
don't complain about it :)
"""
if not self._any_keys_added():
return
path = os.path.expanduser('~/.ssh')
makedirs_safe(path)
with open(filename, 'w') as f:
for hostname, keys in self.ssh._host_keys.items():
for keytype, key in keys.items():
# was f.write
added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if not added_this_time:
f.write(f'{hostname} {keytype} {key.get_base64()}\n')
for hostname, keys in self.ssh._host_keys.items():
for keytype, key in keys.items():
added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if added_this_time:
f.write(f'{hostname} {keytype} {key.get_base64()}\n')
def _build_wsl_command(self, cmd: str) -> str:
wsl_distribution = self.get_option('wsl_distribution')
become = self.get_option('become')
become_user = self.get_option('become_user')
if become and become_user:
wsl_user = become_user
else:
wsl_user = self.get_option('wsl_user')
args = ['wsl.exe', '--distribution', wsl_distribution]
if wsl_user:
args.extend(['--user', wsl_user])
args.extend(['--'])
args.extend(shlex.split(cmd))
if os.getenv('_ANSIBLE_TEST_WSL_CONNECTION_PLUGIN_Waeri5tepheeSha2fae8'):
return shlex.join(args)
return list2cmdline(args) # see https://github.com/python/cpython/blob/3.11/Lib/subprocess.py#L576
def exec_command(self, cmd: str, in_data: bytes | None = None, sudoable: bool = True) -> tuple[int, bytes, bytes]:
""" run a command on inside a WSL distribution """
cmd = self._build_wsl_command(cmd)
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
bufsize = 4096
try:
self.ssh.get_transport().set_keepalive(5)
chan = self.ssh.get_transport().open_session()
except Exception as e:
text_e = to_text(e)
msg = 'Failed to open session'
if text_e:
msg += f': {text_e}'
raise AnsibleConnectionFailure(to_native(msg))
display.vvv(f'EXEC {cmd}', host=self.get_option('remote_addr'))
cmd = to_bytes(cmd, errors='surrogate_or_strict')
no_prompt_out = b''
no_prompt_err = b''
become_output = b''
try:
chan.exec_command(cmd)
if self.become and self.become.expect_prompt():
password_prompt = False
become_success = False
while not (become_success or password_prompt):
display.debug('Waiting for Privilege Escalation input')
chunk = chan.recv(bufsize)
display.debug(f'chunk is: {to_text(chunk)}')
if not chunk:
if b'unknown user' in become_output:
n_become_user = to_native(self.become.get_option('become_user'))
raise AnsibleError(f'user {n_become_user} does not exist')
else:
break
# raise AnsibleError('ssh connection closed waiting for password prompt')
become_output += chunk
# need to check every line because we might get lectured
# and we might get the middle of a line in a chunk
for line in become_output.splitlines(True):
if self.become.check_success(line):
become_success = True
break
elif self.become.check_password_prompt(line):
password_prompt = True
break
if password_prompt:
if self.become:
become_pass = self.become.get_option('become_pass')
chan.sendall(to_bytes(become_pass + '\n', errors='surrogate_or_strict'))
else:
raise AnsibleError('A password is required but none was supplied')
else:
no_prompt_out += become_output
no_prompt_err += become_output
if in_data:
for i in range(0, len(in_data), bufsize):
chan.send(in_data[i:i + bufsize])
chan.shutdown_write()
elif in_data == b'':
chan.shutdown_write()
except socket.timeout:
raise AnsibleError('ssh timed out waiting for privilege escalation.\n' + to_text(become_output))
stdout = b''.join(chan.makefile('rb', bufsize))
stderr = b''.join(chan.makefile_stderr('rb', bufsize))
returncode = chan.recv_exit_status()
# NB the full english error message is:
# 'wsl.exe' is not recognized as an internal or external command,
# operable program or batch file.
if "'wsl.exe' is not recognized" in stderr.decode('utf-8'):
raise AnsibleError(
f'wsl.exe not found in path of host: {to_text(self.get_option("remote_addr"))}')
return (returncode, no_prompt_out + stdout, no_prompt_out + stderr)
def put_file(self, in_path: str, out_path: str) -> None:
""" transfer a file from local to remote """
display.vvv(f'PUT {in_path} TO {out_path}', host=self.get_option('remote_addr'))
try:
with open(in_path, 'rb') as f:
data = f.read()
returncode, stdout, stderr = self.exec_command(
' '.join([
self._shell.executable, '-c',
self._shell.quote(f'cat > {out_path}')]),
in_data=data,
sudoable=False)
if returncode != 0:
if 'cat: not found' in stderr.decode('utf-8'):
raise AnsibleError(
f'cat not found in path of WSL distribution: {to_text(self.get_option("wsl_distribution"))}')
raise AnsibleError(
f'{to_text(stdout)}\n{to_text(stderr)}')
except Exception as e:
raise AnsibleError(
f'error occurred while putting file from {in_path} to {out_path}!\n{to_text(e)}')
def fetch_file(self, in_path: str, out_path: str) -> None:
""" save a remote file to the specified path """
display.vvv(f'FETCH {in_path} TO {out_path}', host=self.get_option('remote_addr'))
try:
returncode, stdout, stderr = self.exec_command(
' '.join([
self._shell.executable, '-c',
self._shell.quote(f'cat {in_path}')]),
sudoable=False)
if returncode != 0:
if 'cat: not found' in stderr.decode('utf-8'):
raise AnsibleError(
f'cat not found in path of WSL distribution: {to_text(self.get_option("wsl_distribution"))}')
raise AnsibleError(
f'{to_text(stdout)}\n{to_text(stderr)}')
with open(out_path, 'wb') as f:
f.write(stdout)
except Exception as e:
raise AnsibleError(
f'error occurred while fetching file from {in_path} to {out_path}!\n{to_text(e)}')
def reset(self) -> None:
""" reset the connection """
if not self._connected:
return
self.close()
self._connect()
def close(self) -> None:
""" terminate the connection """
if self.get_option('host_key_checking') and self.get_option('record_host_keys') and self._any_keys_added():
# add any new SSH host keys -- warning -- this could be slow
# (This doesn't acquire the connection lock because it needs
# to exclude only other known_hosts writers, not connections
# that are starting up.)
lockfile = os.path.basename(self.keyfile)
dirname = os.path.dirname(self.keyfile)
makedirs_safe(dirname)
tmp_keyfile_name = None
try:
with FileLock().lock_file(lockfile, dirname, self.get_option('lock_file_timeout')):
# just in case any were added recently
self.ssh.load_system_host_keys()
self.ssh._host_keys.update(self.ssh._system_host_keys)
# gather information about the current key file, so
# we can ensure the new file has the correct mode/owner
key_dir = os.path.dirname(self.keyfile)
if os.path.exists(self.keyfile):
key_stat = os.stat(self.keyfile)
mode = key_stat.st_mode & 0o777
uid = key_stat.st_uid
gid = key_stat.st_gid
else:
mode = 0o644
uid = os.getuid()
gid = os.getgid()
# Save the new keys to a temporary file and move it into place
# rather than rewriting the file. We set delete=False because
# the file will be moved into place rather than cleaned up.
with tempfile.NamedTemporaryFile(dir=key_dir, delete=False) as tmp_keyfile:
tmp_keyfile_name = tmp_keyfile.name
os.chmod(tmp_keyfile_name, mode)
os.chown(tmp_keyfile_name, uid, gid)
self._save_ssh_host_keys(tmp_keyfile_name)
os.rename(tmp_keyfile_name, self.keyfile)
except LockTimeout:
raise AnsibleError(
f'writing lock file for {self.keyfile} ran in to the timeout of {self.get_option("lock_file_timeout")}s')
except paramiko.hostkeys.InvalidHostKey as e:
raise AnsibleConnectionFailure(f'Invalid host key: {e.line}')
except Exception as e:
# unable to save keys, including scenario when key was invalid
# and caught earlier
raise AnsibleError(
f'error occurred while writing SSH host keys!\n{to_text(e)}')
finally:
if tmp_keyfile_name is not None:
pathlib.Path(tmp_keyfile_name).unlink(missing_ok=True)
self.ssh.close()
self._connected = False

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2025 Ansible community
# 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 (absolute_import, division, print_function)
__metaclass__ = type
class ModuleDocFragment(object):
# Use together with the community.general.redfish module utils' REDFISH_COMMON_ARGUMENT_SPEC
DOCUMENTATION = r"""
options:
validate_certs:
description:
- If V(false), TLS/SSL certificates will not be validated.
- Set this to V(true) to enable certificate checking. Should be used together with O(ca_path).
type: bool
default: false
ca_path:
description:
- PEM formatted file that contains a CA certificate to be used for validation.
- Only used if O(validate_certs=true).
type: path
ciphers:
required: false
description:
- TLS/SSL Ciphers to use for the request.
- When a list is provided, all ciphers are joined in order with V(:).
- See the L(OpenSSL Cipher List Format,https://www.openssl.org/docs/manmaster/man1/openssl-ciphers.html#CIPHER-LIST-FORMAT)
for more details.
- The available ciphers is dependent on the Python and OpenSSL/LibreSSL versions.
type: list
elements: str
"""

View File

@@ -9,12 +9,16 @@ from __future__ import annotations
from ansible.errors import (
AnsibleError,
AnsibleFilterError,
AnsibleFilterTypeError,
)
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.common.collections import is_sequence
try:
from ansible.errors import AnsibleTypeError
except ImportError:
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError
try:
from hashids import Hashids
HAS_HASHIDS = True
@@ -63,7 +67,7 @@ def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
try:
hashid = hashids.encode(*nums)
except TypeError as e:
raise AnsibleFilterTypeError(
raise AnsibleTypeError(
"Data to encode must by a tuple or list of ints: %s" % to_native(e)
)

View File

@@ -23,29 +23,29 @@ options:
"""
EXAMPLES = r"""
# Substitution converts str to AnsibleUnicode
# -------------------------------------------
# Substitution converts str to AnsibleUnicode or _AnsibleTaggedStr
# ----------------------------------------------------------------
# String. AnsibleUnicode.
# String. AnsibleUnicode or _AnsibleTaggedStr.
- data: "abc"
result: '{{ data | community.general.reveal_ansible_type }}'
# result => AnsibleUnicode
# result => AnsibleUnicode (or _AnsibleTaggedStr)
# String. AnsibleUnicode alias str.
- alias: {"AnsibleUnicode": "str"}
# String. AnsibleUnicode/_AnsibleTaggedStr alias str.
- alias: {"AnsibleUnicode": "str", "_AnsibleTaggedStr": "str"}
data: "abc"
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => str
# List. All items are AnsibleUnicode.
# List. All items are AnsibleUnicode/_AnsibleTaggedStr.
- data: ["a", "b", "c"]
result: '{{ data | community.general.reveal_ansible_type }}'
# result => list[AnsibleUnicode]
# result => list[AnsibleUnicode] or list[_AnsibleTaggedStr]
# Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
# Dictionary. All keys and values are AnsibleUnicode/_AnsibleTaggedStr.
- data: {"a": "foo", "b": "bar", "c": "baz"}
result: '{{ data | community.general.reveal_ansible_type }}'
# result => dict[AnsibleUnicode, AnsibleUnicode]
# result => dict[AnsibleUnicode, AnsibleUnicode] or dict[_AnsibleTaggedStr, _AnsibleTaggedStr]
# No substitution and no alias. Type of strings is str
# ----------------------------------------------------
@@ -82,29 +82,43 @@ EXAMPLES = r"""
- result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
# result => dict[str, int]
# Type of strings is AnsibleUnicode or str
# ----------------------------------------
# Type of strings is AnsibleUnicode, _AnsibleTaggedStr, or str
# ------------------------------------------------------------
# Dictionary. The keys are integers or strings. All values are strings.
- alias: {"AnsibleUnicode": "str"}
- alias:
AnsibleUnicode: str
_AnsibleTaggedStr: str
_AnsibleTaggedInt: int
data: {1: 'a', 'b': 'b'}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[int|str, str]
# Dictionary. All keys are integers. All values are keys.
- alias: {"AnsibleUnicode": "str"}
- alias:
AnsibleUnicode: str
_AnsibleTaggedStr: str
_AnsibleTaggedInt: int
data: {1: 'a', 2: 'b'}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[int, str]
# Dictionary. All keys are strings. Multiple types values.
- alias: {"AnsibleUnicode": "str"}
- alias:
AnsibleUnicode: str
_AnsibleTaggedStr: str
_AnsibleTaggedInt: int
_AnsibleTaggedFloat: float
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': true, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[str, bool|dict|float|int|list|str]
# List. Multiple types items.
- alias: {"AnsibleUnicode": "str"}
- alias:
AnsibleUnicode: str
_AnsibleTaggedStr: str
_AnsibleTaggedInt: int
_AnsibleTaggedFloat: float
data: [1, 2, 1.1, 'abc', true, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => list[bool|dict|float|int|list|str]
@@ -122,6 +136,7 @@ from ansible_collections.community.general.plugins.plugin_utils.ansible_type imp
def reveal_ansible_type(data, alias=None):
"""Returns data type"""
# TODO: expose use_native_type parameter
return _ansible_type(data, alias)

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_days
short_description: Converte a duration string to days
short_description: Converts a duration string to days
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to days.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_hours
short_description: Converte a duration string to hours
short_description: Converts a duration string to hours
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to hours.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_milliseconds
short_description: Converte a duration string to milliseconds
short_description: Converts a duration string to milliseconds
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to milliseconds.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_minutes
short_description: Converte a duration string to minutes
short_description: Converts a duration string to minutes
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to minutes.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_months
short_description: Converte a duration string to months
short_description: Convert a duration string to months
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to months.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_seconds
short_description: Converte a duration string to seconds
short_description: Converts a duration string to seconds
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to seconds.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_time_unit
short_description: Converte a duration string to the given time unit
short_description: Converts a duration string to the given time unit
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to the given time unit.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_weeks
short_description: Converte a duration string to weeks
short_description: Converts a duration string to weeks
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to weeks.

View File

@@ -5,7 +5,7 @@
DOCUMENTATION:
name: to_years
short_description: Converte a duration string to years
short_description: Converts a duration string to years
version_added: 0.2.0
description:
- Parse a human readable time duration string and convert to years.

View File

@@ -48,9 +48,14 @@ _value:
from unicodedata import normalize
from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError
from ansible.errors import AnsibleFilterError
from ansible.module_utils.six import text_type
try:
from ansible.errors import AnsibleTypeError
except ImportError:
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError
def unicode_normalize(data, form='NFC'):
"""Applies normalization to 'unicode' strings.
@@ -65,7 +70,7 @@ def unicode_normalize(data, form='NFC'):
"""
if not isinstance(data, text_type):
raise AnsibleFilterTypeError("%s is not a valid input type" % type(data))
raise AnsibleTypeError("%s is not a valid input type" % type(data))
if form not in ('NFC', 'NFD', 'NFKC', 'NFKD'):
raise AnsibleFilterError("%s is not a valid form" % form)

View File

@@ -6,85 +6,99 @@
from __future__ import annotations
DOCUMENTATION = '''
name: iocage
short_description: iocage inventory source
version_added: 10.2.0
author:
- Vladimir Botka (@vbotka)
requirements:
- iocage >= 1.8
DOCUMENTATION = r'''
name: iocage
short_description: iocage inventory source
version_added: 10.2.0
author:
- Vladimir Botka (@vbotka)
requirements:
- iocage >= 1.8
description:
- Get inventory hosts from the iocage jail manager running on O(host).
- By default, O(host) is V(localhost). If O(host) is not V(localhost) it
is expected that the user running Ansible on the controller can
connect to the O(host) account O(user) with SSH non-interactively and
execute the command C(iocage list).
- Uses a configuration file as an inventory source, it must end
in C(.iocage.yml) or C(.iocage.yaml).
extends_documentation_fragment:
- ansible.builtin.constructed
- ansible.builtin.inventory_cache
options:
plugin:
description:
- Get inventory hosts from the iocage jail manager running on O(host).
- By default, O(host) is V(localhost). If O(host) is not V(localhost) it
is expected that the user running Ansible on the controller can
connect to the O(host) account O(user) with SSH non-interactively and
execute the command C(iocage list).
- Uses a configuration file as an inventory source, it must end
in C(.iocage.yml) or C(.iocage.yaml).
extends_documentation_fragment:
- ansible.builtin.constructed
- ansible.builtin.inventory_cache
options:
plugin:
description:
- The name of this plugin, it should always be set to
V(community.general.iocage) for this plugin to recognize
it as its own.
required: true
choices: ['community.general.iocage']
type: str
host:
description: The IP/hostname of the C(iocage) host.
type: str
default: localhost
user:
description:
- C(iocage) user.
It is expected that the O(user) is able to connect to the
O(host) with SSH and execute the command C(iocage list).
This option is not required if O(host) is V(localhost).
type: str
sudo:
description:
- Enable execution as root.
- This requires passwordless sudo of the command C(iocage list*).
type: bool
default: false
version_added: 10.3.0
sudo_preserve_env:
description:
- Preserve environment if O(sudo) is enabled.
- This requires C(SETENV) sudoers tag.
type: bool
default: false
version_added: 10.3.0
get_properties:
description:
- Get jails' properties.
Creates dictionary C(iocage_properties) for each added host.
type: bool
default: false
env:
description:
- O(user)'s environment on O(host).
- Enable O(sudo_preserve_env) if O(sudo) is enabled.
type: dict
default: {}
notes:
- You might want to test the command C(ssh user@host iocage list -l) on
the controller before using this inventory plugin with O(user) specified
and with O(host) other than V(localhost).
- If you run this inventory plugin on V(localhost) C(ssh) is not used.
In this case, test the command C(iocage list -l).
- This inventory plugin creates variables C(iocage_*) for each added host.
- The values of these variables are collected from the output of the
command C(iocage list -l).
- The names of these variables correspond to the output columns.
- The column C(NAME) is used to name the added host.
- The name of this plugin, it should always be set to
V(community.general.iocage) for this plugin to recognize
it as its own.
required: true
choices: ['community.general.iocage']
type: str
host:
description: The IP/hostname of the C(iocage) host.
type: str
default: localhost
user:
description:
- C(iocage) user.
It is expected that the O(user) is able to connect to the
O(host) with SSH and execute the command C(iocage list).
This option is not required if O(host) is V(localhost).
type: str
sudo:
description:
- Enable execution as root.
- This requires passwordless sudo of the command C(iocage list*).
type: bool
default: false
version_added: 10.3.0
sudo_preserve_env:
description:
- Preserve environment if O(sudo) is enabled.
- This requires C(SETENV) sudoers tag.
type: bool
default: false
version_added: 10.3.0
get_properties:
description:
- Get jails' properties.
Creates dictionary C(iocage_properties) for each added host.
type: bool
default: false
env:
description:
- O(user)'s environment on O(host).
- Enable O(sudo_preserve_env) if O(sudo) is enabled.
type: dict
default: {}
hooks_results:
description:
- List of paths to the files in a jail.
- Content of the files is stored in the items of the list C(iocage_hooks).
- If a file is not available the item keeps the dash character C(-).
- The variable C(iocage_hooks) is not created if O(hooks_results) is empty.
type: list
elements: path
version_added: 10.4.0
notes:
- You might want to test the command C(ssh user@host iocage list -l) on
the controller before using this inventory plugin with O(user) specified
and with O(host) other than V(localhost).
- If you run this inventory plugin on V(localhost) C(ssh) is not used.
In this case, test the command C(iocage list -l).
- This inventory plugin creates variables C(iocage_*) for each added host.
- The values of these variables are collected from the output of the
command C(iocage list -l).
- The names of these variables correspond to the output columns.
- The column C(NAME) is used to name the added host.
- The option O(hooks_results) expects the C(poolname) of a jail is mounted to
C(/poolname). For example, if you activate the pool C(iocage) this plugin
expects to find the O(hooks_results) items in the path
C(/iocage/iocage/jails/<name>/root). If you mount the C(poolname) to a
different path the easiest remedy is to create a symlink.
'''
EXAMPLES = '''
EXAMPLES = r'''
---
# file name must end with iocage.yaml or iocage.yml
plugin: community.general.iocage
@@ -142,6 +156,18 @@ keyed_groups:
key: iocage_release
- prefix: state
key: iocage_state
---
# Read the file /var/db/dhclient-hook.address.epair0b in the jails and use it as ansible_host
plugin: community.general.iocage
host: 10.1.0.73
user: admin
hooks_results:
- /var/db/dhclient-hook.address.epair0b
compose:
ansible_host: iocage_hooks.0
groups:
test: inventory_hostname.startswith('test')
'''
import re
@@ -226,6 +252,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
sudo_preserve_env = self.get_option('sudo_preserve_env')
env = self.get_option('env')
get_properties = self.get_option('get_properties')
hooks_results = self.get_option('hooks_results')
cmd = []
my_env = os.environ.copy()
@@ -286,6 +313,50 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.get_properties(t_stdout, results, hostname)
if hooks_results:
cmd_get_pool = cmd.copy()
cmd_get_pool.append(self.IOCAGE)
cmd_get_pool.append('get')
cmd_get_pool.append('--pool')
try:
p = Popen(cmd_get_pool, stdout=PIPE, stderr=PIPE, env=my_env)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise AnsibleError(
f'Failed to run cmd={cmd_get_pool}, rc={p.returncode}, stderr={to_native(stderr)}')
try:
iocage_pool = to_text(stdout, errors='surrogate_or_strict').strip()
except UnicodeError as e:
raise AnsibleError(f'Invalid (non unicode) input returned: {e}') from e
except Exception as e:
raise AnsibleError(f'Failed to get pool: {e}') from e
for hostname, host_vars in results['_meta']['hostvars'].items():
iocage_hooks = []
for hook in hooks_results:
path = "/" + iocage_pool + "/iocage/jails/" + hostname + "/root" + hook
cmd_cat_hook = cmd.copy()
cmd_cat_hook.append('cat')
cmd_cat_hook.append(path)
try:
p = Popen(cmd_cat_hook, stdout=PIPE, stderr=PIPE, env=my_env)
stdout, stderr = p.communicate()
if p.returncode != 0:
iocage_hooks.append('-')
continue
try:
iocage_hook = to_text(stdout, errors='surrogate_or_strict').strip()
except UnicodeError as e:
raise AnsibleError(f'Invalid (non unicode) input returned: {e}') from e
except Exception:
iocage_hooks.append('-')
else:
iocage_hooks.append(iocage_hook)
results['_meta']['hostvars'][hostname]['iocage_hooks'] = iocage_hooks
return results
def get_jails(self, t_stdout, results):

View File

@@ -86,6 +86,11 @@ DOCUMENTATION = '''
type: boolean
default: false
version_added: 6.1.0
dns_servers:
description: Specify which DNS servers to use for name resolution.
type: list
elements: string
version_added: 10.5.0
use_arp_ping:
description: Whether to always (V(true)) use the quick ARP ping or (V(false)) a slower but more reliable method.
type: boolean
@@ -231,6 +236,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
if self.get_option('dns_resolve'):
cmd.append('-n')
if self.get_option('dns_servers'):
cmd.append('--dns-servers')
cmd.append(','.join(self.get_option('dns_servers')))
if self.get_option('udp_scan'):
cmd.append('-sU')

View File

@@ -308,12 +308,17 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _get_json(self, url, ignore_errors=None):
if not self.use_cache or url not in self._cache.get(self.cache_key, {}):
data = []
has_data = False
if self.cache_key not in self._cache:
self._cache[self.cache_key] = {'url': ''}
if self.use_cache:
try:
data = self._cache[self.cache_key][url]
has_data = True
except KeyError:
self.update_cache = True
data = []
if not has_data:
s = self._get_session()
while True:
ret = s.get(url, headers=self.headers)
@@ -339,9 +344,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
data = data + json['data']
break
self._cache[self.cache_key][url] = data
return make_unsafe(self._cache[self.cache_key][url])
self._results[url] = data
return make_unsafe(data)
def _get_nodes(self):
return self._get_json(f"{self.proxmox_url}/api2/json/nodes")
@@ -362,11 +366,26 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
def _get_node_ip(self, node):
ret = self._get_json(f"{self.proxmox_url}/api2/json/nodes/{node}/network")
# sort interface by iface name to make selection as stable as possible
ret.sort(key=lambda x: x['iface'])
for iface in ret:
try:
# only process interfaces adhering to these rules
if 'active' not in iface:
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have an active state")
continue
if 'address' not in iface:
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have an address")
continue
if 'gateway' not in iface:
self.display.vvv(f"Interface {iface['iface']} on node {node} does not have a gateway")
continue
self.display.vv(f"Using interface {iface['iface']} on node {node} with address {iface['address']} as node ip for ansible_host")
return iface['address']
except Exception:
return None
continue
return None
def _get_lxc_interfaces(self, properties, node, vmid):
status_key = self._fact('status')
@@ -680,10 +699,14 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.exclude_nodes = self.get_option('exclude_nodes')
self.cache_key = self.get_cache_key(path)
self.use_cache = cache and self.get_option('cache')
self.update_cache = not cache and self.get_option('cache')
self.host_filters = self.get_option('filters')
self.group_prefix = self.get_option('group_prefix')
self.facts_prefix = self.get_option('facts_prefix')
self.strict = self.get_option('strict')
# actually populate inventory
self._results = {}
self._populate()
if self.update_cache:
self._cache[self.cache_key] = self._results

View File

@@ -6,60 +6,60 @@
from __future__ import annotations
DOCUMENTATION = '''
name: stackpath_compute
short_description: StackPath Edge Computing inventory source
version_added: 1.2.0
author:
- UNKNOWN (@shayrybak)
extends_documentation_fragment:
- inventory_cache
- constructed
DOCUMENTATION = r"""
name: stackpath_compute
short_description: StackPath Edge Computing inventory source
version_added: 1.2.0
author:
- UNKNOWN (@shayrybak)
deprecated:
removed_in: 11.0.0
why: Stackpath (the company) ceased its operations in June 2024. The API URL this plugin relies on is not found in DNS.
alternative: There is none.
extends_documentation_fragment:
- inventory_cache
- constructed
description:
- Get inventory hosts from StackPath Edge Computing.
- Uses a YAML configuration file that ends with stackpath_compute.(yml|yaml).
options:
plugin:
description:
- Get inventory hosts from StackPath Edge Computing.
- Uses a YAML configuration file that ends with stackpath_compute.(yml|yaml).
options:
plugin:
description:
- A token that ensures this is a source file for the plugin.
required: true
type: string
choices: ['community.general.stackpath_compute']
client_id:
description:
- An OAuth client ID generated from the API Management section of the StackPath customer portal
U(https://control.stackpath.net/api-management).
required: true
type: str
client_secret:
description:
- An OAuth client secret generated from the API Management section of the StackPath customer portal
U(https://control.stackpath.net/api-management).
required: true
type: str
stack_slugs:
description:
- A list of Stack slugs to query instances in. If no entry then get instances in all stacks on the account.
type: list
elements: str
use_internal_ip:
description:
- Whether or not to use internal IP addresses, If false, uses external IP addresses, internal otherwise.
- If an instance doesn't have an external IP it will not be returned when this option is set to false.
type: bool
'''
- A token that ensures this is a source file for the plugin.
required: true
type: string
choices: ['community.general.stackpath_compute']
client_id:
description:
- An OAuth client ID generated from the API Management section of the StackPath customer portal U(https://control.stackpath.net/api-management).
required: true
type: str
client_secret:
description:
- An OAuth client secret generated from the API Management section of the StackPath customer portal U(https://control.stackpath.net/api-management).
required: true
type: str
stack_slugs:
description:
- A list of Stack slugs to query instances in. If no entry then get instances in all stacks on the account.
type: list
elements: str
use_internal_ip:
description:
- Whether or not to use internal IP addresses, If false, uses external IP addresses, internal otherwise.
- If an instance doesn't have an external IP it will not be returned when this option is set to false.
type: bool
"""
EXAMPLES = '''
# Example using credentials to fetch all workload instances in a stack.
---
EXAMPLES = r"""
plugin: community.general.stackpath_compute
client_id: my_client_id
client_secret: my_client_secret
stack_slugs:
- my_first_stack_slug
- my_other_stack_slug
- my_first_stack_slug
- my_other_stack_slug
use_internal_ip: false
'''
"""
import traceback
import json

View File

@@ -57,6 +57,20 @@ DOCUMENTATION = '''
description: Use wss when connecting to the Xen Orchestra API
type: boolean
default: true
use_vm_uuid:
description:
- Import Xen VMs to inventory using their UUID as the VM entry name.
- If set to V(false) use VM name labels instead of UUIDs.
type: boolean
default: true
version_added: 10.4.0
use_host_uuid:
description:
- Import Xen Hosts to inventory using their UUID as the Host entry name.
- If set to V(false) use Host name labels instead of UUIDs.
type: boolean
default: true
version_added: 10.4.0
'''
@@ -72,6 +86,8 @@ groups:
kube_nodes: "'kube_node' in tags"
compose:
ansible_port: 2222
use_vm_uuid: false
use_host_uuid: true
'''
@@ -196,10 +212,20 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self._set_composite_vars(self.get_option('compose'), variables, name, strict=strict)
def _add_vms(self, vms, hosts, pools):
vm_name_list = []
for uuid, vm in vms.items():
if self.vm_entry_name_type == 'name_label':
if vm['name_label'] not in vm_name_list:
entry_name = vm['name_label']
vm_name_list.append(vm['name_label'])
else:
vm_duplicate_count = vm_name_list.count(vm['name_label'])
entry_name = vm['name_label'] + "_" + str(vm_duplicate_count)
vm_name_list.append(vm['name_label'])
else:
entry_name = uuid
group = 'with_ip'
ip = vm.get('mainIpAddress')
entry_name = uuid
power_state = vm['power_state'].lower()
pool_name = self._pool_group_name_for_uuid(pools, vm['$poolId'])
host_name = self._host_group_name_for_uuid(hosts, vm['$container'])
@@ -246,8 +272,19 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self._apply_constructable(entry_name, self.inventory.get_host(entry_name).get_vars())
def _add_hosts(self, hosts, pools):
host_name_list = []
for host in hosts.values():
entry_name = host['uuid']
if self.host_entry_name_type == 'name_label':
if host['name_label'] not in host_name_list:
entry_name = host['name_label']
host_name_list.append(host['name_label'])
else:
host_duplicate_count = host_name_list.count(host['name_label'])
entry_name = host['name_label'] + "_" + str(host_duplicate_count)
host_name_list.append(host['name_label'])
else:
entry_name = host['uuid']
group_name = f"xo_host_{clean_group_name(host['name_label'])}"
pool_name = self._pool_group_name_for_uuid(pools, host['$poolId'])
@@ -337,5 +374,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
if not self.get_option('use_ssl'):
self.protocol = 'ws'
self.vm_entry_name_type = 'uuid'
if not self.get_option('use_vm_uuid'):
self.vm_entry_name_type = 'name_label'
self.host_entry_name_type = 'uuid'
if not self.get_option('use_host_uuid'):
self.host_entry_name_type = 'name_label'
objects = self._get_objects()
self._populate(make_unsafe(objects))

View File

@@ -37,9 +37,17 @@ DOCUMENTATION = """
description: Field to fetch. Leave unset to fetch whole response.
type: str
collection_id:
description: Collection ID to filter results by collection. Leave unset to skip filtering.
description:
- Collection ID to filter results by collection. Leave unset to skip filtering.
- O(collection_id) and O(collection_name) are mutually exclusive.
type: str
version_added: 6.3.0
collection_name:
description:
- Collection name to filter results by collection. Leave unset to skip filtering.
- O(collection_id) and O(collection_name) are mutually exclusive.
type: str
version_added: 10.4.0
organization_id:
description: Organization ID to filter results by organization. Leave unset to skip filtering.
type: str
@@ -48,6 +56,12 @@ DOCUMENTATION = """
description: Pass session key instead of reading from env.
type: str
version_added: 8.4.0
result_count:
description:
- Number of results expected for the lookup query. Task will fail if O(result_count)
is set but does not match the number of query results. Leave empty to skip this check.
type: int
version_added: 10.4.0
"""
EXAMPLES = """
@@ -85,6 +99,16 @@ EXAMPLES = """
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', None, collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}
- name: "Get all Bitwarden records from collection"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', None, collection_name='my_collections/test_collection') }}
- name: "Get Bitwarden record named 'a_test', ensure there is exactly one match"
ansible.builtin.debug:
msg: >-
{{ lookup('community.general.bitwarden', 'a_test', result_count=1) }}
"""
RETURN = """
@@ -99,7 +123,7 @@ RETURN = """
from subprocess import Popen, PIPE
from ansible.errors import AnsibleError
from ansible.errors import AnsibleError, AnsibleOptionsError
from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible.parsing.ajson import AnsibleJSONDecoder
from ansible.plugins.lookup import LookupBase
@@ -211,6 +235,24 @@ class Bitwarden(object):
return field_matches
def get_collection_ids(self, collection_name: str, organization_id=None) -> list[str]:
"""Return matching IDs of collections whose name is equal to collection_name."""
# Prepare set of params for Bitwarden CLI
params = ['list', 'collections', '--search', collection_name]
if organization_id:
params.extend(['--organizationid', organization_id])
out, err = self._run(params)
# This includes things that matched in different fields.
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]
# Filter to only return the ID of a collections with exactly matching name
return [item['id'] for item in initial_matches
if str(item.get('name')).lower() == collection_name.lower()]
class LookupModule(LookupBase):
@@ -219,7 +261,9 @@ class LookupModule(LookupBase):
field = self.get_option('field')
search_field = self.get_option('search')
collection_id = self.get_option('collection_id')
collection_name = self.get_option('collection_name')
organization_id = self.get_option('organization_id')
result_count = self.get_option('result_count')
_bitwarden.session = self.get_option('bw_session')
if not _bitwarden.unlocked:
@@ -228,7 +272,27 @@ class LookupModule(LookupBase):
if not terms:
terms = [None]
return [_bitwarden.get_field(field, term, search_field, collection_id, organization_id) for term in terms]
if collection_name and collection_id:
raise AnsibleOptionsError("'collection_name' and 'collection_id' are mutually exclusive!")
elif collection_name:
collection_ids = _bitwarden.get_collection_ids(collection_name, organization_id)
if not collection_ids:
raise BitwardenException("No matching collections found!")
else:
collection_ids = [collection_id]
results = [
_bitwarden.get_field(field, term, search_field, collection_id, organization_id)
for collection_id in collection_ids
for term in terms
]
for result in results:
if result_count is not None and len(result) != result_count:
raise BitwardenException(
f"Number of results doesn't match result_count! ({len(result)} != {result_count})")
return results
_bitwarden = Bitwarden()

View File

@@ -130,12 +130,24 @@ from ansible.template import Templar
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
try:
from ansible.template import trust_as_template as _trust_as_template
HAS_DATATAGGING = True
except ImportError:
HAS_DATATAGGING = False
# Whether Templar has a cache, which can be controlled by Templar.template()'s cache option.
# The cache was removed for ansible-core 2.14 (https://github.com/ansible/ansible/pull/78419)
_TEMPLAR_HAS_TEMPLATE_CACHE = LooseVersion(ansible_version) < LooseVersion('2.14.0')
def _make_safe(value):
if HAS_DATATAGGING and isinstance(value, str):
return _trust_as_template(value)
return value
class LookupModule(LookupBase):
def __evaluate(self, expression, templar, variables):
"""Evaluate expression with templar.
@@ -144,10 +156,13 @@ class LookupModule(LookupBase):
``variables`` are the variables to use.
"""
templar.available_variables = variables or {}
expression = "{0}{1}{2}".format("{{", expression, "}}")
quoted_expression = "{0}{1}{2}".format("{{", expression, "}}")
if _TEMPLAR_HAS_TEMPLATE_CACHE:
return templar.template(expression, cache=False)
return templar.template(expression)
return templar.template(quoted_expression, cache=False)
if hasattr(templar, 'evaluate_expression'):
# This is available since the Data Tagging PR has been merged
return templar.evaluate_expression(_make_safe(expression))
return templar.template(quoted_expression)
def __process(self, result, terms, index, current, templar, variables):
"""Fills ``result`` list with evaluated items.

View File

@@ -13,6 +13,10 @@ DOCUMENTATION = '''
short_description: get credentials from Manifold.co
description:
- Retrieves resources' credentials from Manifold.co
deprecated:
removed_in: 11.0.0
why: Manifold (the company) has been acquired in 2021 and the services used by this plugin are no longer operational.
alternative: There is none.
options:
_terms:
description:

View File

@@ -553,9 +553,7 @@ class OnePassCLIv2(OnePassCLIBase):
environment_update = {"OP_SECRET_KEY": self.secret_key}
return self._run(args, command_input=to_bytes(self.master_password), environment_update=environment_update)
def get_raw(self, item_id, vault=None, token=None):
args = ["item", "get", item_id, "--format", "json"]
def _add_parameters_and_run(self, args, vault=None, token=None):
if self.account_id:
args.extend(["--account", self.account_id])
@@ -582,6 +580,10 @@ class OnePassCLIv2(OnePassCLIBase):
return self._run(args)
def get_raw(self, item_id, vault=None, token=None):
args = ["item", "get", item_id, "--format", "json"]
return self._add_parameters_and_run(args, vault=vault, token=token)
def signin(self):
self._check_required_params(['master_password'])

View File

@@ -46,28 +46,13 @@ RETURN = """
"""
from ansible_collections.community.general.plugins.lookup.onepassword import OnePass, OnePassCLIv2
from ansible.errors import AnsibleLookupError
from ansible.module_utils.common.text.converters import to_bytes
from ansible.plugins.lookup import LookupBase
class OnePassCLIv2Doc(OnePassCLIv2):
def get_raw(self, item_id, vault=None, token=None):
args = ["document", "get", item_id]
if vault is not None:
args = [*args, f"--vault={vault}"]
if self.service_account_token:
if vault is None:
raise AnsibleLookupError("'vault' is required with 'service_account_token'")
environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
return self._run(args, environment_update=environment_update)
if token is not None:
args = [*args, to_bytes("--session=") + token]
return self._run(args)
return self._add_parameters_and_run(args, vault=vault, token=token)
class LookupModule(LookupBase):

View File

@@ -58,11 +58,8 @@ from ansible.errors import AnsibleLookupError
from ansible.plugins.lookup import LookupBase
class OnePassCLIv2SSHKey(OnePassCLIv2):
def get_ssh_key(self, item_id, vault=None, token=None, ssh_format=False):
rc, out, err = self.get_raw(item_id, vault=vault, token=token)
class LookupModule(LookupBase):
def get_ssh_key(self, out, item_id, ssh_format=False):
data = json.loads(out)
if data.get("category") != "SSH_KEY":
@@ -87,8 +84,6 @@ class OnePassCLIv2SSHKey(OnePassCLIv2):
)
return private_key_field.get("value", "")
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
@@ -114,11 +109,11 @@ class LookupModule(LookupBase):
account_id=account_id,
connect_host=connect_host,
connect_token=connect_token,
cli_class=OnePassCLIv2SSHKey,
cli_class=OnePassCLIv2,
)
op.assert_logged_in()
return [
op._cli.get_ssh_key(term, vault, token=op.token, ssh_format=ssh_format)
self.get_ssh_key(op.get_raw(term, vault), term, ssh_format=ssh_format)
for term in terms
]

View File

@@ -572,16 +572,20 @@ class LookupModule(LookupBase):
for term in terms:
self.parse_params(term) # parse the input into paramvals
with self.opt_lock('readwrite'):
if self.check_pass(): # password exists
if self.paramvals['overwrite']:
if self.check_pass(): # password file exists
if self.paramvals['overwrite']: # if "overwrite", always update password
with self.opt_lock('write'):
result.append(self.update_password())
elif self.paramvals["subkey"] != "password" and not self.passdict.get(self.paramvals['subkey']): # password exists but not the subkey
elif (
self.paramvals["subkey"] != "password"
and not self.passdict.get(self.paramvals["subkey"])
and self.paramvals["missing"] == "create"
): # target is a subkey, this subkey is not in passdict BUT missing == create
with self.opt_lock('write'):
result.append(self.update_password())
else:
result.append(self.get_passresult())
else: # password does not exist
else: # password does not exist
if self.paramvals['missing'] == 'create':
with self.opt_lock('write'):
if self.locked == 'write' and self.check_pass(): # lookup password again if under write lock

View File

@@ -78,7 +78,9 @@ def as_list(ignore_none=None, min_len=0, max_len=None):
return _ArgFormat(func, ignore_none=ignore_none)
def as_fixed(args):
def as_fixed(*args):
if len(args) == 1 and is_sequence(args[0]):
args = args[0]
return _ArgFormat(lambda value: _ensure_list(args), ignore_none=False, ignore_missing_value=True)

View File

@@ -456,6 +456,8 @@ class KeycloakAPI(object):
self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
# The Keycloak API expects the realm name (like `master`) not the ID when fetching the realm data.
# See the Keycloak API docs: https://www.keycloak.org/docs-api/latest/rest-api/#_realms_admin
def get_realm_by_id(self, realm='master'):
""" Obtain realm representation by id
@@ -1856,7 +1858,7 @@ class KeycloakAPI(object):
else:
composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe=''))
# Get existing composites
self._request_and_deserialize(composite_url, method='GET')
return self._request_and_deserialize(composite_url, method='GET')
except Exception as e:
self.fail_request(e, msg='Could not get role %s composites in realm %s: %s'
% (rolerep['name'], realm, str(e)))
@@ -2222,6 +2224,23 @@ class KeycloakAPI(object):
except Exception as e:
self.fail_request(e, msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
def delete_authentication_config(self, configId, realm='master'):
""" Delete authenticator config
:param configId: id of authentication config
:param realm: realm of authentication config to be deleted
"""
try:
# Send a DELETE request to remove the specified authentication config from the Keycloak server.
self._request(
URL_AUTHENTICATION_CONFIG.format(
url=self.baseurl,
realm=realm,
id=configId),
method='DELETE')
except Exception as e:
self.fail_request(e, msg="Unable to delete authentication config %s: %s" % (configId, str(e)))
def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'):
""" Create new sublow on the flow
@@ -2808,29 +2827,33 @@ class KeycloakAPI(object):
def get_user_groups(self, user_id, realm='master'):
"""
Get groups for a user.
Get the group names for a user.
:param user_id: User ID
:param realm: Realm
:return: Representation of the client groups.
:return: The client group names as a list of strings.
"""
user_groups = self.get_user_group_details(user_id, realm)
return [user_group['name'] for user_group in user_groups if 'name' in user_group]
def get_user_group_details(self, user_id, realm='master'):
"""
Get the group details for a user.
:param user_id: User ID
:param realm: Realm
:return: The client group details as a list of dictionaries.
"""
try:
groups = []
user_groups_url = URL_USER_GROUPS.format(
url=self.baseurl,
realm=realm,
id=user_id)
user_groups = json.load(
self._request(
user_groups_url,
method='GET'))
for user_group in user_groups:
groups.append(user_group["name"])
return groups
user_groups_url = URL_USER_GROUPS.format(url=self.baseurl, realm=realm, id=user_id)
return self._request_and_deserialize(user_groups_url, method='GET')
except Exception as e:
self.fail_request(e, msg='Could not get groups for user %s in realm %s: %s'
% (user_id, realm, str(e)))
def add_user_in_group(self, user_id, group_id, realm='master'):
"""DEPRECATED: Call add_user_to_group(...) instead. This method is scheduled for removal in community.general 13.0.0."""
return self.add_user_to_group(user_id, group_id, realm)
def add_user_to_group(self, user_id, group_id, realm='master'):
"""
Add a user to a group.
:param user_id: User ID
@@ -2848,7 +2871,7 @@ class KeycloakAPI(object):
user_group_url,
method='PUT')
except Exception as e:
self.fail_request(e, msg='Could not add user %s in group %s in realm %s: %s'
self.fail_request(e, msg='Could not add user %s to group %s in realm %s: %s'
% (user_id, group_id, realm, str(e)))
def remove_user_from_group(self, user_id, group_id, realm='master'):
@@ -2879,49 +2902,72 @@ class KeycloakAPI(object):
:param realm: Realm
:return: True if group membership has been changed. False Otherwise.
"""
changed = False
try:
user_existing_groups = self.get_user_groups(
user_id=userrep['id'],
realm=realm)
groups_to_add_and_remove = self.extract_groups_to_add_to_and_remove_from_user(groups)
# If group membership need to be changed
if not is_struct_included(groups_to_add_and_remove['add'], user_existing_groups):
# Get available groups in the realm
realm_groups = self.get_groups(realm=realm)
for realm_group in realm_groups:
if "name" in realm_group and realm_group["name"] in groups_to_add_and_remove['add']:
self.add_user_in_group(
user_id=userrep["id"],
group_id=realm_group["id"],
realm=realm)
changed = True
elif "name" in realm_group and realm_group['name'] in groups_to_add_and_remove['remove']:
self.remove_user_from_group(
user_id=userrep['id'],
group_id=realm_group['id'],
realm=realm)
changed = True
return changed
groups_to_add, groups_to_remove = self.extract_groups_to_add_to_and_remove_from_user(groups)
if not groups_to_add and not groups_to_remove:
return False
user_groups = self.get_user_group_details(user_id=userrep['id'], realm=realm)
user_group_names = [user_group['name'] for user_group in user_groups if 'name' in user_group]
user_group_paths = [user_group['path'] for user_group in user_groups if 'path' in user_group]
groups_to_add = [group_to_add for group_to_add in groups_to_add
if group_to_add not in user_group_names and group_to_add not in user_group_paths]
groups_to_remove = [group_to_remove for group_to_remove in groups_to_remove
if group_to_remove in user_group_names or group_to_remove in user_group_paths]
if not groups_to_add and not groups_to_remove:
return False
for group_to_add in groups_to_add:
realm_group = self.find_group_by_path(group_to_add, realm=realm)
if realm_group:
self.add_user_to_group(user_id=userrep['id'], group_id=realm_group['id'], realm=realm)
for group_to_remove in groups_to_remove:
realm_group = self.find_group_by_path(group_to_remove, realm=realm)
if realm_group:
self.remove_user_from_group(user_id=userrep['id'], group_id=realm_group['id'], realm=realm)
return True
except Exception as e:
self.module.fail_json(msg='Could not update group membership for user %s in realm %s: %s'
% (userrep['id]'], realm, str(e)))
% (userrep['username'], realm, e))
def extract_groups_to_add_to_and_remove_from_user(self, groups):
groups_extract = {}
groups_to_add = []
groups_to_remove = []
if isinstance(groups, list) and len(groups) > 0:
if isinstance(groups, list):
for group in groups:
group_name = group['name'] if isinstance(group, dict) and 'name' in group else group
if isinstance(group, dict) and ('state' not in group or group['state'] == 'present'):
groups_to_add.append(group_name)
else:
groups_to_remove.append(group_name)
groups_extract['add'] = groups_to_add
groups_extract['remove'] = groups_to_remove
if isinstance(group, dict):
if 'state' not in group or group['state'] == 'present':
groups_to_add.append(group_name)
else:
groups_to_remove.append(group_name)
return groups_to_add, groups_to_remove
return groups_extract
def find_group_by_path(self, target, realm='master'):
"""
Finds a realm group by path, e.g. '/my/group'.
The path is formed by prepending a '/' character to `target` unless it's already present.
This adds support for finding top level groups by name and subgroups by path.
"""
groups = self.get_groups(realm=realm)
path = target if target.startswith('/') else '/' + target
for segment in path.split('/'):
if not segment:
continue
abort = True
for group in groups:
if group['path'] == path:
return self.get_group_by_groupid(group['id'], realm=realm)
if group['name'] == segment:
groups = self.get_subgroups(group, realm=realm)
abort = False
break
if abort:
break
return None
def convert_user_group_list_of_str_to_list_of_dict(self, groups):
list_of_groups = []

View File

@@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2025, Dexter Le <dextersydney2001@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 absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
_state_map = {
"present": "create",
"absent": "remove",
"status": "status",
"enabled": "enable",
"disabled": "disable"
}
def fmt_resource_type(value):
return [value[k] for k in ['resource_standard', 'resource_provider', 'resource_name'] if value.get(k) is not None]
def fmt_resource_operation(value):
cmd = []
for op in value:
cmd.append("op")
cmd.append(op.get('operation_action'))
for operation_option in op.get('operation_option'):
cmd.append(operation_option)
return cmd
def fmt_resource_argument(value):
return ['--group' if value['argument_action'] == 'group' else value['argument_action']] + value['argument_option']
def pacemaker_runner(module, cli_action, **kwargs):
runner = CmdRunner(
module,
command=['pcs', cli_action],
arg_formats=dict(
state=cmd_runner_fmt.as_map(_state_map),
name=cmd_runner_fmt.as_list(),
resource_type=cmd_runner_fmt.as_func(fmt_resource_type),
resource_option=cmd_runner_fmt.as_list(),
resource_operation=cmd_runner_fmt.as_func(fmt_resource_operation),
resource_meta=cmd_runner_fmt.stack(cmd_runner_fmt.as_opt_val)("meta"),
resource_argument=cmd_runner_fmt.as_func(fmt_resource_argument),
wait=cmd_runner_fmt.as_opt_eq_val("--wait"),
),
**kwargs
)
return runner

View File

@@ -95,10 +95,7 @@ def puppet_runner(module):
skip_tags=cmd_runner_fmt.as_func(lambda v: ["--skip_tags", ",".join(v)]),
certname=cmd_runner_fmt.as_opt_eq_val("--certname"),
noop=cmd_runner_fmt.as_func(noop_func),
use_srv_records=cmd_runner_fmt.as_map({
True: "--usr_srv_records",
False: "--no-usr_srv_records",
}),
use_srv_records=cmd_runner_fmt.as_bool("--usr_srv_records", "--no-usr_srv_records", ignore_none=True),
logdest=cmd_runner_fmt.as_map(_logdest_map, default=[]),
modulepath=cmd_runner_fmt.as_opt_eq_val("--modulepath"),
_execute=cmd_runner_fmt.as_func(execute_func),

View File

@@ -38,6 +38,21 @@ FAIL_MSG = 'Issuing a data modification command without specifying the '\
'than one %(resource)s is no longer allowed. Use the `resource_id` '\
'option to specify the target %(resource)s ID.'
# Use together with the community.general.redfish docs fragment
REDFISH_COMMON_ARGUMENT_SPEC = {
"validate_certs": {
"type": "bool",
"default": False,
},
"ca_path": {
"type": "path",
},
"ciphers": {
"type": "list",
"elements": "str",
},
}
class RedfishUtils(object):
@@ -53,8 +68,10 @@ class RedfishUtils(object):
self.resource_id = resource_id
self.data_modification = data_modification
self.strip_etag_quotes = strip_etag_quotes
self.ciphers = ciphers
self.ciphers = ciphers if ciphers is not None else module.params.get("ciphers")
self._vendor = None
self.validate_certs = module.params.get("validate_certs", False)
self.ca_path = module.params.get("ca_path")
def _auth_params(self, headers):
"""
@@ -132,6 +149,17 @@ class RedfishUtils(object):
resp['msg'] = 'Properties in %s are already set' % uri
return resp
def _request(self, uri, **kwargs):
kwargs.setdefault("validate_certs", self.validate_certs)
kwargs.setdefault("follow_redirects", "all")
kwargs.setdefault("use_proxy", True)
kwargs.setdefault("timeout", self.timeout)
kwargs.setdefault("ciphers", self.ciphers)
kwargs.setdefault("ca_path", self.ca_path)
resp = open_url(uri, **kwargs)
headers = {k.lower(): v for (k, v) in resp.info().items()}
return resp, headers
# The following functions are to send GET/POST/PATCH/DELETE requests
def get_request(self, uri, override_headers=None, allow_no_resp=False, timeout=None):
req_headers = dict(GET_HEADERS)
@@ -145,12 +173,15 @@ class RedfishUtils(object):
# in case the caller will be using sessions later.
if uri == (self.root_uri + self.service_root):
basic_auth = False
resp = open_url(uri, method="GET", headers=req_headers,
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=timeout, ciphers=self.ciphers)
headers = {k.lower(): v for (k, v) in resp.info().items()}
resp, headers = self._request(
uri,
method="GET",
headers=req_headers,
url_username=username,
url_password=password,
force_basic_auth=basic_auth,
timeout=timeout,
)
try:
if headers.get('content-encoding') == 'gzip' and LooseVersion(ansible_version) < LooseVersion('2.14'):
# Older versions of Ansible do not automatically decompress the data
@@ -194,18 +225,20 @@ class RedfishUtils(object):
req_headers['content-type'] = multipart_encoder[1]
else:
data = json.dumps(pyld)
resp = open_url(uri, data=data,
headers=req_headers, method="POST",
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=self.timeout, ciphers=self.ciphers)
resp, headers = self._request(
uri,
data=data,
headers=req_headers,
method="POST",
url_username=username,
url_password=password,
force_basic_auth=basic_auth,
)
try:
data = json.loads(to_native(resp.read()))
except Exception as e:
# No response data; this is okay in many cases
data = None
headers = {k.lower(): v for (k, v) in resp.info().items()}
except HTTPError as e:
msg, data = self._get_extended_message(e)
return {'ret': False,
@@ -248,12 +281,15 @@ class RedfishUtils(object):
username, password, basic_auth = self._auth_params(req_headers)
try:
resp = open_url(uri, data=json.dumps(pyld),
headers=req_headers, method="PATCH",
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=self.timeout, ciphers=self.ciphers)
resp, dummy = self._request(
uri,
data=json.dumps(pyld),
headers=req_headers,
method="PATCH",
url_username=username,
url_password=password,
force_basic_auth=basic_auth,
)
except HTTPError as e:
msg, data = self._get_extended_message(e)
return {'ret': False, 'changed': False,
@@ -283,12 +319,15 @@ class RedfishUtils(object):
req_headers['If-Match'] = etag
username, password, basic_auth = self._auth_params(req_headers)
try:
resp = open_url(uri, data=json.dumps(pyld),
headers=req_headers, method="PUT",
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=self.timeout, ciphers=self.ciphers)
resp, dummy = self._request(
uri,
data=json.dumps(pyld),
headers=req_headers,
method="PUT",
url_username=username,
url_password=password,
force_basic_auth=basic_auth,
)
except HTTPError as e:
msg, data = self._get_extended_message(e)
return {'ret': False,
@@ -309,12 +348,15 @@ class RedfishUtils(object):
username, password, basic_auth = self._auth_params(req_headers)
try:
data = json.dumps(pyld) if pyld else None
resp = open_url(uri, data=data,
headers=req_headers, method="DELETE",
url_username=username, url_password=password,
force_basic_auth=basic_auth, validate_certs=False,
follow_redirects='all',
use_proxy=True, timeout=self.timeout, ciphers=self.ciphers)
resp, dummy = self._request(
uri,
data=data,
headers=req_headers,
method="DELETE",
url_username=username,
url_password=password,
force_basic_auth=basic_auth,
)
except HTTPError as e:
msg, data = self._get_extended_message(e)
return {'ret': False,
@@ -1119,7 +1161,8 @@ class RedfishUtils(object):
key = "Actions"
reset_type_values = ['On', 'ForceOff', 'GracefulShutdown',
'GracefulRestart', 'ForceRestart', 'Nmi',
'ForceOn', 'PushPowerButton', 'PowerCycle']
'ForceOn', 'PushPowerButton', 'PowerCycle',
'FullPowerCycle']
# command should be PowerOn, PowerForceOff, etc.
if not command.startswith('Power'):
@@ -3969,3 +4012,20 @@ class RedfishUtils(object):
'ret': True,
'entries': response['data']
}
def get_power_restore_policy(self, systems_uri):
# Retrieve System resource
response = self.get_request(self.root_uri + systems_uri)
if response['ret'] is False:
return response
return {
'ret': True,
'entries': response['data']['PowerRestorePolicy']
}
def get_multi_power_restore_policy(self):
return self.aggregate_systems(self.get_power_restore_policy)
def set_power_restore_policy(self, policy):
body = {'PowerRestorePolicy': policy}
return self.patch_request(self.root_uri + self.systems_uri, body, check_pyld=True)

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2025, Marco Noce <nce.marco@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 absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
def systemd_runner(module, command, **kwargs):
arg_formats = dict(
version=cmd_runner_fmt.as_fixed("--version"),
list_units=cmd_runner_fmt.as_fixed(["list-units", "--no-pager"]),
types=cmd_runner_fmt.as_func(lambda v: [] if not v else ["--type", ",".join(v)]),
all=cmd_runner_fmt.as_fixed("--all"),
plain=cmd_runner_fmt.as_fixed("--plain"),
no_legend=cmd_runner_fmt.as_fixed("--no-legend"),
show=cmd_runner_fmt.as_fixed("show"),
props=cmd_runner_fmt.as_func(lambda v: [] if not v else ["-p", ",".join(v)]),
dashdash=cmd_runner_fmt.as_fixed("--"),
unit=cmd_runner_fmt.as_list(),
)
runner = CmdRunner(
module,
command=command,
arg_formats=arg_formats,
check_rc=True,
**kwargs
)
return runner

View File

@@ -19,7 +19,7 @@ description:
extends_documentation_fragment:
- community.general.attributes
requirements:
- Python package C(BeautifulSoup).
- Python package C(BeautifulSoup) on Python 2, C(beautifulsoup4) on Python 3.
attributes:
check_mode:
support: full
@@ -206,17 +206,29 @@ members:
import re
from ansible_collections.community.general.plugins.module_utils import deps
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six import iteritems
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper, ModuleHelperException
with deps.declare("BeautifulSoup"):
from BeautifulSoup import BeautifulSoup
from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.six import raise_from, PY2
if PY2:
with deps.declare("BeautifulSoup"):
from BeautifulSoup import BeautifulSoup
else:
with deps.declare("beautifulsoup4"):
from bs4 import BeautifulSoup
# balancer member attributes extraction regexp:
EXPRESSION = re.compile(r"(b=([\w\.\-]+)&w=(https?|ajp|wss?|ftp|[sf]cgi)://([\w\.\-]+):?(\d*)([/\w\.\-]*)&?[\w\-\=]*)")
EXPRESSION = re.compile(to_text(r"(b=([\w\.\-]+)&w=(https?|ajp|wss?|ftp|[sf]cgi)://([\w\.\-]+):?(\d*)([/\w\.\-]*)&?[\w\-\=]*)"))
# Apache2 server version extraction regexp:
APACHE_VERSION_EXPRESSION = re.compile(r"SERVER VERSION: APACHE/([\d.]+)")
APACHE_VERSION_EXPRESSION = re.compile(to_text(r"SERVER VERSION: APACHE/([\d.]+)"))
def find_all(where, what):
if PY2:
return where.findAll(what)
return where.find_all(what)
def regexp_extraction(string, _regexp, groups=1):
@@ -256,22 +268,22 @@ class BalancerMember(object):
def get_member_attributes(self):
""" Returns a dictionary of a balancer member's attributes."""
resp, info = fetch_url(self.module, self.management_url)
resp, info = fetch_url(self.module, self.management_url, headers={'Referer': self.management_url})
if info['status'] != 200:
self.module.fail_json(msg="Could not get balancer_member_page, check for connectivity! {0}".format(info))
else:
try:
soup = BeautifulSoup(resp)
except TypeError as exc:
self.module.fail_json(msg="Cannot parse balancer_member_page HTML! {0}".format(exc))
else:
subsoup = soup.findAll('table')[1].findAll('tr')
keys = subsoup[0].findAll('th')
for valuesset in subsoup[1::1]:
if re.search(pattern=self.host, string=str(valuesset)):
values = valuesset.findAll('td')
return {keys[x].string: values[x].string for x in range(0, len(keys))}
raise ModuleHelperException("Could not get balancer_member_page, check for connectivity! {0}".format(info))
try:
soup = BeautifulSoup(resp)
except TypeError as exc:
raise_from(ModuleHelperException("Cannot parse balancer_member_page HTML! {0}".format(exc)), exc)
subsoup = find_all(find_all(soup, 'table')[1], 'tr')
keys = find_all(subsoup[0], 'th')
for valuesset in subsoup[1::1]:
if re.search(pattern=self.host, string=str(valuesset)):
values = find_all(valuesset, 'td')
return {keys[x].string: values[x].string for x in range(0, len(keys))}
def get_member_status(self):
""" Returns a dictionary of a balancer member's status attributes."""
@@ -280,7 +292,7 @@ class BalancerMember(object):
'hot_standby': 'Stby',
'ignore_errors': 'Ign'}
actual_status = self.attributes['Status']
status = {mode: patt in actual_status for mode, patt in iteritems(status_mapping)}
status = {mode: patt in actual_status for mode, patt in status_mapping.items()}
return status
def set_member_status(self, values):
@@ -294,9 +306,9 @@ class BalancerMember(object):
values_url = "".join("{0}={1}".format(url_param, 1 if values[mode] else 0) for mode, url_param in values_mapping.items())
request_body = "{0}{1}".format(request_body, values_url)
response, info = fetch_url(self.module, self.management_url, data=request_body)
response, info = fetch_url(self.module, self.management_url, data=request_body, headers={'Referer': self.management_url})
if info['status'] != 200:
self.module.fail_json(msg="Could not set the member status! " + self.host + " " + info['status'])
raise ModuleHelperException("Could not set the member status! {0} {1}".format(self.host, info['status']))
attributes = property(get_member_attributes)
status = property(get_member_status, set_member_status)
@@ -317,13 +329,10 @@ class BalancerMember(object):
class Balancer(object):
""" Apache httpd 2.4 mod_proxy balancer object"""
def __init__(self, host, suffix, module, tls=False):
if tls:
self.base_url = 'https://{0}'.format(host)
self.url = 'https://{0}{1}'.format(host, suffix)
else:
self.base_url = 'http://{0}'.format(host)
self.url = 'http://{0}{1}'.format(host, suffix)
def __init__(self, module, host, suffix, tls=False):
proto = "https" if tls else "http"
self.base_url = '{0}://{1}'.format(proto, host)
self.url = '{0}://{1}{2}'.format(proto, host, suffix)
self.module = module
self.page = self.fetch_balancer_page()
@@ -331,37 +340,38 @@ class Balancer(object):
""" Returns the balancer management html page as a string for later parsing."""
resp, info = fetch_url(self.module, self.url)
if info['status'] != 200:
self.module.fail_json(msg="Could not get balancer page! HTTP status response: {0}".format(info['status']))
else:
content = resp.read()
apache_version = regexp_extraction(content.upper(), APACHE_VERSION_EXPRESSION, 1)
if apache_version:
if not re.search(pattern=r"2\.4\.[\d]*", string=apache_version):
self.module.fail_json(msg="This module only acts on an Apache2 2.4+ instance, current Apache2 version: " + str(apache_version))
return content
raise ModuleHelperException("Could not get balancer page! HTTP status response: {0}".format(info['status']))
self.module.fail_json(msg="Could not get the Apache server version from the balancer-manager")
content = to_text(resp.read())
apache_version = regexp_extraction(content.upper(), APACHE_VERSION_EXPRESSION, 1)
if not apache_version:
raise ModuleHelperException("Could not get the Apache server version from the balancer-manager")
if not re.search(pattern=r"2\.4\.[\d]*", string=apache_version):
raise ModuleHelperException("This module only acts on an Apache2 2.4+ instance, current Apache2 version: {0}".format(apache_version))
return content
def get_balancer_members(self):
""" Returns members of the balancer as a generator object for later iteration."""
try:
soup = BeautifulSoup(self.page)
except TypeError:
self.module.fail_json(msg="Cannot parse balancer page HTML! {0}".format(self.page))
else:
for element in soup.findAll('a')[1::1]:
balancer_member_suffix = str(element.get('href'))
if not balancer_member_suffix:
self.module.fail_json(msg="Argument 'balancer_member_suffix' is empty!")
else:
yield BalancerMember(self.base_url + balancer_member_suffix, self.url, self.module)
except TypeError as e:
raise_from(ModuleHelperException("Cannot parse balancer page HTML! {0}".format(self.page)), e)
elements = find_all(soup, 'a')
for element in elements[1::1]:
balancer_member_suffix = element.get('href')
if not balancer_member_suffix:
raise ModuleHelperException("Argument 'balancer_member_suffix' is empty!")
yield BalancerMember(self.base_url + balancer_member_suffix, self.url, self.module)
members = property(get_balancer_members)
def main():
class ApacheModProxy(ModuleHelper):
""" Initiates module."""
module = AnsibleModule(
module = dict(
argument_spec=dict(
balancer_vhost=dict(required=True, type='str'),
balancer_url_suffix=dict(default="/balancer-manager/", type='str'),
@@ -372,64 +382,47 @@ def main():
),
supports_check_mode=True
)
use_old_vardict = False
deps.validate(module)
def __init_module__(self):
deps.validate(self.module)
if module.params['state'] is not None:
states = module.params['state']
if (len(states) > 1) and (("present" in states) or ("enabled" in states)):
module.fail_json(msg="state present/enabled is mutually exclusive with other states!")
else:
states = ['None']
if len(self.vars.state or []) > 1 and ("present" in self.vars.state or "enabled" in self.vars.state):
self.do_raise(msg="states present/enabled are mutually exclusive with other states!")
mybalancer = Balancer(module.params['balancer_vhost'],
module.params['balancer_url_suffix'],
module=module,
tls=module.params['tls'])
self.mybalancer = Balancer(self.module, self.vars.balancer_vhost, self.vars.balancer_url_suffix, tls=self.vars.tls)
if module.params['member_host'] is None:
json_output_list = []
for member in mybalancer.members:
json_output_list.append(member.as_dict())
module.exit_json(
changed=False,
members=json_output_list
)
else:
changed = False
member_exists = False
member_status = {'disabled': False, 'drained': False, 'hot_standby': False, 'ignore_errors': False}
for mode in member_status:
for state in states:
if mode == state:
member_status[mode] = True
elif mode == 'disabled' and state == 'absent':
member_status[mode] = True
for member in mybalancer.members:
if str(member.host) == module.params['member_host']:
member_exists = True
if module.params['state'] is not None:
member_status_before = member.status
if not module.check_mode:
member_status_after = member.status = member_status
else:
member_status_after = member_status
if member_status_before != member_status_after:
changed = True
json_output = member.as_dict()
if member_exists:
module.exit_json(
changed=changed,
member=json_output
)
def __run__(self):
if self.vars.member_host is None:
self.vars.members = [member.as_dict() for member in self.mybalancer.members]
else:
module.fail_json(
msg='{member_host} is not a member of the balancer {balancer_vhost}!'.format(
member_host=module.params['member_host'],
balancer_vhost=module.params['balancer_vhost'],
)
)
member_exists = False
member_status = {'disabled': False, 'drained': False, 'hot_standby': False, 'ignore_errors': False}
for mode in member_status:
for state in self.vars.state or []:
if mode == state:
member_status[mode] = True
elif mode == 'disabled' and state == 'absent':
member_status[mode] = True
for member in self.mybalancer.members:
if str(member.host) == self.vars.member_host:
member_exists = True
if self.vars.state is not None:
member_status_before = member.status
if not self.check_mode:
member_status_after = member.status = member_status
else:
member_status_after = member_status
self.changed |= (member_status_before != member_status_after)
self.vars.member = member.as_dict()
if not member_exists:
self.do_raise(msg='{0} is not a member of the balancer {1}!'.format(self.vars.member_host, self.vars.balancer_vhost))
def main():
ApacheModProxy.execute()
if __name__ == '__main__':

View File

@@ -194,6 +194,7 @@ def create_apache_identifier(name):
# re expressions to extract subparts of names
re_workarounds = [
('php8', re.compile(r'^(php)[\d\.]+')),
('php', re.compile(r'^(php\d)\.')),
]

View File

@@ -120,7 +120,7 @@ EXAMPLES = r"""
community.general.btrfs_subvolume:
name: /@
snapshot_source: /
default: Yes
default: true
filesystem_device: /dev/vda2
- name: Create a snapshot of the /@ subvolume and recursively creating intermediate subvolumes as required

View File

@@ -14,6 +14,12 @@ module: clc_alert_policy
short_description: Create or Delete Alert Policies at CenturyLink Cloud
description:
- An Ansible module to Create or Delete Alert Policies at CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_blueprint_package
short_description: Deploys a blue print package on a set of servers in CenturyLink Cloud
description:
- An Ansible module to deploy blue print package on a set of servers in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_firewall_policy
short_description: Create/delete/update firewall policies
description:
- Create or delete or update firewall policies on Centurylink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_group
short_description: Create/delete Server Groups at Centurylink Cloud
description:
- Create or delete Server Groups at Centurylink Centurylink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_loadbalancer
short_description: Create, Delete shared loadbalancers in CenturyLink Cloud
description:
- An Ansible module to Create, Delete shared loadbalancers in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_modify_server
short_description: Modify servers in CenturyLink Cloud
description:
- An Ansible module to modify servers in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_publicip
short_description: Add and Delete public IPs on servers in CenturyLink Cloud
description:
- An Ansible module to add or delete public IP addresses on an existing server or servers in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_server
short_description: Create, Delete, Start and Stop servers in CenturyLink Cloud
description:
- An Ansible module to Create, Delete, Start and Stop servers in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -14,6 +14,12 @@ module: clc_server_snapshot
short_description: Create, Delete and Restore server snapshots in CenturyLink Cloud
description:
- An Ansible module to Create, Delete and Restore server snapshots in CenturyLink Cloud.
deprecated:
removed_in: 11.0.0
why: >
Lumen Public Cloud (formerly known as CenturyLink Cloud) has gone End-of-Life in September 2023.
See more at U(https://www.ctl.io/knowledge-base/release-notes/2023/lumen-public-cloud-platform-end-of-life-notice/?).
alternative: There is none.
extends_documentation_fragment:
- community.general.attributes
- community.general.clc

View File

@@ -551,6 +551,9 @@ class CloudflareAPI(object):
try:
content = resp.read()
except AttributeError:
content = None
if not content:
if info['body']:
content = info['body']
else:
@@ -685,6 +688,7 @@ class CloudflareAPI(object):
else:
search_value = content
zone_id = self._get_zone_id(params['zone'])
records = self.get_dns_records(params['zone'], params['type'], search_record, search_value)
for rr in records:
@@ -692,11 +696,11 @@ class CloudflareAPI(object):
if not ((rr['type'] == params['type']) and (rr['name'] == search_record) and (rr['content'] == content)):
self.changed = True
if not self.module.check_mode:
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
else:
self.changed = True
if not self.module.check_mode:
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(rr['zone_id'], rr['id']), 'DELETE')
result, info = self._cf_api_call('/zones/{0}/dns_records/{1}'.format(zone_id, rr['id']), 'DELETE')
return self.changed
def ensure_dns_record(self, **kwargs):

View File

@@ -220,7 +220,7 @@ def normalize_link_obj(api_obj, module_obj, key):
for obj in module_objs:
identifier = obj.get("ID")
name = obj.get("Name)")
name = obj.get("Name")
if identifier and not name and identifier in id_to_name:
obj["Name"] = id_to_name[identifier]
if not identifier and name and name in name_to_id:

View File

@@ -77,6 +77,13 @@ EXAMPLES = r"""
community.general.copr:
state: absent
name: '@copr/integration_tests'
- name: Install Caddy
community.general.copr:
name: '@caddy/caddy'
chroot: fedora-rawhide-{{ ansible_facts.architecture }}
includepkgs:
- caddy
"""
RETURN = r"""

View File

@@ -221,6 +221,43 @@ def get_packages(module, patterns, only_installed=False):
return packages_available_map_name_evrs
def get_package_mgr():
for bin_path in (DNF_BIN,):
if os.path.exists(bin_path):
return "dnf5" if os.path.realpath(bin_path) == "/usr/bin/dnf5" else "dnf"
# fallback to dnf
return "dnf"
def get_package_list(module, package_mgr="dnf"):
if package_mgr == "dnf":
return do_versionlock(module, "list").split()
package_list = []
if package_mgr == "dnf5":
stanza_start = False
package_name = None
for line in do_versionlock(module, "list").splitlines():
if line.startswith(("#", " ")):
continue
if line.startswith("Package name:"):
stanza_start = True
dummy, name = line.split(":", 1)
name = name.strip()
pkg_name = get_packages(module, patterns=[name])
package_name = "%s-%s.*" % (name, pkg_name[name].pop())
if package_name and package_name not in package_list:
package_list.append(package_name)
if line.startswith("evr"):
dummy, package_version = line.split("=", 1)
package_version = package_version.strip()
if stanza_start:
if package_name and package_name not in package_list:
package_list.append(package_name)
stanza_start = False
return package_list
def main():
module = AnsibleModule(
argument_spec=dict(
@@ -239,9 +276,10 @@ def main():
msg = ""
# Check module pre-requisites.
if not os.path.exists(DNF_BIN):
module.fail_json(msg="%s was not found" % DNF_BIN)
if not os.path.exists(VERSIONLOCK_CONF):
global DNF_BIN
DNF_BIN = module.get_bin_path('dnf', True)
package_mgr = get_package_mgr()
if package_mgr == "dnf" and not os.path.exists(VERSIONLOCK_CONF):
module.fail_json(msg="plugin versionlock is required")
# Check incompatible options.
@@ -250,7 +288,7 @@ def main():
if state != "clean" and not patterns:
module.fail_json(msg="name list is required for %s state" % state)
locklist_pre = do_versionlock(module, "list").split()
locklist_pre = get_package_list(module, package_mgr=package_mgr)
specs_toadd = []
specs_todelete = []
@@ -329,7 +367,7 @@ def main():
"specs_todelete": specs_todelete
}
if not module.check_mode:
response["locklist_post"] = do_versionlock(module, "list").split()
response["locklist_post"] = get_package_list(module, package_mgr=package_mgr)
else:
if state == "clean":
response["locklist_post"] = []

View File

@@ -163,33 +163,38 @@ def parse_error(string):
def install_plugin(module, plugin_bin, plugin_name, version, src, url, proxy_host, proxy_port, timeout, force):
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["present"]]
cmd = [plugin_bin, PACKAGE_STATE_MAP["present"]]
is_old_command = (os.path.basename(plugin_bin) == 'plugin')
# Timeout and version are only valid for plugin, not elasticsearch-plugin
if is_old_command:
if timeout:
cmd_args.append("--timeout %s" % timeout)
cmd.append("--timeout")
cmd.append(timeout)
if version:
plugin_name = plugin_name + '/' + version
cmd_args[2] = plugin_name
cmd[2] = plugin_name
if proxy_host and proxy_port:
cmd_args.append("-DproxyHost=%s -DproxyPort=%s" % (proxy_host, proxy_port))
java_opts = ["-Dhttp.proxyHost=%s" % proxy_host,
"-Dhttp.proxyPort=%s" % proxy_port,
"-Dhttps.proxyHost=%s" % proxy_host,
"-Dhttps.proxyPort=%s" % proxy_port]
module.run_command_environ_update = dict(CLI_JAVA_OPTS=" ".join(java_opts), # Elasticsearch 8.x
ES_JAVA_OPTS=" ".join(java_opts)) # Older Elasticsearch versions
# Legacy ES 1.x
if url:
cmd_args.append("--url %s" % url)
cmd.append("--url")
cmd.append(url)
if force:
cmd_args.append("--batch")
cmd.append("--batch")
if src:
cmd_args.append(src)
cmd.append(src)
else:
cmd_args.append(plugin_name)
cmd = " ".join(cmd_args)
cmd.append(plugin_name)
if module.check_mode:
rc, out, err = 0, "check mode", ""
@@ -204,9 +209,7 @@ def install_plugin(module, plugin_bin, plugin_name, version, src, url, proxy_hos
def remove_plugin(module, plugin_bin, plugin_name):
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["absent"], parse_plugin_repo(plugin_name)]
cmd = " ".join(cmd_args)
cmd = [plugin_bin, PACKAGE_STATE_MAP["absent"], parse_plugin_repo(plugin_name)]
if module.check_mode:
rc, out, err = 0, "check mode", ""

View File

@@ -259,7 +259,12 @@ class GithubDeployKey(object):
key_id = response_body["id"]
self.module.exit_json(changed=True, msg="Deploy key successfully added", id=key_id)
elif status_code == 422:
self.module.exit_json(changed=False, msg="Deploy key already exists")
# there might be multiple reasons for a 422
# so we must check if the reason is that the key already exists
if self.get_existing_key():
self.module.exit_json(changed=False, msg="Deploy key already exists")
else:
self.handle_error(method="POST", info=info)
else:
self.handle_error(method="POST", info=info)

View File

@@ -44,6 +44,12 @@ options:
- This option is only used on creation, not for updates.
type: path
version_added: "4.2.0"
build_timeout:
description:
- Maximum number of seconds a CI job can run.
- If not specified on creation, GitLab will impose a default value.
type: int
version_added: "10.6.0"
builds_access_level:
description:
- V(private) means that repository CI/CD is allowed only to project members.
@@ -430,6 +436,7 @@ class GitLabProject(object):
project_options = {
'allow_merge_on_skipped_pipeline': options['allow_merge_on_skipped_pipeline'],
'builds_access_level': options['builds_access_level'],
'build_timeout': options['build_timeout'],
'ci_config_path': options['ci_config_path'],
'container_expiration_policy': options['container_expiration_policy'],
'container_registry_access_level': options['container_registry_access_level'],
@@ -591,6 +598,7 @@ def main():
allow_merge_on_skipped_pipeline=dict(type='bool'),
avatar_path=dict(type='path'),
builds_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
build_timeout=dict(type='int'),
ci_config_path=dict(type='str'),
container_expiration_policy=dict(type='dict', default=None, options=dict(
cadence=dict(type='str', choices=["1d", "7d", "14d", "1month", "3month"]),
@@ -664,6 +672,7 @@ def main():
allow_merge_on_skipped_pipeline = module.params['allow_merge_on_skipped_pipeline']
avatar_path = module.params['avatar_path']
builds_access_level = module.params['builds_access_level']
build_timeout = module.params['build_timeout']
ci_config_path = module.params['ci_config_path']
container_expiration_policy = module.params['container_expiration_policy']
container_registry_access_level = module.params['container_registry_access_level']
@@ -748,6 +757,7 @@ def main():
"allow_merge_on_skipped_pipeline": allow_merge_on_skipped_pipeline,
"avatar_path": avatar_path,
"builds_access_level": builds_access_level,
"build_timeout": build_timeout,
"ci_config_path": ci_config_path,
"container_expiration_policy": container_expiration_policy,
"container_registry_access_level": container_registry_access_level,

View File

@@ -48,8 +48,9 @@ options:
description:
- The access level for the user.
- Required if O(state=present), user state is set to present.
- V(owner) was added in community.general 10.6.0.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
@@ -67,8 +68,9 @@ options:
description:
- The access level for the user.
- Required if O(state=present), user state is set to present.
- V(owner) was added in community.general 10.6.0.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
required: true
version_added: 3.7.0
state:
@@ -84,9 +86,10 @@ options:
- Adds/remove users of the given access_level to match the given O(gitlab_user)/O(gitlab_users_access) list. If omitted
do not purge orphaned members.
- Is only used when O(state=present).
- V(owner) was added in community.general 10.6.0.
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
version_added: 3.7.0
"""
@@ -239,16 +242,16 @@ def main():
project=dict(type='str', required=True),
gitlab_user=dict(type='list', elements='str'),
state=dict(type='str', default='present', choices=['present', 'absent']),
access_level=dict(type='str', choices=['guest', 'reporter', 'developer', 'maintainer']),
access_level=dict(type='str', choices=['guest', 'reporter', 'developer', 'maintainer', 'owner']),
purge_users=dict(type='list', elements='str', choices=[
'guest', 'reporter', 'developer', 'maintainer']),
'guest', 'reporter', 'developer', 'maintainer', 'owner']),
gitlab_users_access=dict(
type='list',
elements='dict',
options=dict(
name=dict(type='str', required=True),
access_level=dict(type='str', choices=[
'guest', 'reporter', 'developer', 'maintainer'], required=True),
'guest', 'reporter', 'developer', 'maintainer', 'owner'], required=True),
)
),
))
@@ -286,6 +289,7 @@ def main():
'reporter': gitlab.const.REPORTER_ACCESS,
'developer': gitlab.const.DEVELOPER_ACCESS,
'maintainer': gitlab.const.MAINTAINER_ACCESS,
'owner': gitlab.const.OWNER_ACCESS,
}
gitlab_project = module.params['project']

View File

@@ -385,12 +385,39 @@ class Homebrew(object):
self.outdated_packages.add(package_name)
def _extract_package_name(self, package_detail, is_cask):
canonical_name = package_detail["full_token"] if is_cask else package_detail["full_name"] # For ex: 'sqlite'
all_valid_names = set(package_detail.get("aliases", [])) # For ex: {'sqlite3'}
all_valid_names.add(canonical_name)
# "brew info" can lookup by name, full_name, token, full_token, or aliases
# In addition, any name can be prefixed by the tap.
# Any of these can be supplied by the user as the package name. In case
# of ambiguity, where a given name might match multiple packages,
# formulae are preferred over casks. For all other ambiguities, the
# results are an error. Note that in the homebrew/core and
# homebrew/cask taps, there are no "other" ambiguities.
if is_cask: # according to brew info
name = package_detail["token"]
full_name = package_detail["full_token"]
else:
name = package_detail["name"]
full_name = package_detail["full_name"]
# Issue https://github.com/ansible-collections/community.general/issues/9803:
# name can include the tap as a prefix, in order to disambiguate,
# e.g. casks from identically named formulae.
#
# Issue https://github.com/ansible-collections/community.general/issues/10012:
# package_detail["tap"] is None if package is no longer available.
tapped_name = [package_detail["tap"] + "/" + name] if package_detail["tap"] else []
aliases = package_detail.get("aliases", [])
package_names = set([name, full_name] + tapped_name + aliases)
# Finally, identify which of all those package names was the one supplied by the user.
package_names = package_names & set(self.packages)
if len(package_names) != 1:
self.failed = True
self.message = "Package names are missing or ambiguous: " + ", ".join(str(p) for p in package_names)
raise HomebrewException(self.message)
# Then make sure the user provided name resurface.
return (all_valid_names & set(self.packages)).pop()
return package_names.pop()
def _get_packages_info(self):
cmd = [
@@ -831,7 +858,7 @@ def main():
p = module.params
if p['name']:
packages = p['name']
packages = [package_name.lower() for package_name in p['name']]
else:
packages = None

View File

@@ -425,10 +425,7 @@ class HomebrewCask(object):
cmd = base_opts + [self.current_cask]
rc, out, err = self.module.run_command(cmd)
if rc == 0:
return True
else:
return False
return rc == 0
def _get_brew_version(self):
if self.brew_version:
@@ -436,11 +433,13 @@ class HomebrewCask(object):
cmd = [self.brew_path, '--version']
rc, out, err = self.module.run_command(cmd, check_rc=True)
dummy, out, dummy = self.module.run_command(cmd, check_rc=True)
# get version string from first line of "brew --version" output
version = out.split('\n')[0].split(' ')[1]
self.brew_version = version
pattern = r"Homebrew (.*)(\d+\.\d+\.\d+)(-dirty)?"
rematch = re.search(pattern, out)
if not rematch:
self.module.fail_json(msg="Failed to match regex to get brew version", stdout=out)
self.brew_version = rematch.groups()[1]
return self.brew_version
def _brew_cask_command_is_deprecated(self):

View File

@@ -72,7 +72,7 @@ EXAMPLES = r"""
- name: Remove the foo service (equivalent to `brew services stop foo`)
community.general.homebrew_services:
name: foo
service_state: absent
state: absent
"""
RETURN = r"""

View File

@@ -76,6 +76,12 @@ options:
default: TLSv1
type: str
choices: ["SSLv3", "SSLv23", "TLSv1", "TLSv1_1", "TLSv1_2"]
idempotent_boot_once:
description:
- "This option makes O(state=boot_once) succeed instead of failing when the server is already powered on."
type: bool
default: false
version_added: 10.6.0
requirements:
- python-hpilo
notes:
@@ -138,6 +144,7 @@ def main():
image=dict(type='str'),
state=dict(type='str', default='boot_once', choices=['boot_always', 'boot_once', 'connect', 'disconnect', 'no_boot', 'poweroff']),
force=dict(type='bool', default=False),
idempotent_boot_once=dict(type='bool', default=False),
ssl_version=dict(type='str', default='TLSv1', choices=['SSLv3', 'SSLv23', 'TLSv1', 'TLSv1_1', 'TLSv1_2']),
)
)
@@ -152,6 +159,7 @@ def main():
image = module.params['image']
state = module.params['state']
force = module.params['force']
idempotent_boot_once = module.params['idempotent_boot_once']
ssl_version = getattr(hpilo.ssl, 'PROTOCOL_' + module.params.get('ssl_version').upper().replace('V', 'v'))
ilo = hpilo.Ilo(host, login=login, password=password, ssl_version=ssl_version)
@@ -187,13 +195,21 @@ def main():
power_status = ilo.get_host_power_status()
if not force and power_status == 'ON':
module.fail_json(msg='HP iLO (%s) reports that the server is already powered on !' % host)
if power_status == 'ON':
ilo.warm_boot_server()
# ilo.cold_boot_server()
changed = True
if not force and not idempotent_boot_once:
# module.deprecate(
# 'The failure of the module when the server is already powered on is being deprecated.'
# ' Please set the parameter "idempotent_boot_once=true" to start using the new behavior.',
# version='11.0.0',
# collection_name='community.general'
# )
module.fail_json(msg='HP iLO (%s) reports that the server is already powered on !' % host)
elif not force and idempotent_boot_once:
pass
elif force:
ilo.warm_boot_server()
# ilo.cold_boot_server()
changed = True
else:
ilo.press_pwr_btn()
# ilo.reset_server()

View File

@@ -85,7 +85,7 @@ EXAMPLES = r"""
password: '9s36?;fyNp'
owner: root
group: www-data
mode: 0640
mode: '0640'
- name: Remove a user from a password file
community.general.htpasswd:

View File

@@ -16,6 +16,7 @@ description:
- For use with Dell iDRAC operations that require Redfish OEM extensions.
extends_documentation_fragment:
- community.general.attributes
- community.general.redfish
attributes:
check_mode:
support: none
@@ -62,6 +63,12 @@ options:
- ID of the System, Manager or Chassis to modify.
type: str
version_added: '0.2.0'
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author: "Jose Delarosa (@jose-delarosa)"
"""
@@ -93,7 +100,7 @@ return_values:
import re
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC
from ansible.module_utils.common.text.converters import to_native
@@ -147,17 +154,19 @@ CATEGORY_COMMANDS_ALL = {
def main():
result = {}
return_values = {}
argument_spec = dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10),
resource_id=dict()
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10),
resource_id=dict()
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -16,6 +16,7 @@ description:
- Builds Redfish URIs locally and sends them to remote iDRAC controllers to set or update a configuration attribute.
extends_documentation_fragment:
- community.general.attributes
- community.general.redfish
attributes:
check_mode:
support: none
@@ -71,6 +72,12 @@ options:
- ID of the System, Manager or Chassis to modify.
type: str
version_added: '0.2.0'
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author: "Jose Delarosa (@jose-delarosa)"
"""
@@ -154,7 +161,7 @@ from ansible.module_utils.common.validation import (
check_mutually_exclusive,
check_required_arguments
)
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC
from ansible.module_utils.common.text.converters import to_native
@@ -246,18 +253,20 @@ CATEGORY_COMMANDS_MUTUALLY_EXCLUSIVE = {
def main():
result = {}
argument_spec = dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
manager_attributes=dict(type='dict', default={}),
timeout=dict(type='int', default=10),
resource_id=dict()
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
manager_attributes=dict(type='dict', default={}),
timeout=dict(type='int', default=10),
resource_id=dict()
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -17,6 +17,7 @@ description:
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
- community.general.redfish
attributes:
check_mode:
version_added: 3.3.0
@@ -57,6 +58,12 @@ options:
- Timeout in seconds for HTTP requests to iDRAC.
default: 10
type: int
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author: "Jose Delarosa (@jose-delarosa)"
"""
@@ -124,7 +131,7 @@ msg:
"""
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils, REDFISH_COMMON_ARGUMENT_SPEC
from ansible.module_utils.common.text.converters import to_native
@@ -177,16 +184,18 @@ CATEGORY_COMMANDS_ALL = {
def main():
result = {}
argument_spec = dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10)
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10)
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -19,6 +19,7 @@ attributes:
support: none
extends_documentation_fragment:
- community.general.attributes
- community.general.redfish
options:
category:
required: true
@@ -58,6 +59,12 @@ options:
- Timeout in seconds for HTTP requests to iLO.
default: 60
type: int
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author:
- Varni H P (@varini-hp)
"""
@@ -96,22 +103,25 @@ CATEGORY_COMMANDS_ALL = {
}
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
def main():
result = {}
argument_spec = dict(
category=dict(required=True, choices=list(CATEGORY_COMMANDS_ALL.keys())),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
timeout=dict(type="int", default=60),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True)
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True, choices=list(CATEGORY_COMMANDS_ALL.keys())),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
timeout=dict(type="int", default=60),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True)
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -15,6 +15,7 @@ description:
- For use with HPE iLO operations that require Redfish OEM extensions.
extends_documentation_fragment:
- community.general.attributes
- community.general.redfish
attributes:
check_mode:
support: none
@@ -65,6 +66,12 @@ options:
description:
- Value of the attribute to be configured.
type: str
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author:
- "Bhavya B (@bhavya06)"
"""
@@ -113,25 +120,28 @@ CATEGORY_COMMANDS_ALL = {
}
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.text.converters import to_native
def main():
result = {}
argument_spec = dict(
category=dict(required=True, choices=list(
CATEGORY_COMMANDS_ALL.keys())),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
attribute_name=dict(required=True),
attribute_value=dict(type='str'),
timeout=dict(type='int', default=10)
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True, choices=list(
CATEGORY_COMMANDS_ALL.keys())),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
attribute_name=dict(required=True),
attribute_value=dict(type='str'),
timeout=dict(type='int', default=10)
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -16,6 +16,7 @@ description:
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
- community.general.redfish
options:
category:
required: true
@@ -51,6 +52,12 @@ options:
- Timeout in seconds for HTTP requests to iLO.
default: 10
type: int
validate_certs:
version_added: 10.6.0
ca_path:
version_added: 10.6.0
ciphers:
version_added: 10.6.0
author:
- "Bhavya B (@bhavya06)"
"""
@@ -108,21 +115,24 @@ CATEGORY_COMMANDS_DEFAULT = {
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
from ansible_collections.community.general.plugins.module_utils.redfish_utils import REDFISH_COMMON_ARGUMENT_SPEC
def main():
result = {}
category_list = []
argument_spec = dict(
category=dict(required=True, type='list', elements='str'),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10)
)
argument_spec.update(REDFISH_COMMON_ARGUMENT_SPEC)
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True, type='list', elements='str'),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10)
),
argument_spec,
required_together=[
('username', 'password'),
],

View File

@@ -270,6 +270,10 @@ def ensure(module, client):
data = {}
for key in diff:
data[key] = module_host.get(key)
if "usercertificate" not in data:
data["usercertificate"] = [
cert['__base64__'] for cert in ipa_host.get("usercertificate", [])
]
ipa_host_show = client.host_show(name=name)
if ipa_host_show.get('has_keytab', True) and (state == 'disabled' or module.params.get('random_password')):
client.host_disable(name=name)

View File

@@ -124,7 +124,7 @@ EXAMPLES = r"""
server: irc.example.net
use_tls: true
validate_certs: true
channel: #t1
channel: '#t1'
msg: Hello world
- name: Send a message to an IRC channel
@@ -134,7 +134,7 @@ EXAMPLES = r"""
server: irc.example.net
use_tls: true
validate_certs: true
channel: #t1
channel: '#t1'
msg: 'All finished at {{ ansible_date_time.iso8601 }}'
color: red
nick: ansibleIRC
@@ -146,7 +146,7 @@ EXAMPLES = r"""
server: irc.example.net
use_tls: true
validate_certs: true
channel: #t1
channel: '#t1'
nick_to:
- nick1
- nick2

View File

@@ -315,12 +315,13 @@ def _export_public_cert_from_pkcs12(module, executable, pkcs_file, alias, passwo
"-noprompt",
"-keystore",
pkcs_file,
"-alias",
alias,
"-storetype",
"pkcs12",
"-rfc"
]
# Append optional alias
if alias:
export_cmd.extend(["-alias", alias])
(export_rc, export_stdout, export_err) = module.run_command(export_cmd, data=password, check_rc=False)
if export_rc != 0:
@@ -393,6 +394,10 @@ def import_pkcs12_path(module, executable, pkcs12_path, pkcs12_pass, pkcs12_alia
keystore_path, keystore_pass, keystore_alias, keystore_type):
''' Import pkcs12 from path into keystore located on
keystore_path as alias '''
optional_aliases = {
"-destalias": keystore_alias,
"-srcalias": pkcs12_alias
}
import_cmd = [
executable,
"-importkeystore",
@@ -401,13 +406,14 @@ def import_pkcs12_path(module, executable, pkcs12_path, pkcs12_pass, pkcs12_alia
"pkcs12",
"-srckeystore",
pkcs12_path,
"-srcalias",
pkcs12_alias,
"-destkeystore",
keystore_path,
"-destalias",
keystore_alias
]
# Append optional aliases
for flag, value in optional_aliases.items():
if value:
import_cmd.extend([flag, value])
import_cmd += _get_keystore_type_keytool_parameters(keystore_type)
secret_data = "%s\n%s" % (keystore_pass, pkcs12_pass)

View File

@@ -59,6 +59,18 @@ options:
- The personal access token to log-in with.
- Mutually exclusive with O(username) and O(password).
version_added: 4.2.0
client_cert:
type: path
description:
- Client certificate if required.
- In addition to O(username) and O(password) or O(token). Not mutually exclusive.
version_added: 10.4.0
client_key:
type: path
description:
- Client certificate key if required.
- In addition to O(username) and O(password) or O(token). Not mutually exclusive.
version_added: 10.4.0
project:
type: str
@@ -446,6 +458,23 @@ EXAMPLES = r"""
operation: attach
attachment:
filename: topsecretreport.xlsx
# Use username, password and client certificate authentification
- name: Create an issue
community.general.jira:
uri: '{{ server }}'
username: '{{ user }}'
password: '{{ pass }}'
client_cert: '{{ path/to/client-cert }}'
client_key: '{{ path/to/client-key }}'
# Use token and client certificate authentification
- name: Create an issue
community.general.jira:
uri: '{{ server }}'
token: '{{ token }}'
client_cert: '{{ path/to/client-cert }}'
client_key: '{{ path/to/client-key }}'
"""
import base64
@@ -480,6 +509,8 @@ class JIRA(StateModuleHelper):
username=dict(type='str'),
password=dict(type='str', no_log=True),
token=dict(type='str', no_log=True),
client_cert=dict(type='path'),
client_key=dict(type='path'),
project=dict(type='str', ),
summary=dict(type='str', ),
description=dict(type='str', ),
@@ -511,6 +542,7 @@ class JIRA(StateModuleHelper):
],
required_together=[
['username', 'password'],
['client_cert', 'client_key']
],
required_one_of=[
['username', 'token'],

View File

@@ -308,6 +308,8 @@ def create_or_update_executions(kc, config, realm='master'):
}
# add the execution configuration
if new_exec["authenticationConfig"] is not None:
if "authenticationConfig" in execution and "id" in execution["authenticationConfig"]:
kc.delete_authentication_config(execution["authenticationConfig"]["id"], realm=realm)
kc.add_authenticationConfig_to_execution(updated_exec["id"], new_exec["authenticationConfig"], realm=realm)
for key in new_exec:
# remove unwanted key for the next API call

View File

@@ -720,7 +720,7 @@ end_state:
"""
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
keycloak_argument_spec, get_token, KeycloakError, is_struct_included
keycloak_argument_spec, get_token, KeycloakError
from ansible.module_utils.basic import AnsibleModule
import copy
@@ -758,12 +758,30 @@ def normalise_cr(clientrep, remove_ids=False):
if remove_ids:
mapper.pop('id', None)
# Convert bool to string
if 'config' in mapper:
for key, value in mapper['config'].items():
if isinstance(value, bool):
mapper['config'][key] = str(value).lower()
# Set to a default value.
mapper['consentRequired'] = mapper.get('consentRequired', False)
if 'attributes' in clientrep:
for key, value in clientrep['attributes'].items():
if isinstance(value, bool):
clientrep['attributes'][key] = str(value).lower()
clientrep['attributes'].pop('client.secret.creation.time', None)
return clientrep
def normalize_kc_resp(clientrep):
# kc drops the variable 'authorizationServicesEnabled' if set to false
# to minimize diff/changes we set it to false if not set by kc
if clientrep and 'authorizationServicesEnabled' not in clientrep:
clientrep['authorizationServicesEnabled'] = False
def sanitize_cr(clientrep):
""" Removes probably sensitive details from a client representation.
@@ -955,6 +973,8 @@ def main():
else:
before_client = kc.get_client_by_id(cid, realm=realm)
normalize_kc_resp(before_client)
if before_client is None:
before_client = {}
@@ -1026,7 +1046,7 @@ def main():
if module._diff:
result['diff'] = dict(before=sanitize_cr(before_norm),
after=sanitize_cr(desired_norm))
result['changed'] = not is_struct_included(desired_norm, before_norm, CLIENT_META_DATA)
result['changed'] = desired_norm != before_norm
module.exit_json(**result)
@@ -1034,6 +1054,8 @@ def main():
kc.update_client(cid, desired_client, realm=realm)
after_client = kc.get_client_by_id(cid, realm=realm)
normalize_kc_resp(after_client)
if before_client == after_client:
result['changed'] = False
if module._diff:

View File

@@ -528,8 +528,7 @@ EXAMPLES = r"""
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
id: realm
realm: realm
realm: unique_realm_name
state: present
- name: Delete a Keycloak realm
@@ -539,7 +538,7 @@ EXAMPLES = r"""
auth_realm: master
auth_username: USERNAME
auth_password: PASSWORD
id: test
realm: unique_realm_name
state: absent
"""
@@ -554,7 +553,7 @@ proposed:
description: Representation of proposed realm.
returned: always
type: dict
sample: {id: "test"}
sample: {realm: "test"}
existing:
description: Representation of existing realm (sample is truncated).
@@ -767,9 +766,6 @@ def main():
# Process a creation
result['changed'] = True
if 'id' not in desired_realm:
module.fail_json(msg='id needs to be specified when creating a new realm')
if module._diff:
result['diff'] = dict(before='', after=sanitize_cr(desired_realm))
@@ -778,11 +774,11 @@ def main():
# create it
kc.create_realm(desired_realm)
after_realm = kc.get_realm_by_id(desired_realm['id'])
after_realm = kc.get_realm_by_id(desired_realm['realm'])
result['end_state'] = sanitize_cr(after_realm)
result['msg'] = 'Realm %s has been created.' % desired_realm['id']
result['msg'] = 'Realm %s has been created.' % desired_realm['realm']
module.exit_json(**result)
else:
@@ -816,7 +812,7 @@ def main():
result['diff'] = dict(before=before_realm_sanitized,
after=sanitize_cr(after_realm))
result['msg'] = 'Realm %s has been updated.' % desired_realm['id']
result['msg'] = 'Realm %s has been updated.' % desired_realm['realm']
module.exit_json(**result)
else:
@@ -835,7 +831,7 @@ def main():
result['proposed'] = {}
result['end_state'] = {}
result['msg'] = 'Realm %s has been deleted.' % before_realm['id']
result['msg'] = 'Realm %s has been deleted.' % before_realm['realm']
module.exit_json(**result)

View File

@@ -101,6 +101,9 @@ options:
groups:
description:
- List of groups for the user.
Groups can be referenced by their name, like V(staff), or their path, like V(/staff/engineering).
The path syntax allows you to reference subgroups, which is not possible otherwise.
This is possible since community.general 10.6.0.
type: list
elements: dict
default: []

View File

@@ -22,7 +22,12 @@ attributes:
support: none
diff_mode:
support: none
options: {}
options:
multivalues:
description: If lldpctl outputs an attribute multiple time represent all values as a list.
required: false
type: bool
default: false
author: "Andy Hill (@andyhky)"
notes:
- Requires C(lldpd) running and LLDP enabled on switches.
@@ -53,26 +58,49 @@ def gather_lldp(module):
if output:
output_dict = {}
current_dict = {}
lldp_entries = output.split("\n")
lldp_entries = output.strip().split("\n")
final = ""
for entry in lldp_entries:
if entry.startswith('lldp'):
path, value = entry.strip().split("=", 1)
path = path.split(".")
path_components, final = path[:-1], path[-1]
elif final in current_dict and isinstance(current_dict[final], str):
current_dict[final] += '\n' + entry
continue
elif final in current_dict and isinstance(current_dict[final], list):
current_dict[final][-1] += '\n' + entry
continue
else:
value = current_dict[final] + '\n' + entry
continue
current_dict = output_dict
for path_component in path_components:
current_dict[path_component] = current_dict.get(path_component, {})
if not isinstance(current_dict[path_component], dict):
current_dict[path_component] = {'value': current_dict[path_component]}
current_dict = current_dict[path_component]
current_dict[final] = value
if final in current_dict and isinstance(current_dict[final], dict) and module.params['multivalues']:
current_dict = current_dict[final]
final = 'value'
if final not in current_dict or not module.params['multivalues']:
current_dict[final] = value
elif isinstance(current_dict[final], str):
current_dict[final] = [current_dict[final], value]
elif isinstance(current_dict[final], list):
current_dict[final].append(value)
return output_dict
def main():
module = AnsibleModule({})
module_args = dict(
multivalues=dict(type='bool', required=False, default=False)
)
module = AnsibleModule(module_args)
lldp_output = gather_lldp(module)
try:

View File

@@ -34,6 +34,7 @@ options:
- List of comma-separated devices to use as physical devices in this volume group.
- Required when creating or resizing volume group.
- The module will take care of running pvcreate if needed.
- O(remove_extra_pvs) controls whether or not unspecified physical devices are removed from the volume group.
type: list
elements: str
pesize:
@@ -88,6 +89,12 @@ options:
type: bool
default: false
version_added: 7.1.0
remove_extra_pvs:
description:
- Remove physical volumes from the volume group which are not in O(pvs).
type: bool
default: true
version_added: 10.4.0
seealso:
- module: community.general.filesystem
- module: community.general.lvol
@@ -383,6 +390,7 @@ def main():
force=dict(type='bool', default=False),
reset_vg_uuid=dict(type='bool', default=False),
reset_pv_uuid=dict(type='bool', default=False),
remove_extra_pvs=dict(type="bool", default=True),
),
required_if=[
['reset_pv_uuid', True, ['pvs']],
@@ -399,6 +407,7 @@ def main():
vgoptions = module.params['vg_options'].split()
reset_vg_uuid = module.boolean(module.params['reset_vg_uuid'])
reset_pv_uuid = module.boolean(module.params['reset_pv_uuid'])
remove_extra_pvs = module.boolean(module.params["remove_extra_pvs"])
this_vg = find_vg(module=module, vg=vg)
present_state = state in ['present', 'active', 'inactive']
@@ -494,6 +503,9 @@ def main():
devs_to_remove = list(set(current_devs) - set(dev_list))
devs_to_add = list(set(dev_list) - set(current_devs))
if not remove_extra_pvs:
devs_to_remove = []
if current_devs:
if present_state:
for device in current_devs:

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