Compare commits

..

165 Commits
4.2.0 ... 4.7.0

Author SHA1 Message Date
Felix Fontein
22b72e6684 Release 4.7.0. 2022-04-05 14:02:29 +02:00
patchback[bot]
8e7bee4217 Fix small typo (#4452) (#4454)
(cherry picked from commit 380de2d0c1)

Co-authored-by: Wouter Schoot <wouter@schoot.org>
2022-04-05 14:00:35 +02:00
patchback[bot]
cef6b81e5b Bug fix: Warns user if incorrect SDK version is installed (#4422) (#4450)
* Add error handling to check correct SDK version installed

* Fix CI errors

* Added changelog fragment

* Changed exeption type

* Update changelogs fragment

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

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

Co-authored-by: Ricky White <rickywhite@outlook.com>
2022-04-05 07:49:30 +02:00
patchback[bot]
182c365d87 nmcli: suggest new routes4 and routes6 format (#4328) (#4447)
* suggest new routes4 and routes6 format

* make new options instead of modifying exiting one

* fix docs and some small errors

* fixing docs

(cherry picked from commit feb0fffd58)

Co-authored-by: Alex Groshev <38885591+haddystuff@users.noreply.github.com>
2022-04-05 07:12:38 +02:00
patchback[bot]
587cdc82e7 Keycloak client, Add always_display_in_console option (#4429) (#4448)
* Keycloak client, Add always_display_in_console option

* Add 4429-keycloak-client-add-always-display-in-console.yml fragment.

* Update changelogs/fragments/4429-keycloak-client-add-always-display-in-console.yml

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

* Update plugins/modules/identity/keycloak/keycloak_client.py

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

* Update plugins/modules/identity/keycloak/keycloak_client.py

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

Co-authored-by: Michal Vasko <mvasko@cloudwerkstatt.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 79256b2bd2)

Co-authored-by: whoamiUNIX <40315055+whoamiUNIX@users.noreply.github.com>
2022-04-05 07:09:20 +02:00
Felix Fontein
cb1a50a273 Prepare 4.7.0 release. 2022-04-05 07:05:07 +02:00
patchback[bot]
f0df50e665 Bugfix: zypper issue with specified package versions (#4421) (#4446)
* fixed issue with specified package versions

zypper.py was doing nothing on state=present, when ALL requestet/checked packages had a specific version stated. This was caused by get_installed_state() being called with an empty package list, which in this case returns information about all ALL installed packages. This lead to an exessive filter list prerun_state, essentially removing all packages that are installed in ANY version on the target system from the request list.

* Create 4421-zypper_package_version_handling_fix

added changelog fragment for https://github.com/ansible-collections/community.general/pull/4421

* Delete 4421-zypper_package_version_handling_fix

* Create 4421-zypper_package_version_handling_fix.yml

(cherry picked from commit bbe231e261)

Co-authored-by: tover99 <101673769+tover99@users.noreply.github.com>
2022-04-05 06:28:15 +02:00
patchback[bot]
47aa93d970 cronvar: ensure creation of /etc/cron.d in test (#4440) (#4444)
* ensure creation of /etc/cron.d in test

* fixed typo

(cherry picked from commit 9e0ff8ba4b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-04-03 10:54:44 +02:00
patchback[bot]
e89648a114 Remove OpenSuSE Python 2 from devel CI. (#4442) (#4443)
(cherry picked from commit bd83490b45)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-04-02 18:31:40 +02:00
patchback[bot]
6f1bdb3e49 pids: re-enabled tests on Alpine Linux (#4405) (#4439)
* [WIP] pids: re-enabled tests on Alpine Linux

* trying to compile a simple-faked sleep command

* make FreeBSD happy

* remove the block testing for Alpine Linux

* simpler version of sleeper.c

* simpler version of sleeper.c, part II

* Update tests/integration/targets/pids/tasks/main.yml

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

* Update tests/integration/targets/pids/tasks/main.yml

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

* added license to sleeper.c file

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-04-02 08:45:53 +02:00
patchback[bot]
fbf11668f4 CI: Remove 'warn:' that's removed in ansible-core 2.14 (#4434) (#4437)
* Remove 'warn:' that's removed in ansible-core 2.14.

* Install virtualenv when needed.

(cherry picked from commit 24ca69aa05)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-04-01 23:11:39 +02:00
patchback[bot]
3376442aa2 Proxmox Inventory: Add support for templating in inventory file (#4418) (#4435)
* added templating to the url, user, and password

* added changelog fragment

* typo in description for url, and password

* clarify in the changelog what can you change

* update documentation and added an example

* missing quote from examples

* Apply suggestions from code review

Changed to I for option names

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

* Update plugins/inventory/proxmox.py

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

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

Co-authored-by: Ilija Matoski <ilijamt@gmail.com>
2022-04-01 23:07:42 +02:00
patchback[bot]
868edfa664 ipa_service: Add skip_host_check option (#4417) (#4436)
* ipa_service: Add `skip_host_check` option

* Update plugins/modules/identity/ipa/ipa_service.py

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

* Update plugins/modules/identity/ipa/ipa_service.py

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

* Update plugins/modules/identity/ipa/ipa_service.py

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

* changelogs/fragments: Add 4417-ipa_service-add-skip_host_check.yml

Co-authored-by: sodd <4178855+sodd@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1b357bade7)

Co-authored-by: sodd <sodd@users.noreply.github.com>
2022-04-01 23:07:23 +02:00
patchback[bot]
2fcb77f7fb Replace antsibull-lint collection-docs with antsibull-docs lint-collection-docs. (#4423) (#4426)
(cherry picked from commit 668bbed602)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-30 08:17:38 +02:00
patchback[bot]
17135dd082 Add stable-2.13 to CI, thin out older version matrix (#4413) (#4414)
* Add stable-2.13 to CI, thin out older version matrix.

* Thin out matrix more.

* And a bit more.

(cherry picked from commit caedcc3075)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-29 07:52:32 +02:00
patchback[bot]
7516018cfb keycloak: add missing validate_certs parameters for open_url calls (#4382) (#4410)
* fix: missing `validate_certs` parameters for `open_url` calls

As stated in the documentation, the `validate_certs` parameter can be
used to verify (or not) the TLS certificates. But, for some modules (at
least for the `keycloak_authentication` module), this parameter is not
used with the `open_url` function.

* add changelog fragment

* Update changelogs/fragments/4382-keycloak-add-missing-validate_certs-parameters.yml

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

Co-authored-by: Laurent Meunier <lme@atolcd.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 34420e143e)

Co-authored-by: Laurent Meunier <laurent@deltalima.net>
2022-03-28 22:25:14 +02:00
patchback[bot]
58df1df107 keycloak_client: add default_client_scopes and optional_client_scopes (#4385) (#4409)
* keycloak_client: add default_client_scopes and optional_client_scopes

* Changelog fragment for #4385

* Update changelogs/fragments/4385-keycloak-client-default-optional-scopes.yml

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

* Update plugins/modules/identity/keycloak/keycloak_client.py

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

* Update plugins/modules/identity/keycloak/keycloak_client.py

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

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

Co-authored-by: Alex Lubbock <alex@lubbock.uk>
2022-03-28 22:25:00 +02:00
patchback[bot]
e9b3705809 feat: sudoers module supports runas parameter with default of root (#4380) (#4399)
* feat: sudoers module supports runas parameter with default of root

* fix: sudoers tests now pass

* chore: add changelog fragment for 4380

* fix: runas feature now a non-breaking change wh no def with no default

* fix: no trailing space in sudoers.py

* Update plugins/modules/system/sudoers.py

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

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

Co-authored-by: doubletwist13 <doubletwist@fearthepenguin.net>
2022-03-24 06:44:48 +00:00
patchback[bot]
743e9c851f ldap: added documentation as requested (#4389) (#4398)
* added documentation as requested

* Update plugins/doc_fragments/ldap.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-03-24 06:44:30 +00:00
patchback[bot]
a7883ee489 Fixed typo in keycloak_client_rolemapping examples (#4393) (#4401)
* Fixed typo in keycloak_client_rolemapping examples

* Add a changelog fragment.

* Removed changelogs fragment for docs-only change.

Co-authored-by: shnee <shnee@shnee.net>
(cherry picked from commit cb30eb2d30)

Co-authored-by: shnee <CurtyD13@gmail.com>
2022-03-24 06:44:18 +00:00
patchback[bot]
518af70b77 Proxmox inventory plugin - Fix tags parsing (#4378) (#4402)
* Proxmox inventory plugin - Fix tags parsing

  * In some cases the Proxmox API returns a tags string that consists in
    a single space. The Proxmox inventory plugin parsed that into a
    single, empty tag. Stripping the initial string then checking
    whether it actually contains something fixes that.
  * Do not call `_to_safe` on the concatenation of a known safe string
    and a string that was already made safe.

* Changelog fragment for Proxmox inventory plugin tags fix

* Proxmox inventory plugin - Include link to PR in fragment

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

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

Co-authored-by: Emmanuel Benoît <tseeker@nocternity.net>
2022-03-24 06:44:02 +00:00
patchback[bot]
ce7d98aa6f Add collection links file. (#4384) (#4386)
(cherry picked from commit eb4495b716)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-22 07:21:28 +01:00
Felix Fontein
9f91f4b5cd Next expected release is 4.7.0. 2022-03-16 19:12:20 +01:00
Felix Fontein
c45c38f04b Release 4.6.1. 2022-03-16 18:20:34 +01:00
patchback[bot]
f7efb2e394 plugins/inventory/lxd.py: fix listing of containers without os / release (#4351) (#4372)
* plugins/inventory/lxd.py: fix listing of containers without os / release

In some cases, a container might be present, that was initialized empty, therefore lacking meta information about the os or the release.
Test if the data entry is None to avoid calling lower on it.

* Update plugins/inventory/lxd.py

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

* Update plugins/inventory/lxd.py

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

* Create 4351-inventory-lxd-handling_metadata_wo_os_and_release.yml

* fix yaml readability of changelog fragment

* Update changelogs/fragments/4351-inventory-lxd-handling_metadata_wo_os_and_release.yml

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

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Malte Kuhn <mkuhn@maxcluster.de>
(cherry picked from commit 421ccd5dc9)

Co-authored-by: monkz <git@monkz.de>
2022-03-16 18:19:44 +01:00
Felix Fontein
093b83c34f [stable-4] Revert "Allow complex values in variables parameter of terraform module (#4281)" (#4370)
* Revert "Allow complex values in variables parameter of terraform module (#4281)" (#4368)

This reverts commit 4cc7f41395.

(cherry picked from commit 9618fb9786)

* Add changelog fragment.
2022-03-16 07:24:38 +01:00
Felix Fontein
579fdbbc1c Prepare 4.6.1 release. 2022-03-16 07:24:24 +01:00
Felix Fontein
c970c14c71 The next expected release is 4.7.0. 2022-03-15 13:36:57 +01:00
Felix Fontein
24f6493cd4 Release 4.6.0. 2022-03-15 12:36:20 +01:00
patchback[bot]
68364df409 Proxmox inventory plugin - Fix string to dict conversion (#4349) (#4366)
* Proxmox inventory plugin - Fix string to dict conversion (#4348)

  * Re-use the (defined but unused) `plaintext_configs` variable to list
    configuration entries that should be ignored by the string to
    dictionary conversion code. At this point, it only contains the
    `description` string.
  * Convert to a dictionary if the all substrings obtained by splitting
    off the initial value with commas contain a `=` character
  * Limit substring splitting to a single split, so that a substring
    containing `a=b=c` will generate an `a` entry with value `b=c`.

* Added changelog fragment for PR #4349

* Fix changelog fragment for #4349

(cherry picked from commit 3eec63421a)

Co-authored-by: Emmanuel Benoît <tseeker@nocternity.net>
2022-03-15 12:34:44 +01:00
patchback[bot]
fb61da5246 Proxmox inventory filters (#4352) (#4364)
* Proxmox inventory plugin - Initial implementation of filters

  * This is an attempt at implementing something that would satisfy
    issue #3553
  * A rather massive code rewrite was needed as adding the host to the
    inventory, setting its variables and adding it to various groups
    used to be done as soon as the information became available. This is
    not possible when it is not known whether the host should be added
    to the inventory before all data has been gathered.
  * The code for both LXC containers and Qemu VMs was refactored into a
    single loop.
  * Helper functions to generate group and fact names were added.

* Proxmox inventory plugin - Warnings for filter errors

  * When an error occurs while compositing a filter's value and strict
    mode is disabled, display a warning.

* Proxmox inventory plugin - Fixed pool groups building

  * Hosts that were excluded by the host filters were still being added
    to pool groups, causing errors.

* Proxmox inventory plugin - Refactoring

  * Split off the VM/container handling code from the
    `_populate()` method
  * Split off pool group attribution from the `_populate()` method

* Proxmox inventory filters - Changelog fragment

* proxmox inventory - Simplify _can_add_host() method

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

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

Co-authored-by: Emmanuel Benoît <tseeker@nocternity.net>
2022-03-15 12:34:24 +01:00
patchback[bot]
cf9b01ec6b Add description on keeping old behavior and already switching to new behavior. (#4361) (#4363)
(cherry picked from commit 85925eabea)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-15 12:19:10 +01:00
patchback[bot]
89663a0688 ldap_entry - Recursive deletion (#4355) (#4360)
* ldap_entry - Recursive deletion

  * Recursive deletion can be enabled with the `recursive` option. It is
    disabled by default.
  * When enabled, deletion is attempted by sending a single delete
    request with the Subtree Delete control. If that request fails with
    the `NOT_ALLOWED_ON_NONLEAF` error, try deleting the whole branch in
    reverse order using individual delete requests.

* ldap_entry recursive deletion - Changelog fragment

* ldap_entry - Refactored to avoid lint message

* Update changelogs/fragments/4355-ldap-recursive-delete.yml

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

* ldap_entry - Add version_added to the recursive flag

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

* ldap_entry - Moved member assignment to a more suitable location

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

Co-authored-by: Emmanuel Benoît <tseeker@nocternity.net>
2022-03-15 06:05:07 +01:00
patchback[bot]
7fcb21e044 pacman: implement change detection for update_cache=true; add cache_updated return value (#4337) (#4359)
* Implement change detection for update_cache=true. Add cache_updated return value.

* ...

* Make sure pacman --sync --list is called only as often as necessary.

(cherry picked from commit cf4d68ac50)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-15 06:04:58 +01:00
patchback[bot]
1bf9caa90f Fix sanity issues. (#4346) (#4357)
(cherry picked from commit ca2c64b5ca)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-14 21:30:29 +01:00
Felix Fontein
c6ecc0f3f8 Prepare 4.6.0 release. 2022-03-14 21:19:53 +01:00
patchback[bot]
4d74aa05a8 Fix linode inventory filtering (#4336) (#4356)
* Fix linode inventory filtering

There was a regression introduced in the addition of caching. The
`_consume_options` method was added and provided the `config_data`
dictionary. This `pop`s every entry, resulting in an empty `config_data`
dict, which was then reused and expected to be populated.

After reviewing, `_consume_data` doesn't need to be called. Also, once
the ``_read_config_data` method has been called, we no longer need the
config_data dict, and can instead use the `get_option` method throughout.

Once those were removed, the filtering function seemed a bit odd, since
we were no longer using the file. I used that opportunity to move the
filter calls into the populate function directly.

* Remove tests that target removed methods

This removes tests that targeted some custom methods on configuration
file handling. These are no longer necessary since they are now handled
by the BaseInventoryPlugin `_read_config_data` method.

* Add changelog entry for linode inventory bugfix

* Revert filters back to their own method

This moves filters back into their own method, but now uses the
get_option calls to pull filter configuration items.

(cherry picked from commit 386bb4bdd5)

Co-authored-by: steven jacobs <stjacobs@fastmail.fm>
2022-03-14 20:56:13 +01:00
patchback[bot]
7fb44b0643 datadog: Add missing priority (#4311) (#4354)
* datadog: Add missing priority

* datadog: Add missing priority

* datadog: Add missing priority

* datadog: Add documentation and variable declaration

* datadog: Add documentation and variable declaration

* datadog: Add documentation and variable declaration

* Update plugins/modules/monitoring/datadog/datadog_monitor.py

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

Co-authored-by: Fredrik Lysén <fredrik.lysen@klarna.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c40684db58)

Co-authored-by: Fredrik Lysén <flysen@users.noreply.github.com>
2022-03-14 07:29:18 +01:00
patchback[bot]
7ddb2eb438 mksysb - revamped module + fix bug in backup_dmapi_fs option (#3295) (#4353)
* Revamped module + fix bug in backup_dmapi_fs option

* added changelog fragment

* added copyright line

(cherry picked from commit 4af7f49ac0)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-03-14 07:29:08 +01:00
patchback[bot]
3158495572 jira: Use fields in comment to merge in additional data (#4304) (#4347)
* jira: Use fields in comment to merge in additional data

* changlog fragment added

* Update changelogs/fragments/4304-jira-fields-in-comment.yml

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

* updated fields documentation

* Update plugins/modules/web_infrastructure/jira.py

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

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

Co-authored-by: Boosai <51994151+Boosai@users.noreply.github.com>
2022-03-12 08:29:28 +01:00
patchback[bot]
58f110ae9c Update doc. tss.py (env REQUESTS_CA_BUNDLE) (#4338) (#4345)
* Update doc. tss.py (env REQUESTS_CA_BUNDLE)

Add a reference to environment variable REQUESTS_CA_BUNDLE to enable using self signed certificates (on-prem server) in documentation.

* Update tss.py

Remove trailing blank

* Update plugins/lookup/tss.py

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

* Update plugins/lookup/tss.py

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

* Update plugins/lookup/tss.py

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

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

Co-authored-by: Josef Fuchs <josef.fuchs@j-fuchs.at>
2022-03-11 07:20:46 +01:00
patchback[bot]
5695c919f1 Add tls parameter to redis module (#4207) (#4343)
* Add tls parameter to redis module

* Rename changelog fragment to match PR

* Apply suggestions from code review

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

* Port redis module to redis auth module util

* Update changelogs/fragments/4207-add-redis-tls-support.yml

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

* Update plugins/modules/database/misc/redis.py

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

* Undo reuse of redis auth doc fragment

* Use doc fragment.

Co-authored-by: Julian Faude <julian.faude@zweiacht.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 9a74ace1e4)

Co-authored-by: jcharlytown <github@julianfau.de>
2022-03-11 06:15:51 +00:00
patchback[bot]
6e1a1c028e pacman: improve docs, make sure that packages is always returned, deprecate update_cache behavior (#4330) (#4342)
* Improve docs, make sure that packages is always returned, deprecate update_cache behavior.

* Add cache_updated return value.

* Revert "Add cache_updated return value."

This reverts commit 367297bb5c.

* Update tests/unit/plugins/modules/packaging/os/test_pacman.py

Co-authored-by: Jean Raby <jean@raby.sh>

Co-authored-by: Jean Raby <jean@raby.sh>
(cherry picked from commit 10ca62905f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-03-11 06:15:41 +00:00
patchback[bot]
d02b8507d1 Allow complex values in variables parameter of terraform module (#4281) (#4341)
* Allow complex values in variables parameter

Signed-off-by: Webster Mudge <wmudge@gmail.com>

* Add changelog fragment

Signed-off-by: Webster Mudge <wmudge@gmail.com>

* Update changelogs fragments formatting

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

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

Co-authored-by: Webster Mudge <wmudge@cloudera.com>
2022-03-11 06:56:07 +01:00
patchback[bot]
14d43b10c1 npm: add support for production flag when using ci (#4299) (#4339)
* npm - add  '--production` support to 'npm ci' flag

* add changelog fragement for 4299

* Add backticks

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

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

Co-authored-by: Daniel Miller <watermelonpizza@melonstudios.net>
2022-03-11 06:55:54 +01:00
patchback[bot]
92c41a5f55 BOTMETA.yml: add new maintainer to gitlab team (#3695) (#4332)
(cherry picked from commit 56e8bf130a)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-03-08 08:34:36 +01:00
patchback[bot]
012f684133 pacman: add support for remove_nosave (#4316) (#4329)
* pacman: add support for remove_nosave

New parameter: remove_nosave
When enabled, will pass --nosave to pacman when removing packages.
--nosave cannot be used with --print-format and thus it couldn't be
passed via extra_args. See #4315

The code adds the option right before the actual removal of the pkgs.

(This is based on an initial diff from MorphBonehunter)

* changelog

* Update plugins/modules/packaging/os/pacman.py

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

* wording

* ssss

* remove_package: simplify {force,extra,nosave}_args

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

Co-authored-by: Jean Raby <jean@raby.sh>
2022-03-08 07:39:31 +01:00
patchback[bot]
77b7a65002 proxmox: Fix error on VM clone (#4278) (#4306) (#4326)
* proxmox: Fix error on VM clone (#4278)

Incorrect parameters for `get_vmid()` and `get_vm()` caused failures when
cloning VMs.

Fixes #4278

* Update changelogs/fragments/4306-proxmox-fix-error-on-vm-clone.yml

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

Co-authored-by: Davíð Steinn Geirsson <david@isnic.is>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c0f53d60c4)

Co-authored-by: Davíð Steinn Geirsson <david@dsg.is>
2022-03-07 08:49:01 +00:00
patchback[bot]
7f4cd86fe5 Remove DWSR from BOTMETA.yml (#4323) (#4325)
* Remove DWSR from BOTMETA.yml

I'm no longer using Ansible.

* Update .github/BOTMETA.yml

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

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

Co-authored-by: Brandon McNama <brandonmcnama@outlook.com>
2022-03-07 07:17:27 +01:00
patchback[bot]
06980d8239 pacman: don't always return changed w/ update_cache (#4318) (#4322)
* pacman: don't always return changed w/ update_cache

This used to be the behavior before the recent refactoring. [1]

Allows the following to return changed only when packages were upgraded:

  - pacman:
    update_cache: yes
    upgrade: yes

And the following to return changed only when the foo package wasn't at
the latest version:

  - pacman:
    name: foo
    state: latest
    update_cache: yes

[1] https://github.com/ansible-collections/community.general/pull/3907

* Update changelogs/fragments/4318-pacman-restore-old-changed-behavior.yml

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

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

Co-authored-by: Evangelos Foutras <evangelos@foutrelis.com>
2022-03-06 22:57:22 +01:00
patchback[bot]
d4740ff387 Remove nmcli modify dependency on type parameter (#4108) (#4320)
* Remove nmcli modify dependency on type parameter

* Add fragment

* Add newline for lint

* Fixed linting for tests

* Fix fragment

* Move aliases to ip_conn_type function

* Remove connection_map

* Updated fragment

* Fixed fragment

Co-authored-by: Trey West <--local>
(cherry picked from commit 1ca7894d30)

Co-authored-by: Trey West <treywest45th@gmail.com>
2022-03-06 09:26:37 +01:00
patchback[bot]
a0b22e4402 pacman: user --groups instead of --group (#4312) (#4317)
* s/group/groups/

Pacman accepts --group but the actual option name is --groups.
Allows use of other binaries with the same CLI interface as pacman (yay)

* changelog

* Apply suggestions from code review

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

* Add note regarding pacman compat + --print-format

* Update plugins/modules/packaging/os/pacman.py

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

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

Co-authored-by: Jean Raby <jean@raby.sh>
2022-03-04 18:39:20 +00:00
patchback[bot]
a56879c1b0 Fix error when checking if Proxmox VM exists. (#4287) (#4313)
* Fix error when checking if VM exists.

* Add changelog entry.

* Reword changelog entry.

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

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

Co-authored-by: Markus Reiter <me@reitermark.us>
2022-03-04 13:30:57 +01:00
patchback[bot]
d7b31655c4 [plugins/callback/syslog_json.py] use v2 api, add option to skip sysl… (#4223) (#4310)
* [plugins/callback/syslog_json.py] use v2 api, add option to skip syslog on gather_facts

* Update plugins/callback/syslog_json.py

Add version

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

* Update plugins/callback/syslog_json.py

consistency for description

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

* Update plugins/callback/syslog_json.py

ANSIBLE_ environment variable prefix

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

* add changelog fragment for PR 4223

* Update changelogs/fragments/4223-syslog-json-skip-syslog-option.yml

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

Co-authored-by: andrewroffey <36812998+andrewroffey@users.noreply.github.com>
2022-03-03 07:58:00 +01:00
patchback[bot]
70a7f66d4c pipx: added options editable and pip_args (#4303) (#4309)
* pipx: added options editable and pip_args

* added changelog fragment

* added version markers on new options

(cherry picked from commit f988eb5726)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-03-02 22:47:37 +01:00
patchback[bot]
391c3aa850 pacman: re-adding support for URL based pkgs (#4286) (#4302)
* pacman: re-adding support for URL based pkgs

* Update plugins/modules/packaging/os/pacman.py

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

* Update plugins/modules/packaging/os/pacman.py

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

* cmd=cmd in every call to self.fail()

* pacman: integration test for mixed pkg sources

* Add more tests + fix minor bug with URL packages

Version checking for URL packages is left to pacman, so add a check
after the dry run to see if it would actually install anything.

* remove double templating

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

Co-authored-by: Jean Raby <jean@raby.sh>
2022-03-01 06:34:27 +01:00
patchback[bot]
deb95ea6bf zypper: support automatic removal of orphaned dependencies (#4195) (#4301)
* zypper: support automatic removal of orphaned dependencies

* zypper: support automatic removal of orphaned dependencies

  - Add support for --clean-deps option during package removal, which
    will clean up packages that were only installed as dependencies
    of the package being removed.

* Update changelogs/fragments/4192-zypper-add-clean-deps.yml

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

* Update plugins/modules/packaging/os/zypper.py

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

* Update plugins/modules/packaging/os/zypper.py

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

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

Co-authored-by: Jeff Mahoney <jeffm@jeffm.io>
2022-02-28 19:54:58 +01:00
patchback[bot]
806ca0a9e0 Improve ArchLinux tests (#4291) (#4295)
* Make sure that every test that uses package: requires setup_pkg_mgr.

* Upgrade system packages for Arch Linux.

* Re-enable java keytool tests on Arch.

(cherry picked from commit 274b8cceef)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-27 15:50:15 +01:00
patchback[bot]
a171d9bb90 Make timezone tests work on Alpine. (#4292) (#4296)
(cherry picked from commit 14ef334754)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-27 15:50:06 +01:00
patchback[bot]
dd70c8b031 filesize: fix alpine linux sparse file (#4288) (#4294)
* fix sparse file creation on Alpine linux

* re-enable tests for Alpine
* remove `conv=sparse` flag (rely only on `seek=fullsize` & `count=0`)
* doc: add a reference to busybox's dd
* doc: remove restrictions for OpenBSD, Solaris & AIX (should work as
  for Alpine linux now)
* add a changelog fragment

* fix typo

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

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

Co-authored-by: quidame <quidame@poivron.org>
2022-02-27 13:55:50 +01:00
patchback[bot]
30e707aa79 Add very basic integration tests for pcaman. (#4289) (#4290)
(cherry picked from commit be433d762b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-27 13:21:16 +01:00
patchback[bot]
7be95c8bbe Temporarily disable Java keytool installation on Archlinux (#4283) (#4284)
* Temporarily disable Java keytool installation on Archlinux.

* Fix comment.

(cherry picked from commit 0d0e695d8f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-24 23:22:14 +01:00
patchback[bot]
8e9a348e92 pacman: fix upgrade: yes (#4275) (#4277)
* s/sys-upgrade/sysupgrade/

* changelog fragment

* yamllint

* more fragment tweaks

(cherry picked from commit b9f62bb4ef)

Co-authored-by: Jean Raby <jean@raby.sh>
2022-02-23 18:01:06 +01:00
patchback[bot]
2622513d65 Re-enable ansible_galaxy_install tests. (#4253) (#4255)
(cherry picked from commit 2b0b780ccb)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-22 23:16:28 +01:00
Felix Fontein
37d37b20cb Next expected release is 4.6.0. 2022-02-22 14:37:01 +01:00
Felix Fontein
631d555f8a Release 4.5.0. 2022-02-22 13:56:04 +01:00
patchback[bot]
c4a53243d5 Fixes for keycloak_user_federation (#4212) (#4252)
* keycloak: fix creating a user federation w/ idempotent id

Creating a user federation while specifying an id (that doesn't exist
yet) will fail with a 404. This commits fix this behavior.

* keycloak: fix user federation mapper duplication

This commit fixes a bug where mappers are duplicated instead of
configured when creating a user federation.

When creating a user federation, some mappers are autogenerated by
keycloak. This commit lets the keycloak_user_federation module recompute
mappers final values after the user federation is created so that the
module can try to merge them by their name.

* add missing fragment for pr #4212

(cherry picked from commit c1485b885d)

Co-authored-by: Jules Lamur <jlamur@users.noreply.github.com>
2022-02-22 10:08:53 +01:00
patchback[bot]
c0008e976f CI: Add ArchLinux, Debian Bullseye, CentOS Stream 8, and Alpine 3 (#4222) (#4244)
* Add ArchLinux, Debian Bullseye and CentOS Stream 8 to CI.

* Add Alpine to CI matrix as well.

(cherry picked from commit a06903f33a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-22 09:08:35 +00:00
patchback[bot]
f60c90873f Temporarily disable ansible_galaxy_install tests due to Galaxy failures. (#4247) (#4250)
(cherry picked from commit 06705348e3)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-22 09:39:53 +01:00
patchback[bot]
c08a57a7c1 ansible_galaxy_install: added no_deps option (#4240) (#4246)
* ansible_galaxy_install: added no_deps option

* added changelog fragment

* Update plugins/modules/packaging/language/ansible_galaxy_install.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2022-02-22 09:21:02 +01:00
patchback[bot]
3d2caf3933 passwordstore: Add configurable locking (#4194) (#4243)
* passwordstore: Add configurable locking

Passwordstore cannot be accessed safely in parallel, which causes
various issues:

- When accessing the same path, multiple different secrets are
  returned when the secret didn't exist (missing=create).
- When accessing the same _or different_ paths, multiple pinentry
  dialogs will be spawned by gpg-agent sequentially, having to enter
  the password for the same gpg key multiple times in a row.
- Due to issues in gpg dependencies, accessing gpg-agent in parallel
  is not reliable, causing plays to fail (this can be fixed by adding
  `auto-expand-secmem` to _~/.gnupg/gpg-agent.conf_ though).

These problems have been described in various github issues in the past,
e.g., ansible/ansible#23816 and ansible/ansible#27277.

This cannot be worked around in playbooks by users in a non-error-prone
way.

It is addressed by adding new configuration options:

- lock:
  - readwrite: Lock all operations
  - write: Only lock write operations (default)
  - none: Disable locking
- locktimeout: Time to wait for getting a lock (s/m/h suffix)
  (defaults to 15m)

These options can also be set in ansible.cfg, e.g.:

    [passwordstore_lookup]
    lock=readwrite
    locktimeout=30s

Also, add a note about modifying gpg-agent.conf.

* Tidy up locking config

There is no reason why lock configuration should be part of self.paramvals.
Now locking and its configuration happen all in one place.

* Change timeout description wording to the suggested value.

* Rearrange plugin setup, apply PR feedback

(cherry picked from commit 2416b81aa4)

Co-authored-by: grembo <freebsd@grem.de>
2022-02-21 21:37:47 +01:00
patchback[bot]
df6a00dc89 pmem: Add namespace and namespace_append options (#4225) (#4239)
* pmem: Add namespace and namespace_append options

- namespace: Configure the namespace of PMem. PMem should be configured
  by appdirect/memmode, or socket option in advance.
- namespace_append: Enables to append the new namespaces.

* Add changelog fragment entry

* Update the changelog fragment

* Update changelog fragment entry

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

* Update to use human_to_bytes

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

* Update to fix the description of namespace_append

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

* Update to release v4.5.0

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

* Update to fix the typo in the description of namespace_append

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

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

Co-authored-by: mizumm <26898888+mizumm@users.noreply.github.com>
2022-02-20 22:20:02 +01:00
patchback[bot]
bdddc50358 Fix module failure due to itertools.izip_longest (#4211) (#4238)
* Fix module failure due to itertools.izip_longest

* Add changelog fragment. Remove itertools import

* Update changelogs/fragments/4206-imc-rest-module.yaml

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

Co-authored-by: Boris Vasilev <bvasilev@vmware.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 40f9445aea)

Co-authored-by: Boris <borisvasilev395@gmail.com>
2022-02-20 09:53:42 +01:00
Felix Fontein
8a01ad200d Prepare 4.5.0 release. 2022-02-19 23:32:28 +01:00
patchback[bot]
b6ccac372c Fix some more instances of ansible.module_utils._text. (#4232) (#4233)
(cherry picked from commit a262a30122)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-19 08:21:01 +01:00
patchback[bot]
3b1b7966ca feat: support cache in Linode inventory (#4179) (#4234)
(cherry picked from commit f6e0693e86)

Co-authored-by: Will Hegedus <whegedus@linode.com>
2022-02-18 23:33:44 +01:00
patchback[bot]
1f522c414e [PR #4183/f5ec7373 backport][stable-4] yum_versionlock: Fix entry matching (#4228)
* yum_versionlock: Fix entry matching (#4183)

As an input the module receives names of packages to lock.
Those never matched existing entries and therefore always reported
changes.

For compatibility yum is symlinked to dnf on newer systems,
but versionlock entries defer. Try to parse both formats.

Signed-off-by: Florian Achleitner <flo@fopen.at>
(cherry picked from commit f5ec73735f)

* Empty commit to trigger CI.

Co-authored-by: fachleitner <flo@fopen.at>
Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-18 23:19:39 +01:00
patchback[bot]
cf60761cf9 mail: fix the encoding of the mail senders and recipients name (#4061) (#4229)
(cherry picked from commit 8682ac96df)

Co-authored-by: Lénaïc Huard <L3n41c@users.noreply.github.com>
2022-02-18 22:59:04 +01:00
patchback[bot]
4b28b036c9 Drop CentOS 8 from CI. (#4139) (#4231)
(cherry picked from commit b444dc81a1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-18 22:31:25 +01:00
patchback[bot]
ec7c39351d Rework of gitlab_project_variable over gitlab_group_variable (#4086) (#4226)
* Rework of gitlab_project_variable over gitlab_group_variable

* Linting and removed unused example

* Fix test 2

* Sync from review of gitlab_project_variable #4038

* Linting, default protected True, value optional

* Next version is 4.5.0

* Roll back protected default true, and value not required

* Apply suggestions from code review

Missing check_mode

Co-authored-by: Markus Bergholz <git@osuv.de>

* Fix one unit test, comment test that requires premium gitlab

* Add changelog

* Update plugins/modules/source_control/gitlab/gitlab_group_variable.py

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

* Update changelogs/fragments/4086-rework_of_gitlab_proyect_variable_over_gitlab_group_variable.yml

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

* Added conditional gitlab_premium_tests variable when required

* Allow delete without value

* Fix variable name

* Linting

* Value should not be required in doc

* Linting missing new-line

* Update changelogs/fragments/4086-rework_of_gitlab_proyect_variable_over_gitlab_group_variable.yml

Co-authored-by: Markus Bergholz <git@osuv.de>

Co-authored-by: Markus Bergholz <git@osuv.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 44f9bf545d)

Co-authored-by: Sebastian Guarino <sebastian.guarino@gmail.com>
2022-02-18 20:52:36 +00:00
patchback[bot]
b3963fd3c7 passwordstore: Fix error detection for non-English locales (#4219) (#4221)
The passwordstore lookup plugin depends on parsing GnuPG's
error messages in English language. As a result, detection of
a specific error failes when users set a different locale.

This change corrects this by setting the `LANGUAGE` environment
variable to `C` when invoking `pass`, as this only affects
gettext translations.

See
https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html

(cherry picked from commit 77a0c139c9)

Co-authored-by: grembo <freebsd@grem.de>
2022-02-17 22:21:12 +01:00
patchback[bot]
271bafb637 passwordstore: Prevent using path as password (#4192) (#4218)
Given a password stored in _path/to/secret_, requesting the password
_path/to_ will literally return `path/to`. This can lead to using
weak passwords by accident/mess up logic in code, based on the
state of the password store.

This is worked around by applying the same logic `pass` uses:
If a password was returned, check if there is a .gpg file it could
have come from. If not, treat it as missing.

Fixes ansible-collections/community.general#4185

(cherry picked from commit da49c0968d)

Co-authored-by: grembo <freebsd@grem.de>
2022-02-17 21:33:18 +01:00
patchback[bot]
6f5152d053 Allow YAML docs in plugins/test/ and plugins/filters/. (#4204) (#4216)
(cherry picked from commit 1e4b8e30a9)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-17 19:44:34 +01:00
patchback[bot]
f8842e39be ini_file: Don't report changed=true when removing if nothing is changed. (#4155) (#4214)
* don't report changed when nothing is removed

* add change log

* linter happy

* Update plugins/modules/files/ini_file.py

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

* Update changelogs/fragments/4154-ini_file_changed.yml

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

* add absent idempotency test

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

Co-authored-by: James Livulpi <james.livulpi@me.com>
2022-02-17 13:50:57 +01:00
patchback[bot]
b1459b13fe gitlab_runner: Make owned and project mutually exclusive (#4136) (#4210)
* gitlab_runner: Set owned and project mutually exclusive

* gitlab_runner : Refactor _runners_endpoint usage

(cherry picked from commit 05c3e0d69f)

Co-authored-by: Léo GATELLIER <26511053+lgatellier@users.noreply.github.com>
2022-02-17 13:29:19 +01:00
patchback[bot]
57fa900f40 [modules/cloud/misc/proxmox_kvm] Adding EFI disk support (#4106) (#4209)
* Included efidisk0 option to be able to create VMs with persitent EFI disks

* Added forgotten argument to create_vm invocation and missing test for update

* Added changelog fragment relevant to PR

* Fixed documentation issues (missing period, and added version) from review

* Removed breaking change dependency for new option, modified changelog fragment according to review

* Fixed typo in documentation

* Added examples of `efidisk0` usage

* Added examples of `efidisk0` usage

* Fixed lines containing blank spaces

* Rebased on 4.4.0, added efi option, added sanity checks on efi option

* Adjusted version_added to 4.5.0

* Corrected typo in create_vm invocation, adjusted merging of efi and efidisk0 options

* Updated efidosk0 option to dict, added flattening to str, added constraint on bios option if efidisk0 is set

* Replaced loop by list comprehension for efidisk0 flattening

* Removed unused code left over from refactor from efi/efidis0 options

(cherry picked from commit 988cc82a89)

Co-authored-by: thuttinpasseron <87776406+thuttinpasseron@users.noreply.github.com>
2022-02-16 22:52:58 +01:00
patchback[bot]
f0a232d7a7 New module: pmem to configure Intel Optane Persistent Memory modules (#4162) (#4208)
* Add new module: pmem

This commit introduces to pmem module to configure Intel Optane
Persistent Memory modules (PMem).

* Add botmeta

* Update plugins/modules/storage/pmem/pmem.py

* Convert to snake_case options

* Update related to xmltodict

* Update to use list instead of string

* Update to use single quote to the string

* Update plugins/modules/storage/pmem/pmem.py

(cherry picked from commit 7f793c83f1)

Co-authored-by: mizumm <26898888+mizumm@users.noreply.github.com>
2022-02-16 22:52:44 +01:00
patchback[bot]
64f91aafa8 Add nejch and lgatellier as GitLab module maintainers. (#4199) (#4201)
(cherry picked from commit 7b02adc57e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-14 21:10:00 +01:00
patchback[bot]
7600fec752 Updated keycloak.py to allow defining connection timeout value (#4168) (#4178) (#4198)
* Updated keycloak.py to allow defining connection timeout value (#4168) (#2)

* Added parameter to doc_fragments and edited the changelog message (#4168)

* Added parameter to doc_fragments and edited the changelog message (#4168)

(cherry picked from commit 2498591695)

Co-authored-by: Nikolas Laskaris <laskarisn@gmail.com>
2022-02-14 19:56:01 +01:00
patchback[bot]
5af1ac26ac Add scaleway_private_network module (#4042) (#4197)
* begin add private network

* scaleway_private_network , basic add and remove ok, work in progress

* scaleway_private_network : add search in next page

* scalewy_private_network add tags

* scaleway_private_network fix correct return value for register

* scaleway_privat_network change some text

* fix some sanity

* fix  line too long

* fix  line too long SCALEWAY_LOCATION

* some change for sanity

* fix sanity again

* add author in BOTMETA

* fix error in name  in fike BOTMETA

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* add test for scaleway_private_network

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

* Update plugins/modules/cloud/scaleway/scaleway_private_network.py

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

Co-authored-by: pastral <52627592+pastral@users.noreply.github.com>
2022-02-14 18:27:07 +01:00
patchback[bot]
5c85b2d891 proxmox_kvm: add win11 to ostype (#4191) (#4193)
* proxmox_kvm: add win11 to ostype

* add changelog fragment

* Update changelogs/fragments/4191-proxmox-add-win11.yml

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

Co-authored-by: Andrea Ghensi <andrea.ghensi@gmail.com>
2022-02-12 18:32:12 +01:00
patchback[bot]
0a8aa03425 opentelemetry: enrich services for jenkins, hetzner or jira (#4105) (#4190)
* opentelemetry: enrich services for jenkins, hetzner, jira, zypper, chocolatey

* remove source and name for the time being

Those arguments can be later on in the future added, maybe with some opt-in feature, so let's only focus in the ones which are fully http based for now

* changelog fragment

* Update changelogs/fragments/4105-opentelemetry_plugin-enrich_jira_hetzner_jenkins_services.yaml

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

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

Co-authored-by: Victor Martinez <victormartinezrubio@gmail.com>
2022-02-12 09:17:26 +00:00
patchback[bot]
fa689ffadc [modules/cloud/misc/proxmox_kvm] Update docs for storage format option (#4186) (#4189)
* Updated storage format documentation to point to PVE docs to show possible values

* Fixed trailing space

(cherry picked from commit 14b8cd9c64)

Co-authored-by: thuttinpasseron <87776406+thuttinpasseron@users.noreply.github.com>
2022-02-12 09:30:11 +01:00
patchback[bot]
7d2332626e dconf: Skip processes that disappeared while we inspected them (#4153) (#4182)
* dconf: Skip processes that disappeared while we inspected them

Fixes #4151

* Update changelogs/fragments/4151-dconf-catch-psutil-nosuchprocess.yaml

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

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

Co-authored-by: Pavol Babinčák‏ <scroolik@gmail.com>
2022-02-10 07:47:47 +01:00
patchback[bot]
bdc7e48779 request for comments - pacman: speed up most operations when working with a package list (#3907) (#4176)
* pacman: rewrite with a cache to speed up execution

- Use a cache (or inventory) to speed up lookups of:
  - installed packages and groups
  - available packages and groups
  - upgradable packages
- Call pacman with the list of pkgs instead of one call per package (for
  installations, upgrades and removals)
- Use pacman [--sync|--upgrade] --print-format [...] to gather list of
  changes. Parsing that instead of the regular output of pacman, which
  is error prone and can be changed by user configuration.
  This can introduce a TOCTOU problem but unless something else calls
  pacman between the invocations, it shouldn't be a concern.
- Given the above, "check mode" code is within the function that would
  carry out the actual operation. This should make it harder for the
  check code and the "real code" to diverge.
- Support for specifying alternate package name formats is a bit more
  robust. pacman is used to extract the name of the package when the
  specified package is a file or a URL.
  The "<repo>/<pkgname>" format is also supported.

For "state: latest" with a list of ~35 pkgs, this module is about 5
times faster than the original.

* Let fail() actually work

* all unhappy paths now end up calling fail()

* Update copyright

* Argument changes

update_cache_extra_args handled as a list like the others
moved the module setup to its own function for easier testing
update and upgrade have no defaults (None) to let required_one_of() do
its job properly

* update_cache exit path

Shift successful exit without name or upgrade under "update_cache".

It is an error if name or upgrade isn't specified and update_cache wasn't specified
either. (Caught by ansiblemodule required_one_of but still)

* Add pkgs to output on success only

Also align both format, only pkg name for now

* Multiple fixes

Move VersionTuple to top level for import from tests
Add removed pkgs to the exit json when removing packages
fixup list of upgraded pkgs reported on upgrades (was tuple of list for
no reason)
use list idiom for upgrades, like the rest
drop unused expand_package_groups function
skip empty lines when building inventory

* pacman: add tests

* python 2.x compat + pep8

* python 2.x some more

* Fix failure when pacman emits warnings

Add tests covering that failure case

* typo

* Whitespace

black failed me...

* Adjust documentation to fit implicit defaults

* fix test failures on older pythons

* remove file not intended for commit

* Test exception str with e.match

* Build inventory after cache update + adjust tests

* Apply suggestions from code review

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

* Update plugins/modules/packaging/os/pacman.py

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

* changelog

* bump copyright year and add my name to authors

* Update changelogs/fragments/3907-pacman-speedup.yml

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

* maintainer entry

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

Co-authored-by: Jean Raby <jean@raby.sh>
2022-02-09 12:35:26 +01:00
patchback[bot]
815638f2ec vdo: Remove unused variable (#4163) (#4170)
* fix vdo error #3916

* add changelog fragment

(cherry picked from commit acd8853242)

Co-authored-by: Joseph Torcasso <87090265+jatorcasso@users.noreply.github.com>
2022-02-07 20:49:16 +01:00
patchback[bot]
a678029bd2 Refactor all Proxmox modules to use shared module_utils. (#4029) (#4164)
* Refactor Proxmox modules to use `module_utils`.

* Fix tests.

* Rename `node_check`.

* Add `ignore_missing` to `get_vm`.

* Refactor `proxmox` module.

* Add changelog entry.

* Add `choose_first_if_multiple` parameter for deprecation.

(cherry picked from commit a61bdbadd5)

Co-authored-by: Markus Reiter <me@reitermark.us>
2022-02-07 17:48:11 +01:00
patchback[bot]
fab30c5e55 Update Proxmox Inventory Documentation with additional examples (#4148) (#4159)
* Update Documentation with additional example

* Added an example to have the plugin return an IP address for a Proxmox guest, instead of the name of the guest (default behavior)
* Added an example to include a string literal to every guest (to support a playbook being able to check for variable presence to identify inventory in use)

* Update for line length readability

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

* Changed to cleaner static value

* Changed text for clarity

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

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

Co-authored-by: IronTooch <27360514+IronTooch@users.noreply.github.com>
2022-02-05 21:57:13 +01:00
patchback[bot]
3e25c692d7 Update docs helper. Automate generation of 'Merging lists of dictiona… (#4125) (#4160)
* Update docs helper. Automate generation of 'Merging lists of dictionaries'.

* Updated helper/lists_mergeby/playbook.yml, list of examples and
  templates. See playbook.yml on how to create *.out files, test
  examples and generate the REST file
  filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
* Generated REST file copied to directory rst
* Simplified examples. The common lists are published only once. Only
  the expressions are published instead of the whole tasks.
* To change the content of the section 'Merging lists of dictionaries'
  update template
  filter_guide_abstract_informations_merging_lists_of_dictionaries.rst.j2
  and run the playbook.
* Deleted rst/examples/lists_mergeby. Not needed anymore.

* Update docs/docsite/helper/lists_mergeby/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst.j2

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

* Update docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst

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

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2022-02-05 21:33:15 +01:00
patchback[bot]
e1a4b50074 gitlab_project_variable: Allow delete without value (#4150) (#4157)
* value is not required when state is absent

* fix integration test. missing value

* fix condition

* add changelog fragment

* fail fast

* try required_if on suboptions

* revert

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* fix naming in doc

* typo in name

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

Co-authored-by: Markus Bergholz <git@osuv.de>
2022-02-05 21:20:41 +01:00
patchback[bot]
3a270cea95 Fix return value documentation to use a valid value for 'type'. (#4142) (#4147)
(cherry picked from commit 9322809b3a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-02 22:16:18 +01:00
patchback[bot]
41672c20d3 homebrew_cask: reinstall when force is install option (#4090) (#4145)
* homebrew_cask: reinstall when force is install option

* add changelog entry

* Fix OSX CI runs - run as non-root

* test with cask that has no macos dependencies

* use `brooklyn` cask to test

(cherry picked from commit 8b95c56030)

Co-authored-by: Joseph Torcasso <87090265+jatorcasso@users.noreply.github.com>
2022-02-02 21:54:52 +01:00
Felix Fontein
57f5ceece8 The next expected release is 4.5.0. 2022-02-01 13:11:06 +01:00
Felix Fontein
945bb91e04 Release 4.4.0. 2022-02-01 12:31:04 +01:00
patchback[bot]
b48a5c264f mail callback: fully use Ansible's option handling; deprecate not specifying sender (#4140) (#4141)
* Fully use Ansible's option handling. Deprecate not specifying sender.

* Update plugins/callback/mail.py

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit e09254df91)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-02-01 10:47:32 +01:00
patchback[bot]
5bae017de9 Try to fix CentOS 8 in CI - at least a bit. (#4132) (#4138)
(cherry picked from commit 24f7a3b6ad)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-31 21:54:24 +01:00
patchback[bot]
e568a760ac Fix and rework gitlab_project_variable (#4038) (#4133)
* rework-and-fix

* fix delete bug and change report

* delete the requested variables based on env scope

* fix absent logic when not purge: remove what is requested

* change code to current behaviour

* complete implementation

* fix delete

* restore origin return structure

* reorder

* add test for origin bug

* add changelog fragment

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* remove yaml

* apply suggestions

* readd accidental removed line

* improve the truth of return value 'project_variable' in check mode

* fix pep8, over-indented

* fix typos and add subelement options

* Update changelogs/fragments/4038-fix-and-rework-gitlb-project-variable.yml

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

* Update changelogs/fragments/4038-fix-and-rework-gitlb-project-variable.yml

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

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* Update plugins/modules/source_control/gitlab/gitlab_project_variable.py

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

* remove diff feature

* resolve all recommentdations

* resolve change requests, improve doc and remove default value before compare, because values always exists (prebuild)

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

Co-authored-by: Markus Bergholz <git@osuv.de>
2022-01-31 20:58:05 +01:00
patchback[bot]
8132568d2f Added new feature for ansible_user and ansible_port in Icinga2 inventory source (#4088) (#4130)
* Added new feature for ansible_user and ansible_port

* Replaced 'try' and 'except' with 'if' condition

* Replace '!=' with 'is not'

* Fixed if condition

* Implement the constructed interface

* Correction at the suggestion of felixfontein

* Added new options in unit test for icinga2 inventory

* Added blank lines in unit test for icinga2 inventory

* Added default filter in example

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

* Fixed variable name in example

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

* Added a changelog fragment

* Fixed changelog fragment

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

* Updated documentation options

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

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

Co-authored-by: Nedelin Petkov <mlg@abv.bg>
2022-01-31 20:22:59 +01:00
patchback[bot]
0e320641b8 Fix local port regex in listen_ports_facts (#4092) (#4128)
* Fix local port regex

Thsi PR fix the bug reported in #4091

* Update changelogs/fragments/4092-fix_local_ports_regex_listen_ports_facts.yaml

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

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

Co-authored-by: gaetan-craft <97035736+gaetan-craft@users.noreply.github.com>
2022-01-31 20:01:23 +01:00
patchback[bot]
8679d59376 Add profile parameter for scaleway inventory (#4049) (#4129)
* add profile parameter for scaleway inventory

* Update doc from review and add changelog

* Update changelogs from review

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

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

Co-authored-by: LucasBoisserie <LucasBoisserie@users.noreply.github.com>
2022-01-31 20:01:08 +01:00
patchback[bot]
2554b4b0f4 gitlab: use gitlab instance runner to create runner (#3965) (#4123)
When using project it will use project level runner to create runner that based on python-gitlab it will be used for enabling runner and needs a runner_id so for creating a new runner it should use gitlab level runner

Signed-off-by: Seena Fallah <seenafallah@gmail.com>
(cherry picked from commit 929136808f)

Co-authored-by: Seena Fallah <seenafallah@gmail.com>
2022-01-31 06:20:30 +01:00
patchback[bot]
379b6d3523 [inventory/cobbler] Add include_profiles option (#4068) (#4121)
* [inventory/cobbler] Add exclude/include_profile option

Also some minor cleanup

* Review suggestions

* Still must init cache_key

* Add note to exclude_profiles about include_profiles

* Add changelog fragment

(cherry picked from commit 0dd886bac8)

Co-authored-by: Orion Poplawski <orion@nwra.com>
2022-01-31 06:20:07 +01:00
patchback[bot]
fe4f4198af Docs split filter guide (#4103) (#4120)
* Update docs. Split fiter_guide.rst to files per sections.

* Fix docs.

* Update docs. Split filter_guide_abstract_informations.rst to files per sections.

* Create section 'Merging lists of dictionaries' from the template in helper/lists_mergeby.

* Fixed indentation. Comments and notes added.

* Revert "Fixed indentation. Comments and notes added."

This reverts commit 0f38450868.

* Revert "Create section 'Merging lists of dictionaries' from the template in helper/lists_mergeby."

This reverts commit 5b9d01ec2d.

(cherry picked from commit 9c146787f5)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2022-01-31 06:19:53 +01:00
patchback[bot]
db84ea4ab6 linode: Allow templating token for dynamic inventory (#4040) (#4119)
* linode: Allow templating token for dynamic inventory

Template the value for the access_token if it's a Jinja template.

Allows for looking up tokens from files or pulling from secrets stores like Vault.

* add Linode changelog fragment

* Fix lookup example for newer versions of Ansible

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

* Rename test case for clarity

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

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

Co-authored-by: Will Hegedus <will@wbhegedus.me>
2022-01-30 21:40:07 +00:00
Felix Fontein
de5970d17a Prepare 4.4.0 release. 2022-01-30 15:17:16 +01:00
patchback[bot]
433d0571b4 PyOpenSSL 22.0.0 no longer supports Python 2.7 (#4114) (#4118)
* PyOpenSSL 22.0.0 no longer supports Python 2.7.

* Try to make pip on CentOS 6 happy.

(cherry picked from commit 84124224ae)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-30 15:15:10 +01:00
patchback[bot]
53b95fd182 python_requirements_info: don't overwrite results in 'mismatched' dict key (#4078) (#4111)
* bugfix: don't overwrite results in 'mismatched'

Whichever mismatched package is evaluated last is the value stored in the
'mismatched' key. Instead, it should have a subdict for each pkg that is mismatched
to keep in line with its documented usage.

* Update changelogs/fragments/4078-python_requirements_info.yaml

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

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

Co-authored-by: Will Hegedus <will@wbhegedus.me>
2022-01-29 15:19:57 +00:00
patchback[bot]
ad1f25e576 opentelemetry: enrich service for community.docker.docker_login (#4104) (#4109)
* opentelemetry: support service for community.docker.docker_login

* changelog

(cherry picked from commit e793e2e94f)

Co-authored-by: Victor Martinez <victormartinezrubio@gmail.com>
2022-01-29 15:19:44 +00:00
patchback[bot]
49eda7270e Add options to filter lists_mergeby (#4058) (#4101)
* Update filter lists_mergeby #4057

* Added options 'recursive' and 'list_merge'. The functionality of the
  added options is the same as in the filter 'combine'.
* Allow the user to do [list1, list2, ...]|lists_mergeby('index')
* Use the function merge_hash from ansible.utils.vars

* Add merge_hash_wrapper to test Ansible version

* Enable Ansible 2.9 and lower versions with default options of
  lists_mergeby only.
* Non-default options of lists_mergeby trigger error in 2.9 and lower
  versions.
* Update messages and tests.

* Fix tests.

* Use LooseVersion instead of SpecifierSet.

* Update docs 'Filter Guide' section 'Merging lists of dictionaries'.

* Added changelog fragment.

* Update changelogs/fragments/4058-lists_mergeby-add-parameters.yml

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Added examples; moved to rst/examples; fixes.

* Improve error message testing sequence.

* Removed .yamllint

* Update docs/docsite/rst/examples/lists_mergeby/example-003.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/example-004.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/example-005.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/example-006.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/example-007.yml

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/filter_guide.rst

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

* Update tests/integration/targets/filter_list/tasks/lists_mergeby_default.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/example-008.yml

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

* Fix docs. Antsibull only copies .rst files.

* Fix examples in-line.

* Update docs/docsite/rst/filter_guide.rst

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs/docsite/rst/examples/lists_mergeby/examples.yml

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

* Update docs lists_mergeby. Remove rubbish.

* Emphasized labes of examples in filter_guide.rst
* Removed temporary file examples/lists_mergeby/examples.rst
* Removed tests/integration/targets/filter_list/runme.*

* Fix docs. Description of the lists_merge options.

* Move helper files out of rst/ directory.

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

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2022-01-28 12:46:05 +01:00
patchback[bot]
9c4799c903 Actually expand ~ in yarn global install folder (#4048) (#4100)
* Fix 'changed' status for yarn global by actually expanding ~

* Ignore use-argspec-type-path test

* Add changelog fragment

* Update changelogs/fragments/4048-expand-tilde-in-yarn-global-install-folder.yaml

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

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

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
2022-01-28 07:41:36 +01:00
patchback[bot]
88bf99b272 Properly parse JSON Lines output from yarn (#4050) (#4098)
* Properly parse JSON Lines output from yarn

* Properly support output of yarn global list

* Add changelog fragment

* Check that the string starts with 'bins-'

* Fix changelog fragment

* Update changelogs/fragments/4050-properly-parse-json-lines-output-from-yarn.yaml

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

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

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
2022-01-28 07:38:51 +01:00
patchback[bot]
3ca6e8525e New Module: Homectl module for managing systemd-homed (#4018) (#4096)
* initial development of homectl module

* botmeta

* fix some linting

* Update .github/BOTMETA.yml

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* use array form of run_command

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

* Update plugins/modules/system/homectl.py

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

* added mofifying user record and cleaned up based on comments

* added updating records/multiple changes regarding options, examples doc, return doc

* add integration tests and more overall improvements

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* Update plugins/modules/system/homectl.py

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

* removed modify handle within present

* adding more options and better checking of user records when updating

* Apply suggestions from code review

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

* Update plugins/modules/system/homectl.py

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

* Add code review changes

- remove unsafe_shell with run_command.
- use dict.pop() in user_metadata dict.
- consistent quoting to single quotes.
- change logic to determine check mode better
- fix integration tests and added check_mode tests

* Fix handling of mount opts

When a user is created without mountopts homed will use nodev and nosuid
by default, however the user record metadata will not contain these
values. This commit takes extra care that correct value is being set to
true or false. So if a user gives mountopts with just nodev we need to
make sure the nosuid and noexec gets set to false, etc. If mountopts are
same as currently in user record make sure nothing would be changed and
outputs correctly.

Also fixed some tests.

* change fmethod modify_user to prepare_modify_user_command

* Code review fixes and add existing user pw checking

- Added methods to check existing users password is correct by comparing
  the hash stored in homed user record and the hash of given password
- Updated integration tests for above case
- Added aliases file so CI can run

* 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 ab7e4ee578)

Co-authored-by: James Livulpi <james.livulpi@me.com>
2022-01-28 07:38:25 +01:00
patchback[bot]
0169cb8358 Adding while loop to wait for cluster container creation (#4039) (#4095)
* Adding while loop to wait

* Adding changelog fragment

* Adding parameter and more docs

* Adjusting docs

Co-authored-by: Travis Scotto <tscotto@webstaurantstore.com>
(cherry picked from commit 7aab4497ac)

Co-authored-by: tman5 <10875976+tman5@users.noreply.github.com>
2022-01-28 07:38:10 +01:00
patchback[bot]
499f4b4066 Fix missing '>'. (#4080) (#4082)
(cherry picked from commit 5fead8bbde)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-25 08:04:29 +01:00
patchback[bot]
ff08c20f12 one_vm: add release action (#4036) (#4077)
* one_vm: add release action

Previously you could create VMs with the `vm_start_on_hold` parameter
but then ansible couldn't release the VMs so they would be scheduled to
run. This PR adds the ability to release VMs which are in the 'HOLD'
state.

* Add changelog fragment

* Update changelogs/fragments/4036-onevm-add-release-action.yaml

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

* Update plugins/modules/cloud/opennebula/one_vm.py

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

* Make releasing a VM part of the running state

When `state: running` is specified the code checks if the VM is in a
'HOLD' state and will release the VM when needed.

Co-authored-by: Gerben Welter <gerben.welter@hcs-company.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit a4983ce38a)

Co-authored-by: Gerben Welter <gerben@welter.nu>
2022-01-24 21:00:19 +01:00
patchback[bot]
d27c06faeb [PR #3943/12c0220c backport][stable-4] Add option "options" to snap module (#4076)
* Add option "options" to snap module (#3943)

* Add functionality proposed in https://github.com/ansible-collections/community.general/issues/666

* Fix pylint errors mentioned in CI pipeline

* Fix pylint errors mentioned in CI pipeline (continued)

* Update plugins/modules/packaging/os/snap.py

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

* Apply suggestions from code review

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

* Added tests
Fixed error occurring when called without options
Added changelog snippet

* Remove changelog entry as suggested in review

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

* Apply suggestions from code review

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

* rewrite `if len(overall_options_changed) > 0` in a more Pythonic way
un-indent `if len(overall_options_changed) > 0` to only be executed after the options of all snaps have been checked

* better placement of local variable `overall_options_changed`

* Re-arrange code to reduce indentation level (suggested by reviewer)

* Re-arrange code to reduce indentation level (suggested by reviewer, continued)

* Re-arrange code to reduce indentation level (suggested by reviewer, continued)
Raise exception if option map returned by `snap set` contains list container (suggested by reviewer)
Handle Python2 type `long` correctly (suggested by reviewer)

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

* Fix version_added.

(cherry picked from commit 62d519de10)

Co-authored-by: marcus67 <marcus.rickert@web.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-24 09:23:31 +01:00
patchback[bot]
0f98b63944 Add nmcli support for IPv6 routes (#4062) (#4075)
(cherry picked from commit f954539795)

Co-authored-by: Trey West <treywest45th@gmail.com>
2022-01-23 13:26:09 +01:00
patchback[bot]
55c70dfb72 Improve documentation on how to run tests (#4070) (#4072)
* Improve documentation on how to run tests.

* Fix incomplete sentence.

* Apply suggestions from code review

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* Improve separation.

* Fix unrelated typo.

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 8a03d9f286)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-21 19:55:16 +01:00
patchback[bot]
f78993ba12 mail: add Date and Message-ID headers (#4056) (#4069)
(cherry picked from commit 750d96a95f)

Co-authored-by: Lénaïc Huard <L3n41c@users.noreply.github.com>
2022-01-21 09:29:15 +01:00
patchback[bot]
b97ce10156 Fix exception in the mail callback plugin (#4026) (#4064)
(cherry picked from commit c7500c217f)

Co-authored-by: Lénaïc Huard <L3n41c@users.noreply.github.com>
2022-01-20 09:30:03 +01:00
patchback[bot]
9250430d7d Fix detection of installed cargo packages with hyphens in name (#4052) (#4054)
* Fix detection of installed cargo packages with hyphens in name

* Add changelog fragment

* Fix outdated package detection

* Add changelog fragment for af4fae72

* One more thing

* Add idempotency tests

(cherry picked from commit c18fdb43d7)

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
2022-01-18 19:40:37 +01:00
patchback[bot]
d61305d267 opentelemetry: no_log:true causes exception when generating trace (#4043) (#4051)
* dont check for urls when args is None

* add changelog fragment

* fix lint on changelog fragment

Co-authored-by: Nick Gregory <nick.gregory@openenterprise.co.uk>
(cherry picked from commit 5540dab382)

Co-authored-by: NixM0nk3y <github@openenterprise.co.uk>
2022-01-17 21:57:46 +01:00
patchback[bot]
198b813b55 Update example (#4041) (#4047)
The `simple_config_file` was confusing and doesn't work if you copy paste it.

(cherry picked from commit 20d09a4ae6)

Co-authored-by: Samori Gorse <samori@codeinstyle.io>
2022-01-16 20:55:03 +01:00
patchback[bot]
9e6df4f1c9 Move Proxmox HAS_PROXMOXER check into module_utils. (#4030) (#4046)
* Move Proxmox `HAS_PROXMOXER` check into `module_utils`.

* Fix tests.

* Fix typo.

* Update changelog entry.

(cherry picked from commit 761fbe4fa3)

Co-authored-by: Markus Reiter <me@reitermark.us>
2022-01-16 20:28:26 +01:00
patchback[bot]
a477044fb7 Update CI matrix for Remote Devel. (#4033) (#4035)
(cherry picked from commit 3faffe8f47)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-13 09:15:18 +01:00
Felix Fontein
2a97812856 Next expected release is 4.4.0. 2022-01-11 08:08:12 +01:00
Felix Fontein
c85bb8713e Release 4.3.0 2022-01-11 07:27:25 +01:00
patchback[bot]
5cdc8f4b07 New Module: Keycloak Realm Info (#3998) (#4022)
* feat(plugins/keycloak): add get_realm_info_by_id as util function

* feat(plugins/keycloak): add keycloak_realm_info module

* chore: add maintainer

* feat(plugins/keycloak): remove supports_check_mode

* feat(plugins/keycloak): add supports_check_mode back

* Update plugins/modules/identity/keycloak/keycloak_realm_info.py

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

* Update plugins/modules/identity/keycloak/keycloak_realm_info.py

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

* docs(plugins/keycloak): cleanup docs

* feat(plugins/keycloak): add unit test

* Update plugins/modules/identity/keycloak/keycloak_realm_info.py

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

* Update plugins/modules/identity/keycloak/keycloak_realm_info.py

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

* feat(plugins/keycloak): remove end_state

* docs(plugins/keycloak): complete sentences

* docs(plugins/keycloak): use dict for return type

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

Co-authored-by: Fynnnnn <fynn.cfchen@gmail.com>
2022-01-11 07:13:16 +01:00
Felix Fontein
50131f5dfa Prepare 4.3.0 release. 2022-01-10 23:06:56 +01:00
patchback[bot]
c734e7c2e5 fix alternatives parsing when they are part of a group (#3976) (#4021)
* fix alternatives parsing when they are part of a group

* add changelog fragment

Co-authored-by: Guillaume Rousse <guillaume.rousse@renater.fr>
(cherry picked from commit a675afcba9)

Co-authored-by: Guillaume Rousse <guillomovitch@gmail.com>
2022-01-10 07:27:31 +01:00
patchback[bot]
7e6e8f7749 puppet: Add documentation and remove deprecation for show_diff, keep deprecation for alias show-diff (#3980) (#4019)
* puppet: Add documentation and remove deprecation for show_diff

* Add changelog fragment

* Update changelogs/fragments/3980-puppet-show_diff.yml

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

* Update plugins/modules/system/puppet.py

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

* Update plugins/modules/system/puppet.py

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

* Fixing syntax error introduced in 29298da3

* More documentation for show_diff and fix some sanity errors

* Update changelogs/fragments/3980-puppet-show_diff.yml

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

* Update tests/sanity/ignore-2.10.txt

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

* Add validate-modules:parameter-invalid to ignores due to invalid and depricated alias

* Keep use-argspec-type-path in ignores

* Update plugins/modules/system/puppet.py

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

Co-authored-by: Benoit Vaudel <benoit@catalyst.net.nz>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit fe57cd5ac8)

Co-authored-by: Benoit Vaudel <vaudelbenoit@aol.com>
2022-01-10 07:27:22 +01:00
patchback[bot]
687acdc961 Fix example code for flattened lookup (#4013) (#4016)
Co-authored-by: Lee Garrett <lgarrett@rocketjump.eu>
(cherry picked from commit d19ab93faf)

Co-authored-by: Lee Garrett <leegarrett@users.noreply.github.com>
2022-01-09 12:29:22 +01:00
patchback[bot]
16092feaab ipmi_power: Add machine option to ensure the power state via the remote target address (#3968) (#4012)
* ipmi_power: Add machine option to ensure the power state via the remote target address

* Fix yamllint sanity check error

* Add changelog fragment entry

* Apply suggestions from the code review

* update to apply suggestions

* Add version_added.

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

Co-authored-by: mizumm <26898888+mizumm@users.noreply.github.com>
2022-01-08 16:17:56 +01:00
patchback[bot]
6676fb8fb4 New module for cargo command (#3712) (#4011)
* New module for cargo command

* Resolve CI errors

* Update plugins/modules/packaging/language/cargo.py

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

* Update plugins/modules/packaging/language/cargo.py

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

* Update plugins/modules/packaging/language/cargo.py

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

* Add maintainer

* Change installed_packages from property to function

* Allow cargo to install list of of packages

* Remove period at the end of task names

* Pass only the list of packages to take action on to cargo

* Add integration tests for cargo

* Update plugins/modules/packaging/language/cargo.py

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

* Apply suggestions from code review

* Update tests/integration/targets/cargo/tasks/setup.yml

* Update tests/integration/targets/cargo/tasks/setup.yml

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

Co-authored-by: radek-sprta <mail@radeksprta.eu>
2022-01-08 16:03:23 +01:00
patchback[bot]
a860f537dd Restrict PyNaCL to 1.4.x on RHEL8 when using Python 3.6 (#4006) (#4010)
* Restrict PyNaCL to 1.4.x on RHEL8 when using Python 3.6.

* Fix typo.

(cherry picked from commit 77a930cf6b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-08 14:19:25 +00:00
patchback[bot]
f1a9c2f00a nmcli: Add wireguard connection type support (#3985) (#4007)
* nmcli: add wireguard connection type

* nmcli: fix wireguard unit tests

* nmcli: set ipv4.method to disabled if ip4 not set

Method 'auto' is not supported for WireGuard

* nmcli: add wireguard documentation

* nmcli: clean up wireguard documentation

* nmcli: add wireguard changelog fragment

* nmcli: fix wireguard documentation

* Apply suggestions from code review

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>
(cherry picked from commit 4ea58fba75)

Co-authored-by: Johan Wennerberg <j.wennerberg@gmail.com>
2022-01-08 14:33:02 +01:00
patchback[bot]
f8de068e32 Fix 2.9 unit tests (#4002) (#4005)
* Fix 2.9 unit tests.

* Another try.

(cherry picked from commit 26a91e811f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-08 13:34:11 +01:00
patchback[bot]
70b4bacf0f Fix comment. (#3993) (#3995)
(cherry picked from commit a6a8cd02b6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-06 15:10:49 +01:00
patchback[bot]
41f5d1741c proxmox: Add clone parameter (#3930) (#3992)
* proxmox: Add clone parameter

* Add changelog fragment

* Add version_added

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

* Add PR URL to changelog fragment

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

* Clarify what content_check does

* Split up try/except block to give a separate error message when creation pre-checks fail

* Create seperate case for cloning

* Prevent 'clone' argument from being removed

* Fix double argument, add todo's

* Check if to be cloned container actually exists

* Adjust module options dependencies

* Require 'storage' parameter when cloned container is not a template and ignore otherwise

* Don't only create linked clones of template containers

* Fix pylint errors

* Add extra example

* Minor language fix

* Add clone_type parameter to specify cloning behaviour

* I can't find if openvz nodes have this clone API, so just don't support it

* Remove unrelated changes

* Don't pass unused kwargs

* Revert more unrelated changes

* Remove required_together clone and clone_type because clone_type has a default choice

* Fix clone_type reference

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

* Fix missing period

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

* Fix redundant period

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

* Fix redundant period

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

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

Co-authored-by: Martijn <martijn@mrtijn.nl>
2022-01-06 08:06:55 +01:00
patchback[bot]
54ede7dd7f Fix BOTMETA and corresponding sanity test (#3989) (#3990)
* Fix BOTMETA and authors mistakes.

* Fix BOTMETA sanity test regex.

(cherry picked from commit 11205eefee)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-06 06:56:27 +01:00
patchback[bot]
7f0702b786 Use vendored copy of distutils.version. (#3984) (#3987)
(cherry picked from commit cf7a33356c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-05 22:05:13 +01:00
patchback[bot]
89a3abe64a [Bug] Scaleway The volume is created systematically on par1 (#3964) (#3983)
* [Bug] The volume is created systematically on par1

* add change log

* added backward compatibility with organization

* add documentation

* change typo doc

* Update changelogs/fragments/3964-scaleway_volume_add_region.yml

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

* Update plugins/modules/cloud/scaleway/scaleway_volume.py

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

* Update plugins/modules/cloud/scaleway/scaleway_volume.py

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

* Update plugins/modules/cloud/scaleway/scaleway_volume.py

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

* Update plugins/modules/cloud/scaleway/scaleway_volume.py

Co-authored-by: Rémy Léone <remy.leone@gmail.com>

* optimization

Co-authored-by: Romain SCHARFF <rscharff@plussimple.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Rémy Léone <remy.leone@gmail.com>
(cherry picked from commit 125516b957)

Co-authored-by: xilmen <romain.scha@gmail.com>
2022-01-05 18:12:11 +01:00
patchback[bot]
59eff2e3e0 Re-enable snap tests (#3967) (#3981)
* Re-enable snap tests.

* Skip tests on RHEL 8.2 and 8.3.

* Refactor snap setup.

* Try to simplify setup.

(cherry picked from commit bb78d98f8f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-05 17:49:05 +01:00
patchback[bot]
1115b463fe Sudoers (take 2) (#3746) (#3977)
* Add module and pass the andebox validate-modules

* Fixes pep8 and sanity checks

* Add tests (intending that they'll fail)

* Fix pep8 complaint

* Remove stub test_sudoers file

* Add version_added to documentation

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>

* Various improvements as suggested by reviewers

* Remove further required: false from documentation

* Make yaml indentation consistently indented

* Remove default for command argument

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>

* Refactor check_mode checking as guards

* Update documentation formatting and use to_native

* Update plugins/modules/system/sudoers.py

* Update examples and formatting

* Fix merge conflict

* Update handle

* Add some integration tests

* Update tests to pass yamllint

* Fix assertions typo

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

* Remove wrapping quotes from assertions

* Use >- for long example names

* Add aliases file to sudoers integration tests

* Fix integration test name

* Create new alternative sudoers directory in case /tmp doesn't exist

* Alternative assertion test for checking rule revocation

* Re-quote assertions

* Update version_added to 4.3.0

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

* Uppercase first character of short_description

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

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

Co-authored-by: Jon <ellis.jp@gmail.com>
2022-01-04 21:08:02 +01:00
patchback[bot]
77bf1fedf5 Get rid of distutils.spawn and distutils.util (#3934) (#3974)
* Replace distutils.spawn.find_executable.

* Replace distutils.util.strtobool.

(cherry picked from commit 77b7b4f75b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2022-01-04 07:22:25 +01:00
patchback[bot]
89560ea2e7 Mattermost: Add sending of attachments (#3946) (#3972)
* Add sending of attachments

* Change required arguments and add changelog

- text was still default -> changed to required_one_of text or attachments
- Add version_added
- Add changelog fragment for mattermost attachments

Co-Authored-By: Felix Fontein <felix@fontein.de>

* Fix wrong indentation

* Add trailing comma

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

* Remove default=None

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

* Fix sentence

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

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

Co-authored-by: xobtoor <313188+xobtoor@users.noreply.github.com>
2022-01-03 19:44:06 +01:00
patchback[bot]
f9919d28d4 slack - use UTF-8 charset in content-type header (#3933) (#3971)
* Use UTF-8 charset in content-type header

* Add changelog fragment

(cherry picked from commit a4ab85fd68)

Co-authored-by: bluikko <14869000+bluikko@users.noreply.github.com>
2022-01-03 19:43:50 +01:00
patchback[bot]
7b4660d28a Add support of project id for scawelay_compute (#3951) (#3961)
* Add support of project id for scawelay_compute

* Create 3951-scaleway_compute_add_project_id

* rename changelog frament

* remove useless whitespace in scaleway_compute.py

* Update changelogs/fragments/3951-scaleway_compute_add_project_id.yml

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

* Update plugins/modules/cloud/scaleway/scaleway_compute.py

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

* correct documentation

* Update changelogs/fragments/3951-scaleway_compute_add_project_id.yml

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

* Update changelogs/fragments/3951-scaleway_compute_add_project_id.yml

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

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

Co-authored-by: pmangin <96626847+pmangin@users.noreply.github.com>
2021-12-28 16:44:10 +01:00
patchback[bot]
29496be80e Restrict redis to < 4.1.0 for ansible-base 2.10. (#3955) (#3959)
(cherry picked from commit 3f2364574d)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-27 21:17:09 +01:00
patchback[bot]
991c96615c fix scaleway_user_data (#3940) (#3954)
* fix  scaleway_user_data

scaleway_user_data put cloud-init valuer with 2 unexpected " (begin and end of value)

If Content-Type is not change , it's jsonify ( file module_utils/scaleway.py ligne 131 )

fix the probleme  when "Content-Type" is used instead of "Content-type"

* Create 3940_fix_contenttype_scaleway_user_data.yml

* Update changelogs/fragments/3940_fix_contenttype_scaleway_user_data.yml

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

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

Co-authored-by: pmangin <96626847+pmangin@users.noreply.github.com>
2021-12-27 20:00:58 +01:00
patchback[bot]
fe5ad997c1 ipa_dnszone: add PTR synchronization support for dnszones (#3374) (#3950)
* Add PTR synchronization support for dnszones

* Add changelog fragment

* Update changelogs/fragments/3374-add-ipa-ptr-sync-support.yml

Update to reflect proper module name.

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

* Update plugins/modules/identity/ipa/ipa_dnszone.py

Add period.

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

* Update plugins/modules/identity/ipa/ipa_dnszone.py

Remove requires comment.

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

* Change type to boolean in following with API docs

* Tested with needed changes made.

* Fix documentation to max implementation

* Check for specific params; allow for modifications if needed

* Add PTR synchronization support for dnszones

* Add changelog fragment

* Update changelogs/fragments/3374-add-ipa-ptr-sync-support.yml

Update to reflect proper module name.

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

* Remove trailing whitespace

* Make use of full search and compare params

* Fix formatting errors

* Move the change flag outside of module check

* Fix itens typo to items

* Update dynamicupdate to a boolean

* Remove unnecessary flags and options

* Minor comment changes

* Update changelogs/fragments/3374-add-ipa-ptr-sync-support.yml

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

* Update plugins/modules/identity/ipa/ipa_dnszone.py

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

Co-authored-by: Anne-Marie Lee <alee@datainterfuse.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 84e45c2cc0)

Co-authored-by: Annie Lee <hambriak@gmail.com>
2021-12-27 16:22:55 +01:00
patchback[bot]
468b28bbb8 Add counter filter (#3921) (#3945)
* Add counter filter

* move counter filter doc to existing chapter

* Use existing typerror exception from Counter

* Match counter filter example task name and output

(cherry picked from commit 9642a15d34)

Co-authored-by: Rémy Keil <remy.keil@gmail.com>
2021-12-26 15:25:18 +01:00
patchback[bot]
9b57221d9a Prepare for distutils.version being removed in Python 3.12 (#3936) (#3941)
* Prepare for distutils.version being removed in Python 2.12.

* Fix copy'n'paste error.

* Re-add Loose prefix.

* Fix Python version typos.

* Improve formulation.

* Move message into own line.

* Fix casing, now that the object is no longer called Version.

(cherry picked from commit a2f72be6c8)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-24 19:15:47 +01:00
patchback[bot]
cd1a92d417 Fix filesystem tests (so they run on their own) (#3937) (#3939)
* Don't use loops for installing packages.

* Install util-linux-systemd on OpenSuSE so that findmnt is around.

(cherry picked from commit f34c454412)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-23 12:33:24 +01:00
Felix Fontein
7486e3a074 Next expected release is 4.3.0. 2021-12-21 12:24:08 +01:00
344 changed files with 14375 additions and 3984 deletions

View File

@@ -69,6 +69,19 @@ stages:
- test: 3
- test: 4
- test: extra
- stage: Sanity_2_13
displayName: Sanity 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Test {0}
testFormat: 2.13/sanity/{0}
targets:
- test: 1
- test: 2
- test: 3
- test: 4
- stage: Sanity_2_12
displayName: Sanity 2.12
dependsOn: []
@@ -138,6 +151,19 @@ stages:
- test: 3.8
- test: 3.9
- test: '3.10'
- stage: Units_2_13
displayName: Units 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.13/units/{0}/1
targets:
- test: 2.7
- test: 3.6
- test: 3.8
- test: 3.9
- stage: Units_2_12
displayName: Units 2.12
dependsOn: []
@@ -148,12 +174,8 @@ stages:
testFormat: 2.12/units/{0}/1
targets:
- test: 2.6
- test: 2.7
- test: 3.5
- test: 3.6
- test: 3.7
- test: 3.8
- test: '3.10'
- stage: Units_2_11
displayName: Units 2.11
dependsOn: []
@@ -166,9 +188,6 @@ stages:
- test: 2.6
- test: 2.7
- test: 3.5
- test: 3.6
- test: 3.7
- test: 3.8
- test: 3.9
- stage: Units_2_10
displayName: Units 2.10
@@ -191,11 +210,7 @@ stages:
testFormat: 2.9/units/{0}/1
targets:
- test: 2.6
- test: 2.7
- test: 3.5
- test: 3.6
- test: 3.7
- test: 3.8
## Remote
- stage: Remote_devel
@@ -206,20 +221,36 @@ stages:
parameters:
testFormat: devel/{0}
targets:
- name: macOS 11.1
test: macos/11.1
- name: macOS 12.0
test: macos/12.0
- name: RHEL 7.9
test: rhel/7.9
- name: RHEL 8.5
test: rhel/8.5
- name: FreeBSD 12.2
test: freebsd/12.2
- name: FreeBSD 12.3
test: freebsd/12.3
- name: FreeBSD 13.0
test: freebsd/13.0
groups:
- 1
- 2
- 3
- stage: Remote_2_13
displayName: Remote 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.13/{0}
targets:
- name: macOS 12.0
test: macos/12.0
- name: RHEL 8.5
test: rhel/8.5
groups:
- 1
- 2
- 3
- stage: Remote_2_12
displayName: Remote 2.12
dependsOn: []
@@ -302,14 +333,32 @@ stages:
test: fedora34
- name: Fedora 35
test: fedora35
- name: openSUSE 15 py2
test: opensuse15py2
- name: openSUSE 15 py3
- name: openSUSE 15
test: opensuse15
- name: Ubuntu 18.04
test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- name: Alpine 3
test: alpine3
groups:
- 1
- 2
- 3
- stage: Docker_2_13
displayName: Docker 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.13/linux/{0}
targets:
- name: Fedora 35
test: fedora35
- name: openSUSE 15 py2
test: opensuse15py2
- name: Alpine 3
test: alpine3
groups:
- 1
- 2
@@ -324,12 +373,8 @@ stages:
targets:
- name: CentOS 6
test: centos6
- name: CentOS 8
test: centos8
- name: Fedora 34
test: fedora34
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 20.04
test: ubuntu2004
groups:
@@ -344,12 +389,10 @@ stages:
parameters:
testFormat: 2.11/linux/{0}
targets:
- name: CentOS 7
test: centos7
- name: Fedora 33
test: fedora33
- name: openSUSE 15 py2
test: opensuse15py2
- name: Alpine 3
test: alpine3
groups:
- 2
- 3
@@ -378,12 +421,30 @@ stages:
targets:
- name: Fedora 31
test: fedora31
- name: openSUSE 15 py3
test: opensuse15
groups:
- 2
- 3
### Community Docker
- stage: Docker_community_devel
displayName: Docker (community images) devel
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: devel/linux-community/{0}
targets:
- name: Debian Bullseye
test: debian-bullseye/3.9
- name: ArchLinux
test: archlinux/3.10
- name: CentOS Stream 8
test: centos-stream8/3.8
groups:
- 1
- 2
- 3
### Cloud
- stage: Cloud_devel
displayName: Cloud devel
@@ -395,6 +456,16 @@ stages:
testFormat: devel/cloud/{0}/1
targets:
- test: 2.7
- test: '3.10'
- stage: Cloud_2_13
displayName: Cloud 2.13
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
nameFormat: Python {0}
testFormat: 2.13/cloud/{0}/1
targets:
- test: 3.9
- stage: Cloud_2_12
displayName: Cloud 2.12
@@ -444,25 +515,31 @@ stages:
- Sanity_2_10
- Sanity_2_11
- Sanity_2_12
- Sanity_2_13
- Units_devel
- Units_2_9
- Units_2_10
- Units_2_11
- Units_2_12
- Units_2_13
- Remote_devel
- Remote_2_9
- Remote_2_10
- Remote_2_11
- Remote_2_12
- Remote_2_13
- Docker_devel
- Docker_2_9
- Docker_2_10
- Docker_2_11
- Docker_2_12
- Docker_2_13
- Docker_community_devel
- Cloud_devel
- Cloud_2_9
- Cloud_2_10
- Cloud_2_11
- Cloud_2_12
- Cloud_2_13
jobs:
- template: templates/coverage.yml

33
.github/BOTMETA.yml vendored
View File

@@ -118,6 +118,8 @@ files:
$doc_fragments/xenserver.py:
maintainers: bvitnik
labels: xenserver
$filters/counter.py:
maintainers: keilr
$filters/dict.py:
maintainers: felixfontein
$filters/dict_kv.py:
@@ -164,9 +166,9 @@ files:
$inventories/proxmox.py:
maintainers: $team_virt ilijamt
$inventories/xen_orchestra.py:
maintainers: shinuza
maintainers: ddelnano shinuza
$inventories/icinga2.py:
maintainers: bongoeadgc6
maintainers: BongoEADGC6
$inventories/scaleway.py:
maintainers: $team_scaleway
labels: cloud scaleway
@@ -322,6 +324,10 @@ files:
$modules/cloud/misc/proxmox_kvm.py:
maintainers: helldorado
ignore: skvidal
$modules/cloud/misc/proxmox_nic.py:
maintainers: Kogelvis
$modules/cloud/misc/proxmox_tasks_info:
maintainers: paginabianca
$modules/cloud/misc/proxmox_template.py:
maintainers: UnderGreen
ignore: skvidal
@@ -412,6 +418,8 @@ files:
maintainers: Spredzy
$modules/cloud/scaleway/scaleway_organization_info.py:
maintainers: Spredzy
$modules/cloud/scaleway/scaleway_private_network.py:
maintainers: pastral
$modules/cloud/scaleway/scaleway_security_group.py:
maintainers: DenBeke
$modules/cloud/scaleway/scaleway_security_group_info.py:
@@ -534,6 +542,8 @@ files:
maintainers: adamgoossens
$modules/identity/keycloak/keycloak_identity_provider.py:
maintainers: laurpaum
$modules/identity/keycloak/keycloak_realm_info.py:
maintainers: fynncfchen
$modules/identity/keycloak/keycloak_realm.py:
maintainers: kris2kris
$modules/identity/keycloak/keycloak_role.py:
@@ -722,6 +732,8 @@ files:
maintainers: mwarkentin
$modules/packaging/language/bundler.py:
maintainers: thoiberg
$modules/packaging/language/cargo.py:
maintainers: radek-sprta
$modules/packaging/language/composer.py:
maintainers: dmtrs
ignore: resmo
@@ -809,7 +821,7 @@ files:
$modules/packaging/os/opkg.py:
maintainers: skinp
$modules/packaging/os/pacman.py:
maintainers: elasticdog indrajitr tchernomax
maintainers: elasticdog indrajitr tchernomax jraby
labels: pacman
ignore: elasticdog
$modules/packaging/os/pacman_key.py:
@@ -903,6 +915,10 @@ files:
$modules/remote_management/manageiq/:
labels: manageiq
maintainers: $team_manageiq
$modules/remote_management/manageiq/manageiq_alert_profiles.py:
maintainers: elad661
$modules/remote_management/manageiq/manageiq_alerts.py:
maintainers: elad661
$modules/remote_management/manageiq/manageiq_group.py:
maintainers: evertmulder
$modules/remote_management/manageiq/manageiq_tenant.py:
@@ -963,6 +979,8 @@ files:
maintainers: farhan7500 gautamphegde
$modules/storage/ibm/:
maintainers: tzure
$modules/storage/pmem/pmem.py:
maintainers: mizumm
$modules/storage/vexata/:
maintainers: vexata
$modules/storage/zfs/:
@@ -1008,6 +1026,8 @@ files:
$modules/system/gconftool2.py:
maintainers: Akasurde kevensen
labels: gconftool2
$modules/system/homectl.py:
maintainers: jameslivulpi
$modules/system/interfaces_file.py:
maintainers: obourdon hryamzik
labels: interfaces_file
@@ -1090,6 +1110,8 @@ files:
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
$modules/system/ssh_config.py:
maintainers: gaqzi Akasurde
$modules/system/sudoers.py:
maintainers: JonEllis
$modules/system/svc.py:
maintainers: bcoca
$modules/system/syspatch.py:
@@ -1146,7 +1168,8 @@ files:
$modules/web_infrastructure/jenkins_script.py:
maintainers: hogarthj
$modules/web_infrastructure/jira.py:
maintainers: Slezhuk tarka pertoft DWSR
maintainers: Slezhuk tarka pertoft
ignore: DWSR
labels: jira
$modules/web_infrastructure/nginx_status_info.py:
maintainers: resmo
@@ -1215,7 +1238,7 @@ macros:
team_cyberark_conjur: jvanderhoof ryanprior
team_e_spirit: MatrixCrawler getjack
team_flatpak: JayKayy oolongbrothers
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
team_hpux: bcoca davx8342
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
team_ipa: Akasurde Nosmoht fxfitz justchris1

View File

@@ -6,6 +6,284 @@ Community General Release Notes
This changelog describes changes after version 3.0.0.
v4.7.0
======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
- ipa_service - add ``skip_host_check`` parameter. (https://github.com/ansible-collections/community.general/pull/4417).
- keycloak_client - add ``always_display_in_console`` parameter (https://github.com/ansible-collections/community.general/issues/4390).
- keycloak_client - add ``default_client_scopes`` and ``optional_client_scopes`` parameters. (https://github.com/ansible-collections/community.general/pull/4385).
- proxmox inventory plugin - add support for templating the ``url``, ``user``, and ``password`` options (https://github.com/ansible-collections/community.general/pull/4418).
- sudoers - add support for ``runas`` parameter (https://github.com/ansible-collections/community.general/issues/4379).
Bugfixes
--------
- dsv lookup plugin - raise an Ansible error if the wrong ``python-dsv-sdk`` version is installed (https://github.com/ansible-collections/community.general/pull/4422).
- keycloak_* - the documented ``validate_certs`` parameter was not taken into account when calling the ``open_url`` function in some cases, thus enforcing certificate validation even when ``validate_certs`` was set to ``false``. (https://github.com/ansible-collections/community.general/pull/4382)
- nmcli - fix returning "changed" when routes parameters set, also suggest new routes4 and routes6 format (https://github.com/ansible-collections/community.general/issues/4131).
- proxmox inventory plugin - fixed the ``tags_parsed`` field when Proxmox returns a single space for the ``tags`` entry (https://github.com/ansible-collections/community.general/pull/4378).
- zypper - fixed bug that caused zypper to always report [ok] and do nothing on ``state=present`` when all packages in ``name`` had a version specification (https://github.com/ansible-collections/community.general/issues/4371, https://github.com/ansible-collections/community.general/pull/4421).
v4.6.1
======
Release Summary
---------------
Extraordinary bugfix release to fix a breaking change in ``terraform``.
Bugfixes
--------
- lxd inventory plugin - do not crash if OS and release metadata are not present
(https://github.com/ansible-collections/community.general/pull/4351).
- terraform - revert bugfix https://github.com/ansible-collections/community.general/pull/4281 that tried to fix ``variable`` handling to allow complex values. It turned out that this was breaking several valid use-cases (https://github.com/ansible-collections/community.general/issues/4367, https://github.com/ansible-collections/community.general/pull/4370).
v4.6.0
======
Release Summary
---------------
Regular feature and bugfix release.
Minor Changes
-------------
- jira - when creating a comment, ``fields`` now is used for additional data (https://github.com/ansible-collections/community.general/pull/4304).
- ldap_entry - add support for recursive deletion (https://github.com/ansible-collections/community.general/issues/3613).
- mksysb - revamped the module using ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/3295).
- nmcli - add missing connection aliases ``802-3-ethernet`` and ``802-11-wireless`` (https://github.com/ansible-collections/community.general/pull/4108).
- nmcli - remove nmcli modify dependency on ``type`` parameter (https://github.com/ansible-collections/community.general/issues/2858).
- npm - add ability to use ``production`` flag when ``ci`` is set (https://github.com/ansible-collections/community.general/pull/4299).
- pacman - add ``remove_nosave`` parameter to avoid saving modified configuration files as ``.pacsave`` files. (https://github.com/ansible-collections/community.general/pull/4316, https://github.com/ansible-collections/community.general/issues/4315).
- pacman - now implements proper change detection for ``update_cache=true``. Adds ``cache_updated`` return value to when ``update_cache=true`` to report this result independently of the module's overall changed return value (https://github.com/ansible-collections/community.general/pull/4337).
- pipx - added options ``editable`` and ``pip_args`` (https://github.com/ansible-collections/community.general/issues/4300).
- proxmox inventory plugin - add support for client-side jinja filters (https://github.com/ansible-collections/community.general/issues/3553).
- redis - add authentication parameters ``login_user``, ``tls``, ``validate_certs``, and ``ca_certs`` (https://github.com/ansible-collections/community.general/pull/4207).
- syslog_json - add option to skip logging of ``gather_facts`` playbook tasks; use v2 callback API (https://github.com/ansible-collections/community.general/pull/4223).
- zypper - add support for ``--clean-deps`` option to remove packages that depend on a package being removed (https://github.com/ansible-collections/community.general/pull/4195).
Deprecated Features
-------------------
- pacman - from community.general 5.0.0 on, the ``changed`` status of ``update_cache`` will no longer be ignored if ``name`` or ``upgrade`` is specified. To keep the old behavior, add something like ``register: result`` and ``changed_when: result.packages | length > 0`` to your task (https://github.com/ansible-collections/community.general/pull/4329).
Bugfixes
--------
- filesize - add support for busybox dd implementation, that is used by default on Alpine linux (https://github.com/ansible-collections/community.general/pull/4288, https://github.com/ansible-collections/community.general/issues/4259).
- linode inventory plugin - fix configuration handling relating to inventory filtering (https://github.com/ansible-collections/community.general/pull/4336).
- mksysb - fixed bug for parameter ``backup_dmapi_fs`` was passing the wrong CLI argument (https://github.com/ansible-collections/community.general/pull/3295).
- pacman - Use ``--groups`` instead of ``--group`` (https://github.com/ansible-collections/community.general/pull/4312).
- pacman - fix URL based package installation (https://github.com/ansible-collections/community.general/pull/4286, https://github.com/ansible-collections/community.general/issues/4285).
- pacman - fix ``upgrade=yes`` (https://github.com/ansible-collections/community.general/pull/4275, https://github.com/ansible-collections/community.general/issues/4274).
- pacman - make sure that ``packages`` is always returned when ``name`` or ``upgrade`` is specified, also if nothing is done (https://github.com/ansible-collections/community.general/pull/4329).
- pacman - when the ``update_cache`` option is combined with another option such as ``upgrade``, report ``changed`` based on the actions performed by the latter option. This was the behavior in community.general 4.4.0 and before. In community.general 4.5.0, a task combining these options would always report ``changed`` (https://github.com/ansible-collections/community.general/pull/4318).
- proxmox inventory plugin - always convert strings that follow the ``key=value[,key=value[...]]`` form into dictionaries (https://github.com/ansible-collections/community.general/pull/4349).
- proxmox inventory plugin - fixed the ``description`` field being ignored if it contained a comma (https://github.com/ansible-collections/community.general/issues/4348).
- proxmox_kvm - fix error in check when creating or cloning (https://github.com/ansible-collections/community.general/pull/4306).
- proxmox_kvm - fix error when checking whether Proxmox VM exists (https://github.com/ansible-collections/community.general/pull/4287).
- terraform - fix ``variable`` handling to allow complex values (https://github.com/ansible-collections/community.general/pull/4281).
Known Issues
------------
- pacman - ``update_cache`` cannot differentiate between up to date and outdated package lists and will report ``changed`` in both situations (https://github.com/ansible-collections/community.general/pull/4318).
- pacman - binaries specified in the ``executable`` parameter must support ``--print-format`` in order to be used by this module. In particular, AUR helper ``yay`` is known not to currently support it (https://github.com/ansible-collections/community.general/pull/4312).
v4.5.0
======
Release Summary
---------------
Regular feature and bugfix release.
Minor Changes
-------------
- Avoid internal ansible-core module_utils in favor of equivalent public API available since at least Ansible 2.9. This fixes some instances added since the last time this was fixed (https://github.com/ansible-collections/community.general/pull/4232).
- ansible_galaxy_install - added option ``no_deps`` to the module (https://github.com/ansible-collections/community.general/issues/4174).
- gitlab_group_variable - new ``variables`` parameter (https://github.com/ansible-collections/community.general/pull/4038 and https://github.com/ansible-collections/community.general/issues/4074).
- keycloak_* modules - added connection timeout parameter when calling server (https://github.com/ansible-collections/community.general/pull/4168).
- linode inventory plugin - add support for caching inventory results (https://github.com/ansible-collections/community.general/pull/4179).
- opentelemetry_plugin - enrich service when using the ``jenkins``, ``hetzner`` or ``jira`` modules (https://github.com/ansible-collections/community.general/pull/4105).
- pacman - the module has been rewritten and is now much faster when using ``state=latest``. Operations are now done all packages at once instead of package per package and the configured output format of ``pacman`` no longer affect the module's operation. (https://github.com/ansible-collections/community.general/pull/3907, https://github.com/ansible-collections/community.general/issues/3783, https://github.com/ansible-collections/community.general/issues/4079)
- passwordstore lookup plugin - add configurable ``lock`` and ``locktimeout`` options to avoid race conditions in itself and in the ``pass`` utility it calls. By default, the plugin now locks on write operations (https://github.com/ansible-collections/community.general/pull/4194).
- proxmox modules - move common code into ``module_utils`` (https://github.com/ansible-collections/community.general/pull/4029).
- proxmox_kvm - added EFI disk support when creating VM with OVMF UEFI BIOS with new ``efidisk0`` option (https://github.com/ansible-collections/community.general/pull/4106, https://github.com/ansible-collections/community.general/issues/1638).
- proxmox_kwm - add ``win11`` to ``ostype`` parameter for Windows 11 and Windows Server 2022 support (https://github.com/ansible-collections/community.general/issues/4023, https://github.com/ansible-collections/community.general/pull/4191).
Bugfixes
--------
- dconf - skip processes that disappeared while we inspected them (https://github.com/ansible-collections/community.general/issues/4151).
- gitlab_group_variable - add missing documentation about GitLab versions that support ``environment_scope`` and ``variable_type`` (https://github.com/ansible-collections/community.general/pull/4038).
- gitlab_group_variable - allow to set same variable name under different environment scopes. Due this change, the return value ``group_variable`` differs from previous version in check mode. It was counting ``updated`` values, because it was accidentally overwriting environment scopes (https://github.com/ansible-collections/community.general/pull/4038).
- gitlab_group_variable - fix idempotent change behaviour for float and integer variables (https://github.com/ansible-collections/community.general/pull/4038).
- gitlab_project_variable - ``value`` is not necessary when deleting variables (https://github.com/ansible-collections/community.general/pull/4150).
- gitlab_runner - make ``project`` and ``owned`` mutually exclusive (https://github.com/ansible-collections/community.general/pull/4136).
- homebrew_cask - fix force install operation (https://github.com/ansible-collections/community.general/issues/3703).
- imc_rest - fixes the module failure due to the usage of ``itertools.izip_longest`` which is not available in Python 3 (https://github.com/ansible-collections/community.general/issues/4206).
- ini_file - when removing nothing do not report changed (https://github.com/ansible-collections/community.general/issues/4154).
- keycloak_user_federation - creating a user federation while specifying an ID (that does not exist yet) no longer fail with a 404 Not Found (https://github.com/ansible-collections/community.general/pull/4212).
- keycloak_user_federation - mappers auto-created by keycloak are matched and merged by their name and no longer create duplicated entries (https://github.com/ansible-collections/community.general/pull/4212).
- mail callback plugin - fix encoding of the name of sender and recipient (https://github.com/ansible-collections/community.general/issues/4060, https://github.com/ansible-collections/community.general/pull/4061).
- passwordstore lookup plugin - fix error detection for non-English locales (https://github.com/ansible-collections/community.general/pull/4219).
- passwordstore lookup plugin - prevent returning path names as passwords by accident (https://github.com/ansible-collections/community.general/issues/4185, https://github.com/ansible-collections/community.general/pull/4192).
- vdo - fix options error (https://github.com/ansible-collections/community.general/pull/4163).
- yum_versionlock - fix matching of existing entries with names passed to the module. Match yum and dnf lock format (https://github.com/ansible-collections/community.general/pull/4183).
New Modules
-----------
Cloud
~~~~~
scaleway
^^^^^^^^
- scaleway_private_network - Scaleway private network management
Storage
~~~~~~~
pmem
^^^^
- pmem - Configure Intel Optane Persistent Memory modules
v4.4.0
======
Release Summary
---------------
Regular features and bugfixes release.
Minor Changes
-------------
- cobbler inventory plugin - add ``include_profiles`` option (https://github.com/ansible-collections/community.general/pull/4068).
- gitlab_project_variable - new ``variables`` parameter (https://github.com/ansible-collections/community.general/issues/4038).
- icinga2 inventory plugin - implemented constructed interface (https://github.com/ansible-collections/community.general/pull/4088).
- linode inventory plugin - allow templating of ``access_token`` variable in Linode inventory plugin (https://github.com/ansible-collections/community.general/pull/4040).
- lists_mergeby filter plugin - add parameters ``list_merge`` and ``recursive``. These are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9 (https://github.com/ansible-collections/community.general/pull/4058).
- lxc_container - added ``wait_for_container`` parameter. If ``true`` the module will wait until the running task reports success as the status (https://github.com/ansible-collections/community.general/pull/4039).
- mail callback plugin - add ``Message-ID`` and ``Date`` headers (https://github.com/ansible-collections/community.general/issues/4055, https://github.com/ansible-collections/community.general/pull/4056).
- mail callback plugin - properly use Ansible's option handling to split lists (https://github.com/ansible-collections/community.general/pull/4140).
- nmcli - adds ``routes6`` and ``route_metric6`` parameters for supporting IPv6 routes (https://github.com/ansible-collections/community.general/issues/4059).
- opennebula - add the release action for VMs in the ``HOLD`` state (https://github.com/ansible-collections/community.general/pull/4036).
- opentelemetry_plugin - enrich service when using the ``docker_login`` (https://github.com/ansible-collections/community.general/pull/4104).
- proxmox modules - move ``HAS_PROXMOXER`` check into ``module_utils`` (https://github.com/ansible-collections/community.general/pull/4030).
- scaleway inventory plugin - add profile parameter ``scw_profile`` (https://github.com/ansible-collections/community.general/pull/4049).
- snap - add option ``options`` permitting to set options using the ``snap set`` command (https://github.com/ansible-collections/community.general/pull/3943).
Deprecated Features
-------------------
- mail callback plugin - not specifying ``sender`` is deprecated and will be disallowed in community.general 6.0.0 (https://github.com/ansible-collections/community.general/pull/4140).
Bugfixes
--------
- cargo - fix detection of outdated packages when ``state=latest`` (https://github.com/ansible-collections/community.general/pull/4052).
- cargo - fix incorrectly reported changed status for packages with a name containing a hyphen (https://github.com/ansible-collections/community.general/issues/4044, https://github.com/ansible-collections/community.general/pull/4052).
- gitlab_project_variable - add missing documentation about GitLab versions that support ``environment_scope`` and ``variable_type`` (https://github.com/ansible-collections/community.general/issues/4038).
- gitlab_project_variable - allow to set same variable name under different environment scopes. Due this change, the return value ``project_variable`` differs from previous version in check mode. It was counting ``updated`` values, because it was accidentally overwriting environment scopes (https://github.com/ansible-collections/community.general/issues/4038).
- gitlab_project_variable - fix idempotent change behaviour for float and integer variables (https://github.com/ansible-collections/community.general/issues/4038).
- gitlab_runner - use correct API endpoint to create and retrieve project level runners when using ``project`` (https://github.com/ansible-collections/community.general/pull/3965).
- listen_ports_facts - local port regex was not handling well IPv6 only binding. Fixes the regex for ``ss`` (https://github.com/ansible-collections/community.general/pull/4092).
- mail callback plugin - fix crash on Python 3 (https://github.com/ansible-collections/community.general/issues/4025, https://github.com/ansible-collections/community.general/pull/4026).
- opentelemetry - fix generating a trace with a task containing ``no_log: true`` (https://github.com/ansible-collections/community.general/pull/4043).
- python_requirements_info - store ``mismatched`` return values per package as documented in the module (https://github.com/ansible-collections/community.general/pull/4078).
- yarn - fix incorrect handling of ``yarn list`` and ``yarn global list`` output that could result in fatal error (https://github.com/ansible-collections/community.general/pull/4050).
- yarn - fix incorrectly reported status when installing a package globally (https://github.com/ansible-collections/community.general/issues/4045, https://github.com/ansible-collections/community.general/pull/4050).
- yarn - fix missing ``~`` expansion in yarn global install folder which resulted in incorrect task status (https://github.com/ansible-collections/community.general/issues/4045, https://github.com/ansible-collections/community.general/pull/4048).
New Modules
-----------
System
~~~~~~
- homectl - Manage user accounts with systemd-homed
v4.3.0
======
Release Summary
---------------
Regular feature and bugfix release.
Minor Changes
-------------
- ipa_dnszone - ``dynamicupdate`` is now a boolean parameter, instead of a string parameter accepting ``"true"`` and ``"false"``. Also the module is now idempotent with respect to ``dynamicupdate`` (https://github.com/ansible-collections/community.general/pull/3374).
- ipa_dnszone - add DNS zone synchronization support (https://github.com/ansible-collections/community.general/pull/3374).
- ipmi_power - add ``machine`` option to ensure the power state via the remote target address (https://github.com/ansible-collections/community.general/pull/3968).
- mattermost - add the possibility to send attachments instead of text messages (https://github.com/ansible-collections/community.general/pull/3946).
- nmcli - add ``wireguard`` connection type (https://github.com/ansible-collections/community.general/pull/3985).
- proxmox - add ``clone`` parameter (https://github.com/ansible-collections/community.general/pull/3930).
- puppet - remove deprecation for ``show_diff`` parameter. Its alias ``show-diff`` is still deprecated and will be removed in community.general 7.0.0 (https://github.com/ansible-collections/community.general/pull/3980).
- scaleway_compute - add possibility to use project identifier (new ``project`` option) instead of deprecated organization identifier (https://github.com/ansible-collections/community.general/pull/3951).
- scaleway_volume - all volumes are systematically created on par1 (https://github.com/ansible-collections/community.general/pull/3964).
Bugfixes
--------
- Various modules and plugins - use vendored version of ``distutils.version`` instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.general/pull/3936).
- alternatives - fix output parsing for alternatives groups (https://github.com/ansible-collections/community.general/pull/3976).
- jail connection plugin - replace deprecated ``distutils.spawn.find_executable`` with Ansible's ``get_bin_path`` to find the executable (https://github.com/ansible-collections/community.general/pull/3934).
- lxd connection plugin - replace deprecated ``distutils.spawn.find_executable`` with Ansible's ``get_bin_path`` to find the ``lxc`` executable (https://github.com/ansible-collections/community.general/pull/3934).
- passwordstore lookup plugin - replace deprecated ``distutils.util.strtobool`` with Ansible's ``convert_bool.boolean`` to interpret values for the ``create``, ``returnall``, ``overwrite``, 'backup``, and ``nosymbols`` options (https://github.com/ansible-collections/community.general/pull/3934).
- say callback plugin - replace deprecated ``distutils.spawn.find_executable`` with Ansible's ``get_bin_path`` to find the ``say`` resp. ``espeak`` executables (https://github.com/ansible-collections/community.general/pull/3934).
- scaleway_user_data - fix double-quote added where no double-quote is needed to user data in scaleway's server (``Content-type`` -> ``Content-Type``) (https://github.com/ansible-collections/community.general/pull/3940).
- slack - add ``charset`` to HTTP headers to avoid Slack API warning (https://github.com/ansible-collections/community.general/issues/3932).
- zone connection plugin - replace deprecated ``distutils.spawn.find_executable`` with Ansible's ``get_bin_path`` to find the executable (https://github.com/ansible-collections/community.general/pull/3934).
New Plugins
-----------
Filter
~~~~~~
- counter - Counts hashable elements in a sequence
New Modules
-----------
Identity
~~~~~~~~
keycloak
^^^^^^^^
- keycloak_realm_info - Allows obtaining Keycloak realm public information via Keycloak API
Packaging
~~~~~~~~~
language
^^^^^^^^
- cargo - Manage Rust packages with cargo
System
~~~~~~
- sudoers - Manage sudoers files
v4.2.0
======

View File

@@ -24,7 +24,7 @@ Also, consider taking up a valuable, reviewed, but abandoned pull request which
* Try committing your changes with an informative but short commit message.
* Do not squash your commits and force-push to your branch if not needed. Reviews of your pull request are much easier with individual commits to comprehend the pull request history. All commits of your pull request branch will be squashed into one commit by GitHub upon merge.
* Do not add merge commits to your PR. The bot will complain and you will have to rebase ([instructions for rebasing](https://docs.ansible.com/ansible/latest/dev_guide/developing_rebasing.html)) to remove them before your PR can be merged. To avoid that git automatically does merges during pulls, you can configure it to do rebases instead by running `git config pull.rebase true` inside the respository checkout.
* Do not add merge commits to your PR. The bot will complain and you will have to rebase ([instructions for rebasing](https://docs.ansible.com/ansible/latest/dev_guide/developing_rebasing.html)) to remove them before your PR can be merged. To avoid that git automatically does merges during pulls, you can configure it to do rebases instead by running `git config pull.rebase true` inside the repository checkout.
* Make sure your PR includes a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs-how-to). (You must not include a fragment for new modules or new plugins, except for test and filter plugins. Also you shouldn't include one for docs-only changes. If you're not sure, simply don't include one, we'll tell you whether one is needed or not :) )
* Avoid reformatting unrelated parts of the codebase in your PR. These types of changes will likely be requested for reversion, create additional work for reviewers, and may cause approval to be delayed.
@@ -36,6 +36,54 @@ If you want to test a PR locally, refer to [our testing guide](https://github.co
If you find any inconsistencies or places in this document which can be improved, feel free to raise an issue or pull request to fix it.
## Run sanity, unit or integration tests locally
You have to check out the repository into a specific path structure to be able to run `ansible-test`. The path to the git checkout must end with `.../ansible_collections/community/general`. Please see [our testing guide](https://github.com/ansible/community-docs/blob/main/test_pr_locally_guide.rst) for instructions on how to check out the repository into a correct path structure. The short version of these instructions is:
```.bash
mkdir -p ~/dev/ansible_collections/community
git clone https://github.com/ansible-collections/community.general.git ~/dev/ansible_collections/community/general
cd ~/dev/ansible_collections/community/general
```
Then you can run `ansible-test` (which is a part of [ansible-core](https://pypi.org/project/ansible-core/)) inside the checkout. The following example commands expect that you have installed Docker or Podman. Note that Podman has only been supported by more recent ansible-core releases. If you are using Docker, the following will work with Ansible 2.9+.
The following commands show how to run sanity tests:
```.bash
# Run sanity tests for all files in the collection:
ansible-test sanity --docker -v
# Run sanity tests for the given files and directories:
ansible-test sanity --docker -v plugins/modules/system/pids.py tests/integration/targets/pids/
```
The following commands show how to run unit tests:
```.bash
# Run all unit tests:
ansible-test units --docker -v
# Run all unit tests for one Python version (a lot faster):
ansible-test units --docker -v --python 3.8
# Run a specific unit test (for the nmcli module) for one Python version:
ansible-test units --docker -v --python 3.8 tests/unit/plugins/modules/net_tools/test_nmcli.py
```
The following commands show how to run integration tests:
```.bash
# Run integration tests for the interfaces_files module in a Docker container using the
# fedora35 operating system image (the supported images depend on your ansible-core version):
ansible-test integration --docker fedora35 -v interfaces_file
# Run integration tests for the flattened lookup **without any isolation**:
ansible-test integration -v lookup_flattened
```
If you are unsure about the integration test target name for a module or plugin, you can take a look in `tests/integration/targets/`. Tests for plugins have the plugin type prepended.
## Creating new modules or plugins
Creating new modules and plugins requires a bit more work than other Pull Requests.

View File

@@ -17,7 +17,7 @@ If you encounter abusive behavior violating the [Ansible Code of Conduct](https:
## Tested with Ansible
Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
Tested with the current Ansible 2.9, ansible-base 2.10, ansible-core 2.11, ansible-core 2.12, ansible-core 2.13 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
## External requirements

View File

@@ -1238,3 +1238,406 @@ releases:
name: ilo_redfish_info
namespace: remote_management.redfish
release_date: '2021-12-21'
4.3.0:
changes:
bugfixes:
- Various modules and plugins - use vendored version of ``distutils.version``
instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.general/pull/3936).
- alternatives - fix output parsing for alternatives groups (https://github.com/ansible-collections/community.general/pull/3976).
- jail connection plugin - replace deprecated ``distutils.spawn.find_executable``
with Ansible's ``get_bin_path`` to find the executable (https://github.com/ansible-collections/community.general/pull/3934).
- lxd connection plugin - replace deprecated ``distutils.spawn.find_executable``
with Ansible's ``get_bin_path`` to find the ``lxc`` executable (https://github.com/ansible-collections/community.general/pull/3934).
- passwordstore lookup plugin - replace deprecated ``distutils.util.strtobool``
with Ansible's ``convert_bool.boolean`` to interpret values for the ``create``,
``returnall``, ``overwrite``, 'backup``, and ``nosymbols`` options (https://github.com/ansible-collections/community.general/pull/3934).
- say callback plugin - replace deprecated ``distutils.spawn.find_executable``
with Ansible's ``get_bin_path`` to find the ``say`` resp. ``espeak`` executables
(https://github.com/ansible-collections/community.general/pull/3934).
- scaleway_user_data - fix double-quote added where no double-quote is needed
to user data in scaleway's server (``Content-type`` -> ``Content-Type``) (https://github.com/ansible-collections/community.general/pull/3940).
- slack - add ``charset`` to HTTP headers to avoid Slack API warning (https://github.com/ansible-collections/community.general/issues/3932).
- zone connection plugin - replace deprecated ``distutils.spawn.find_executable``
with Ansible's ``get_bin_path`` to find the executable (https://github.com/ansible-collections/community.general/pull/3934).
minor_changes:
- ipa_dnszone - ``dynamicupdate`` is now a boolean parameter, instead of a string
parameter accepting ``"true"`` and ``"false"``. Also the module is now idempotent
with respect to ``dynamicupdate`` (https://github.com/ansible-collections/community.general/pull/3374).
- ipa_dnszone - add DNS zone synchronization support (https://github.com/ansible-collections/community.general/pull/3374).
- ipmi_power - add ``machine`` option to ensure the power state via the remote
target address (https://github.com/ansible-collections/community.general/pull/3968).
- mattermost - add the possibility to send attachments instead of text messages
(https://github.com/ansible-collections/community.general/pull/3946).
- nmcli - add ``wireguard`` connection type (https://github.com/ansible-collections/community.general/pull/3985).
- proxmox - add ``clone`` parameter (https://github.com/ansible-collections/community.general/pull/3930).
- puppet - remove deprecation for ``show_diff`` parameter. Its alias ``show-diff``
is still deprecated and will be removed in community.general 7.0.0 (https://github.com/ansible-collections/community.general/pull/3980).
- scaleway_compute - add possibility to use project identifier (new ``project``
option) instead of deprecated organization identifier (https://github.com/ansible-collections/community.general/pull/3951).
- scaleway_volume - all volumes are systematically created on par1 (https://github.com/ansible-collections/community.general/pull/3964).
release_summary: Regular feature and bugfix release.
fragments:
- 3374-add-ipa-ptr-sync-support.yml
- 3921-add-counter-filter-plugin.yml
- 3930-proxmox-add-clone.yaml
- 3933-slack-charset-header.yaml
- 3934-distutils.yml
- 3936-distutils.version.yml
- 3940_fix_contenttype_scaleway_user_data.yml
- 3946-mattermost_attachments.yml
- 3951-scaleway_compute_add_project_id.yml
- 3964-scaleway_volume_add_region.yml
- 3968-ipmi_power-add-machine-option.yaml
- 3976-fix-alternatives-parsing.yml
- 3980-puppet-show_diff.yml
- 3985-nmcli-add-wireguard-connection-type.yml
- 4.3.0.yml
modules:
- description: Manage Rust packages with cargo
name: cargo
namespace: packaging.language
- description: Allows obtaining Keycloak realm public information via Keycloak
API
name: keycloak_realm_info
namespace: identity.keycloak
- description: Manage sudoers files
name: sudoers
namespace: system
plugins:
filter:
- description: Counts hashable elements in a sequence
name: counter
namespace: null
release_date: '2022-01-11'
4.4.0:
changes:
bugfixes:
- cargo - fix detection of outdated packages when ``state=latest`` (https://github.com/ansible-collections/community.general/pull/4052).
- cargo - fix incorrectly reported changed status for packages with a name containing
a hyphen (https://github.com/ansible-collections/community.general/issues/4044,
https://github.com/ansible-collections/community.general/pull/4052).
- gitlab_project_variable - add missing documentation about GitLab versions
that support ``environment_scope`` and ``variable_type`` (https://github.com/ansible-collections/community.general/issues/4038).
- 'gitlab_project_variable - allow to set same variable name under different
environment scopes. Due this change, the return value ``project_variable``
differs from previous version in check mode. It was counting ``updated`` values,
because it was accidentally overwriting environment scopes (https://github.com/ansible-collections/community.general/issues/4038).
'
- gitlab_project_variable - fix idempotent change behaviour for float and integer
variables (https://github.com/ansible-collections/community.general/issues/4038).
- gitlab_runner - use correct API endpoint to create and retrieve project level
runners when using ``project`` (https://github.com/ansible-collections/community.general/pull/3965).
- listen_ports_facts - local port regex was not handling well IPv6 only binding.
Fixes the regex for ``ss`` (https://github.com/ansible-collections/community.general/pull/4092).
- mail callback plugin - fix crash on Python 3 (https://github.com/ansible-collections/community.general/issues/4025,
https://github.com/ansible-collections/community.general/pull/4026).
- 'opentelemetry - fix generating a trace with a task containing ``no_log: true``
(https://github.com/ansible-collections/community.general/pull/4043).'
- python_requirements_info - store ``mismatched`` return values per package
as documented in the module (https://github.com/ansible-collections/community.general/pull/4078).
- yarn - fix incorrect handling of ``yarn list`` and ``yarn global list`` output
that could result in fatal error (https://github.com/ansible-collections/community.general/pull/4050).
- yarn - fix incorrectly reported status when installing a package globally
(https://github.com/ansible-collections/community.general/issues/4045, https://github.com/ansible-collections/community.general/pull/4050).
- yarn - fix missing ``~`` expansion in yarn global install folder which resulted
in incorrect task status (https://github.com/ansible-collections/community.general/issues/4045,
https://github.com/ansible-collections/community.general/pull/4048).
deprecated_features:
- mail callback plugin - not specifying ``sender`` is deprecated and will be
disallowed in community.general 6.0.0 (https://github.com/ansible-collections/community.general/pull/4140).
minor_changes:
- cobbler inventory plugin - add ``include_profiles`` option (https://github.com/ansible-collections/community.general/pull/4068).
- gitlab_project_variable - new ``variables`` parameter (https://github.com/ansible-collections/community.general/issues/4038).
- icinga2 inventory plugin - implemented constructed interface (https://github.com/ansible-collections/community.general/pull/4088).
- linode inventory plugin - allow templating of ``access_token`` variable in
Linode inventory plugin (https://github.com/ansible-collections/community.general/pull/4040).
- lists_mergeby filter plugin - add parameters ``list_merge`` and ``recursive``.
These are only supported when used with ansible-base 2.10 or ansible-core,
but not with Ansible 2.9 (https://github.com/ansible-collections/community.general/pull/4058).
- lxc_container - added ``wait_for_container`` parameter. If ``true`` the module
will wait until the running task reports success as the status (https://github.com/ansible-collections/community.general/pull/4039).
- mail callback plugin - add ``Message-ID`` and ``Date`` headers (https://github.com/ansible-collections/community.general/issues/4055,
https://github.com/ansible-collections/community.general/pull/4056).
- mail callback plugin - properly use Ansible's option handling to split lists
(https://github.com/ansible-collections/community.general/pull/4140).
- nmcli - adds ``routes6`` and ``route_metric6`` parameters for supporting IPv6
routes (https://github.com/ansible-collections/community.general/issues/4059).
- opennebula - add the release action for VMs in the ``HOLD`` state (https://github.com/ansible-collections/community.general/pull/4036).
- opentelemetry_plugin - enrich service when using the ``docker_login`` (https://github.com/ansible-collections/community.general/pull/4104).
- proxmox modules - move ``HAS_PROXMOXER`` check into ``module_utils`` (https://github.com/ansible-collections/community.general/pull/4030).
- scaleway inventory plugin - add profile parameter ``scw_profile`` (https://github.com/ansible-collections/community.general/pull/4049).
- snap - add option ``options`` permitting to set options using the ``snap set``
command (https://github.com/ansible-collections/community.general/pull/3943).
release_summary: Regular features and bugfixes release.
fragments:
- 3935-use-gitlab-instance-runner-to-create-runner.yml
- 3943-add-option-options-to-snap-module.yml
- 4.4.0.yml
- 4026-fix-mail-callback.yml
- 4030-proxmox-has-proxmoxer.yml
- 4036-onevm-add-release-action.yaml
- 4038-fix-and-rework-gitlb-project-variable.yml
- 4039-cluster-container-wait.yml
- 4040-linode-token-templating.yaml
- 4043-fix-no-log-opentelemetry.yml
- 4048-expand-tilde-in-yarn-global-install-folder.yaml
- 4049-profile-for-scaleway-inventory.yml
- 4050-properly-parse-json-lines-output-from-yarn.yaml
- 4052-fix-detection-of-installed-cargo-packages-with-hyphens.yaml
- 4056-add-missing-mail-headers.yml
- 4058-lists_mergeby-add-parameters.yml
- 4062-nmcli-ipv6-routes-support.yml
- 4068-add-include_file-option.yml
- 4078-python_requirements_info.yaml
- 4088-add-constructed-interface-for-icinga2-inventory.yml
- 4092-fix_local_ports_regex_listen_ports_facts.yaml
- 4104-opentelemetry_plugin-enrich_docker_login.yaml
- 4140-mail-callback-options.yml
modules:
- description: Manage user accounts with systemd-homed
name: homectl
namespace: system
release_date: '2022-02-01'
4.5.0:
changes:
bugfixes:
- dconf - skip processes that disappeared while we inspected them (https://github.com/ansible-collections/community.general/issues/4151).
- gitlab_group_variable - add missing documentation about GitLab versions that
support ``environment_scope`` and ``variable_type`` (https://github.com/ansible-collections/community.general/pull/4038).
- 'gitlab_group_variable - allow to set same variable name under different environment
scopes. Due this change, the return value ``group_variable`` differs from
previous version in check mode. It was counting ``updated`` values, because
it was accidentally overwriting environment scopes (https://github.com/ansible-collections/community.general/pull/4038).
'
- gitlab_group_variable - fix idempotent change behaviour for float and integer
variables (https://github.com/ansible-collections/community.general/pull/4038).
- gitlab_project_variable - ``value`` is not necessary when deleting variables
(https://github.com/ansible-collections/community.general/pull/4150).
- gitlab_runner - make ``project`` and ``owned`` mutually exclusive (https://github.com/ansible-collections/community.general/pull/4136).
- homebrew_cask - fix force install operation (https://github.com/ansible-collections/community.general/issues/3703).
- imc_rest - fixes the module failure due to the usage of ``itertools.izip_longest``
which is not available in Python 3 (https://github.com/ansible-collections/community.general/issues/4206).
- ini_file - when removing nothing do not report changed (https://github.com/ansible-collections/community.general/issues/4154).
- keycloak_user_federation - creating a user federation while specifying an
ID (that does not exist yet) no longer fail with a 404 Not Found (https://github.com/ansible-collections/community.general/pull/4212).
- keycloak_user_federation - mappers auto-created by keycloak are matched and
merged by their name and no longer create duplicated entries (https://github.com/ansible-collections/community.general/pull/4212).
- mail callback plugin - fix encoding of the name of sender and recipient (https://github.com/ansible-collections/community.general/issues/4060,
https://github.com/ansible-collections/community.general/pull/4061).
- passwordstore lookup plugin - fix error detection for non-English locales
(https://github.com/ansible-collections/community.general/pull/4219).
- passwordstore lookup plugin - prevent returning path names as passwords by
accident (https://github.com/ansible-collections/community.general/issues/4185,
https://github.com/ansible-collections/community.general/pull/4192).
- vdo - fix options error (https://github.com/ansible-collections/community.general/pull/4163).
- yum_versionlock - fix matching of existing entries with names passed to the
module. Match yum and dnf lock format (https://github.com/ansible-collections/community.general/pull/4183).
minor_changes:
- Avoid internal ansible-core module_utils in favor of equivalent public API
available since at least Ansible 2.9. This fixes some instances added since
the last time this was fixed (https://github.com/ansible-collections/community.general/pull/4232).
- ansible_galaxy_install - added option ``no_deps`` to the module (https://github.com/ansible-collections/community.general/issues/4174).
- gitlab_group_variable - new ``variables`` parameter (https://github.com/ansible-collections/community.general/pull/4038
and https://github.com/ansible-collections/community.general/issues/4074).
- keycloak_* modules - added connection timeout parameter when calling server
(https://github.com/ansible-collections/community.general/pull/4168).
- linode inventory plugin - add support for caching inventory results (https://github.com/ansible-collections/community.general/pull/4179).
- opentelemetry_plugin - enrich service when using the ``jenkins``, ``hetzner``
or ``jira`` modules (https://github.com/ansible-collections/community.general/pull/4105).
- pacman - the module has been rewritten and is now much faster when using ``state=latest``.
Operations are now done all packages at once instead of package per package
and the configured output format of ``pacman`` no longer affect the module's
operation. (https://github.com/ansible-collections/community.general/pull/3907,
https://github.com/ansible-collections/community.general/issues/3783, https://github.com/ansible-collections/community.general/issues/4079)
- passwordstore lookup plugin - add configurable ``lock`` and ``locktimeout``
options to avoid race conditions in itself and in the ``pass`` utility it
calls. By default, the plugin now locks on write operations (https://github.com/ansible-collections/community.general/pull/4194).
- proxmox modules - move common code into ``module_utils`` (https://github.com/ansible-collections/community.general/pull/4029).
- proxmox_kvm - added EFI disk support when creating VM with OVMF UEFI BIOS
with new ``efidisk0`` option (https://github.com/ansible-collections/community.general/pull/4106,
https://github.com/ansible-collections/community.general/issues/1638).
- proxmox_kwm - add ``win11`` to ``ostype`` parameter for Windows 11 and Windows
Server 2022 support (https://github.com/ansible-collections/community.general/issues/4023,
https://github.com/ansible-collections/community.general/pull/4191).
release_summary: Regular feature and bugfix release.
fragments:
- 3703-force-install-homebrew-cask.yml
- 3907-pacman-speedup.yml
- 3916-fix-vdo-options-type.yml
- 4.5.0.yml
- 4029-proxmox-refactor.yml
- 4061-fix-mail-recipient-encoding.yml
- 4086-rework_of_gitlab_proyect_variable_over_gitlab_group_variable.yml
- 4105-opentelemetry_plugin-enrich_jira_hetzner_jenkins_services.yaml
- 4106-proxmox-efidisk0-support.yaml
- 4136-gitlab_runner-make-project-owned-mutually-exclusive.yml
- 4150-gitlab-project-variable-absent-fix.yml
- 4151-dconf-catch-psutil-nosuchprocess.yaml
- 4154-ini_file_changed.yml
- 4168-add-keycloak-url-timeout.yml
- 4179-linode-inventory-cache.yaml
- 4183-fix-yum_versionlock.yaml
- 4191-proxmox-add-win11.yml
- 4192-improve-passwordstore-consistency.yml
- 4194-configurable-passwordstore-locking.yml
- 4206-imc-rest-module.yaml
- 4212-fixes-for-keycloak-user-federation.yml
- 4219-passwordstore-locale-fix.yml
- 4232-text-converter-import.yml
- 4240-ansible_galaxy_install-no_deps.yml
modules:
- description: Configure Intel Optane Persistent Memory modules
name: pmem
namespace: storage.pmem
- description: Scaleway private network management
name: scaleway_private_network
namespace: cloud.scaleway
release_date: '2022-02-22'
4.6.0:
changes:
bugfixes:
- filesize - add support for busybox dd implementation, that is used by default
on Alpine linux (https://github.com/ansible-collections/community.general/pull/4288,
https://github.com/ansible-collections/community.general/issues/4259).
- linode inventory plugin - fix configuration handling relating to inventory
filtering (https://github.com/ansible-collections/community.general/pull/4336).
- mksysb - fixed bug for parameter ``backup_dmapi_fs`` was passing the wrong
CLI argument (https://github.com/ansible-collections/community.general/pull/3295).
- pacman - Use ``--groups`` instead of ``--group`` (https://github.com/ansible-collections/community.general/pull/4312).
- pacman - fix URL based package installation (https://github.com/ansible-collections/community.general/pull/4286,
https://github.com/ansible-collections/community.general/issues/4285).
- pacman - fix ``upgrade=yes`` (https://github.com/ansible-collections/community.general/pull/4275,
https://github.com/ansible-collections/community.general/issues/4274).
- pacman - make sure that ``packages`` is always returned when ``name`` or ``upgrade``
is specified, also if nothing is done (https://github.com/ansible-collections/community.general/pull/4329).
- pacman - when the ``update_cache`` option is combined with another option
such as ``upgrade``, report ``changed`` based on the actions performed by
the latter option. This was the behavior in community.general 4.4.0 and before.
In community.general 4.5.0, a task combining these options would always report
``changed`` (https://github.com/ansible-collections/community.general/pull/4318).
- proxmox inventory plugin - always convert strings that follow the ``key=value[,key=value[...]]``
form into dictionaries (https://github.com/ansible-collections/community.general/pull/4349).
- proxmox inventory plugin - fixed the ``description`` field being ignored if
it contained a comma (https://github.com/ansible-collections/community.general/issues/4348).
- proxmox_kvm - fix error in check when creating or cloning (https://github.com/ansible-collections/community.general/pull/4306).
- proxmox_kvm - fix error when checking whether Proxmox VM exists (https://github.com/ansible-collections/community.general/pull/4287).
- terraform - fix ``variable`` handling to allow complex values (https://github.com/ansible-collections/community.general/pull/4281).
deprecated_features:
- 'pacman - from community.general 5.0.0 on, the ``changed`` status of ``update_cache``
will no longer be ignored if ``name`` or ``upgrade`` is specified. To keep
the old behavior, add something like ``register: result`` and ``changed_when:
result.packages | length > 0`` to your task (https://github.com/ansible-collections/community.general/pull/4329).'
known_issues:
- pacman - ``update_cache`` cannot differentiate between up to date and outdated
package lists and will report ``changed`` in both situations (https://github.com/ansible-collections/community.general/pull/4318).
- pacman - binaries specified in the ``executable`` parameter must support ``--print-format``
in order to be used by this module. In particular, AUR helper ``yay`` is known
not to currently support it (https://github.com/ansible-collections/community.general/pull/4312).
minor_changes:
- jira - when creating a comment, ``fields`` now is used for additional data
(https://github.com/ansible-collections/community.general/pull/4304).
- ldap_entry - add support for recursive deletion (https://github.com/ansible-collections/community.general/issues/3613).
- mksysb - revamped the module using ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/3295).
- nmcli - add missing connection aliases ``802-3-ethernet`` and ``802-11-wireless``
(https://github.com/ansible-collections/community.general/pull/4108).
- nmcli - remove nmcli modify dependency on ``type`` parameter (https://github.com/ansible-collections/community.general/issues/2858).
- npm - add ability to use ``production`` flag when ``ci`` is set (https://github.com/ansible-collections/community.general/pull/4299).
- pacman - add ``remove_nosave`` parameter to avoid saving modified configuration
files as ``.pacsave`` files. (https://github.com/ansible-collections/community.general/pull/4316,
https://github.com/ansible-collections/community.general/issues/4315).
- pacman - now implements proper change detection for ``update_cache=true``.
Adds ``cache_updated`` return value to when ``update_cache=true`` to report
this result independently of the module's overall changed return value (https://github.com/ansible-collections/community.general/pull/4337).
- pipx - added options ``editable`` and ``pip_args`` (https://github.com/ansible-collections/community.general/issues/4300).
- proxmox inventory plugin - add support for client-side jinja filters (https://github.com/ansible-collections/community.general/issues/3553).
- redis - add authentication parameters ``login_user``, ``tls``, ``validate_certs``,
and ``ca_certs`` (https://github.com/ansible-collections/community.general/pull/4207).
- syslog_json - add option to skip logging of ``gather_facts`` playbook tasks;
use v2 callback API (https://github.com/ansible-collections/community.general/pull/4223).
- zypper - add support for ``--clean-deps`` option to remove packages that depend
on a package being removed (https://github.com/ansible-collections/community.general/pull/4195).
release_summary: Regular feature and bugfix release.
fragments:
- 3295-mksysb-revamp.yaml
- 4.6.0.yml
- 4108-nmcli-support-modifcation-without-type-param.yml
- 4192-zypper-add-clean-deps.yml
- 4207-add-redis-tls-support.yml
- 4223-syslog-json-skip-syslog-option.yml
- 4275-pacman-sysupgrade.yml
- 4281-terraform-complex-variables.yml
- 4286-pacman-url-pkgs.yml
- 4287-fix-proxmox-vm-chek.yml
- 4288-fix-4259-support-busybox-dd.yml
- 4299-npm-add-production-with-ci-flag.yml
- 4303-pipx-editable.yml
- 4304-jira-fields-in-comment.yml
- 4306-proxmox-fix-error-on-vm-clone.yml
- 4312-pacman-groups.yml
- 4316-pacman-remove-nosave.yml
- 4318-pacman-restore-old-changed-behavior.yml
- 4330-pacman-packages-update_cache.yml
- 4336-linode-inventory-filtering.yaml
- 4337-pacman-update_cache.yml
- 4349-proxmox-inventory-dict-facts.yml
- 4352-proxmox-inventory-filters.yml
- 4355-ldap-recursive-delete.yml
release_date: '2022-03-15'
4.6.1:
changes:
bugfixes:
- 'lxd inventory plugin - do not crash if OS and release metadata are not present
(https://github.com/ansible-collections/community.general/pull/4351).
'
- terraform - revert bugfix https://github.com/ansible-collections/community.general/pull/4281
that tried to fix ``variable`` handling to allow complex values. It turned
out that this was breaking several valid use-cases (https://github.com/ansible-collections/community.general/issues/4367,
https://github.com/ansible-collections/community.general/pull/4370).
release_summary: Extraordinary bugfix release to fix a breaking change in ``terraform``.
fragments:
- 4.6.1.yml
- 4351-inventory-lxd-handling_metadata_wo_os_and_release.yml
- 4368-reverts-4281.yml
release_date: '2022-03-16'
4.7.0:
changes:
bugfixes:
- dsv lookup plugin - raise an Ansible error if the wrong ``python-dsv-sdk``
version is installed (https://github.com/ansible-collections/community.general/pull/4422).
- keycloak_* - the documented ``validate_certs`` parameter was not taken into
account when calling the ``open_url`` function in some cases, thus enforcing
certificate validation even when ``validate_certs`` was set to ``false``.
(https://github.com/ansible-collections/community.general/pull/4382)
- nmcli - fix returning "changed" when routes parameters set, also suggest new
routes4 and routes6 format (https://github.com/ansible-collections/community.general/issues/4131).
- proxmox inventory plugin - fixed the ``tags_parsed`` field when Proxmox returns
a single space for the ``tags`` entry (https://github.com/ansible-collections/community.general/pull/4378).
- zypper - fixed bug that caused zypper to always report [ok] and do nothing
on ``state=present`` when all packages in ``name`` had a version specification
(https://github.com/ansible-collections/community.general/issues/4371, https://github.com/ansible-collections/community.general/pull/4421).
minor_changes:
- ipa_service - add ``skip_host_check`` parameter. (https://github.com/ansible-collections/community.general/pull/4417).
- keycloak_client - add ``always_display_in_console`` parameter (https://github.com/ansible-collections/community.general/issues/4390).
- keycloak_client - add ``default_client_scopes`` and ``optional_client_scopes``
parameters. (https://github.com/ansible-collections/community.general/pull/4385).
- proxmox inventory plugin - add support for templating the ``url``, ``user``,
and ``password`` options (https://github.com/ansible-collections/community.general/pull/4418).
- sudoers - add support for ``runas`` parameter (https://github.com/ansible-collections/community.general/issues/4379).
release_summary: Regular bugfix and feature release.
fragments:
- 4.7.0.yml
- 4131-nmcli_fix_reports_changed_for_routes4_parameter.yml
- 4378-proxmox-inventory-tags.yml
- 4380-sudoers-runas-parameter.yml
- 4382-keycloak-add-missing-validate_certs-parameters.yml
- 4385-keycloak-client-default-optional-scopes.yml
- 4386-proxmox-support-templating-in-inventory-file.yml
- 4417-ipa_service-add-skip_host_check.yml
- 4421-zypper_package_version_handling_fix.yml
- 4422-warn-user-if-incorrect-SDK-version-is-installed.yaml
- 4429-keycloak-client-add-always-display-in-console.yml
release_date: '2022-04-05'

View File

@@ -0,0 +1,13 @@
list1:
- name: foo
extra: true
- name: bar
extra: false
- name: meh
extra: true
list2:
- name: foo
path: /foo
- name: baz
path: /baz

View File

@@ -0,0 +1,19 @@
list1:
- name: myname01
param01:
x: default_value
y: default_value
list:
- default_value
- name: myname02
param01: [1, 1, 2, 3]
list2:
- name: myname01
param01:
y: patch_value
z: patch_value
list:
- patch_value
- name: myname02
param01: [3, 4, 4, {key: value}]

View File

@@ -0,0 +1,10 @@
---
- name: 1. Merge two lists by common attribute 'name'
include_vars:
dir: example-001_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-001.out

View File

@@ -0,0 +1 @@
../default-common.yml

View File

@@ -0,0 +1,2 @@
list3: "{{ list1|
community.general.lists_mergeby(list2, 'name') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 2. Merge two lists by common attribute 'name'
include_vars:
dir: example-002_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-002.out

View File

@@ -0,0 +1 @@
../default-common.yml

View File

@@ -0,0 +1,2 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 3. Merge recursive by 'name', replace lists (default)
include_vars:
dir: example-003_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-003.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,3 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true) }}"

View File

@@ -0,0 +1,10 @@
---
- name: 4. Merge recursive by 'name', keep lists
include_vars:
dir: example-004_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-004.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,4 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='keep') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 5. Merge recursive by 'name', append lists
include_vars:
dir: example-005_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-005.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,4 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='append') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 6. Merge recursive by 'name', prepend lists
include_vars:
dir: example-006_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-006.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,4 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='prepend') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 7. Merge recursive by 'name', append lists 'remove present'
include_vars:
dir: example-007_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-007.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,4 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='append_rp') }}"

View File

@@ -0,0 +1,10 @@
---
- name: 8. Merge recursive by 'name', prepend lists 'remove present'
include_vars:
dir: example-008_vars
- debug:
var: list3
when: debug|d(false)|bool
- template:
src: list3.out.j2
dest: example-008.out

View File

@@ -0,0 +1 @@
../default-recursive-true.yml

View File

@@ -0,0 +1,4 @@
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='prepend_rp') }}"

View File

@@ -0,0 +1,50 @@
---
examples:
- label: 'In the example below the lists are merged by the attribute ``name``:'
file: example-001_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-001.out
lang: 'yaml'
- label: 'It is possible to use a list of lists as an input of the filter:'
file: example-002_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces the same result as in the previous example:'
file: example-002.out
lang: 'yaml'
- label: 'Example ``list_merge=replace`` (default):'
file: example-003_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-003.out
lang: 'yaml'
- label: 'Example ``list_merge=keep``:'
file: example-004_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-004.out
lang: 'yaml'
- label: 'Example ``list_merge=append``:'
file: example-005_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-005.out
lang: 'yaml'
- label: 'Example ``list_merge=prepend``:'
file: example-006_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-006.out
lang: 'yaml'
- label: 'Example ``list_merge=append_rp``:'
file: example-007_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-007.out
lang: 'yaml'
- label: 'Example ``list_merge=prepend_rp``:'
file: example-008_vars/list3.yml
lang: 'yaml+jinja'
- label: 'This produces:'
file: example-008.out
lang: 'yaml'

View File

@@ -0,0 +1,8 @@
{% for i in examples %}
{{ i.label }}
.. code-block:: {{ i.lang }}
{{ lookup('file', i.file)|indent(2) }}
{% endfor %}

View File

@@ -0,0 +1,57 @@
Merging lists of dictionaries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the ``lists_mergeby`` filter.
.. note:: The output of the examples in this section use the YAML callback plugin. Quoting: "Ansible output that can be quite a bit easier to read than the default JSON formatting." See :ref:`the documentation for the community.general.yaml callback plugin <ansible_collections.community.general.yaml_callback>`.
Let us use the lists below in the following examples:
.. code-block:: yaml
{{ lookup('file', 'default-common.yml')|indent(2) }}
{% for i in examples[0:2] %}
{{ i.label }}
.. code-block:: {{ i.lang }}
{{ lookup('file', i.file)|indent(2) }}
{% endfor %}
.. versionadded:: 2.0.0
{% for i in examples[2:4] %}
{{ i.label }}
.. code-block:: {{ i.lang }}
{{ lookup('file', i.file)|indent(2) }}
{% endfor %}
The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. These parameters are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9. This is available since community.general 4.4.0.
**recursive**
Is a boolean, default to ``False``. Should the ``community.general.lists_mergeby`` recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
**list_merge**
Is a string, its possible values are ``replace`` (default), ``keep``, ``append``, ``prepend``, ``append_rp`` or ``prepend_rp``. It modifies the behaviour of ``community.general.lists_mergeby`` when the hashes to merge contain arrays/lists.
The examples below set ``recursive=true`` and display the differences among all six options of ``list_merge``. Functionality of the parameters is exactly the same as in the filter ``combine``. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
Let us use the lists below in the following examples
.. code-block:: yaml
{{ lookup('file', 'default-recursive-true.yml')|indent(2) }}
{% for i in examples[4:16] %}
{{ i.label }}
.. code-block:: {{ i.lang }}
{{ lookup('file', i.file)|indent(2) }}
{% endfor %}

View File

@@ -0,0 +1,2 @@
list3:
{{ list3|to_nice_yaml(indent=0) }}

View File

@@ -0,0 +1,59 @@
---
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 1) Run all examples and create example-XXX.out
# shell> ansible-playbook playbook.yml -e examples=true
#
# 2) Optionally, for testing, create examples_all.rst
# shell> ansible-playbook playbook.yml -e examples_all=true
#
# 3) Create docs REST files
# shell> ansible-playbook playbook.yml -e merging_lists_of_dictionaries=true
#
# Notes:
# * Use YAML callback, e.g. set ANSIBLE_STDOUT_CALLBACK=community.general.yaml
# * Use sphinx-view to render and review the REST files
# shell> sphinx-view <path_to_helper>/examples_all.rst
# * Proofread and copy completed docs *.rst files into the directory rst.
# * Then delete the *.rst and *.out files from this directory. Do not
# add *.rst and *.out in this directory to the version control.
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# community.general/docs/docsite/helper/lists_mergeby/playbook.yml
- hosts: localhost
gather_facts: false
tasks:
- block:
- import_tasks: example-001.yml
tags: t001
- import_tasks: example-002.yml
tags: t002
- import_tasks: example-003.yml
tags: t003
- import_tasks: example-004.yml
tags: t004
- import_tasks: example-005.yml
tags: t005
- import_tasks: example-006.yml
tags: t006
- import_tasks: example-007.yml
tags: t007
- import_tasks: example-008.yml
tags: t008
when: examples|d(false)|bool
- block:
- include_vars: examples.yml
- template:
src: examples_all.rst.j2
dest: examples_all.rst
when: examples_all|d(false)|bool
- block:
- include_vars: examples.yml
- template:
src: filter_guide_abstract_informations_merging_lists_of_dictionaries.rst.j2
dest: filter_guide_abstract_informations_merging_lists_of_dictionaries.rst
when: merging_lists_of_dictionaries|d(false)|bool

23
docs/docsite/links.yml Normal file
View File

@@ -0,0 +1,23 @@
---
edit_on_github:
repository: ansible-collections/community.general
branch: main
path_prefix: ''
extra_links:
- description: Submit a bug report
url: https://github.com/ansible-collections/community.general/issues/new?assignees=&labels=&template=bug_report.yml
- description: Request a feature
url: https://github.com/ansible-collections/community.general/issues/new?assignees=&labels=&template=feature_request.yml
communication:
matrix_rooms:
- topic: General usage and support questions
room: '#users:ansible.im'
irc_channels:
- topic: General usage and support questions
network: Libera
channel: '#ansible'
mailing_lists:
- topic: Ansible Project List
url: https://groups.google.com/g/ansible-project

View File

@@ -1,3 +1,4 @@
.. _ansible_collections.community.general.docsite.filter_guide:
community.general Filter Guide
@@ -5,780 +6,14 @@ community.general Filter Guide
The :ref:`community.general collection <plugins_in_community.general>` offers several useful filter plugins.
.. contents:: Topics
Paths
-----
The ``path_join`` filter has been added in ansible-base 2.10. If you want to use this filter, but also need to support Ansible 2.9, you can use ``community.general``'s ``path_join`` shim, ``community.general.path_join``. This filter redirects to ``path_join`` for ansible-base 2.10 and ansible-core 2.11 or newer, and re-implements the filter for Ansible 2.9.
.. code-block:: yaml+jinja
# ansible-base 2.10 or newer:
path: {{ ('/etc', path, 'subdir', file) | path_join }}
# Also works with Ansible 2.9:
path: {{ ('/etc', path, 'subdir', file) | community.general.path_join }}
.. versionadded:: 3.0.0
Abstract transformations
------------------------
Dictionaries
^^^^^^^^^^^^
You can use the ``dict_kv`` filter to create a single-entry dictionary with ``value | community.general.dict_kv(key)``:
.. code-block:: yaml+jinja
- name: Create a single-entry dictionary
debug:
msg: "{{ myvar | community.general.dict_kv('thatsmyvar') }}"
vars:
myvar: myvalue
- name: Create a list of dictionaries where the 'server' field is taken from a list
debug:
msg: >-
{{ myservers | map('community.general.dict_kv', 'server')
| map('combine', common_config) }}
vars:
common_config:
type: host
database: all
myservers:
- server1
- server2
This produces:
.. code-block:: ansible-output
TASK [Create a single-entry dictionary] **************************************************
ok: [localhost] => {
"msg": {
"thatsmyvar": "myvalue"
}
}
TASK [Create a list of dictionaries where the 'server' field is taken from a list] *******
ok: [localhost] => {
"msg": [
{
"database": "all",
"server": "server1",
"type": "host"
},
{
"database": "all",
"server": "server2",
"type": "host"
}
]
}
.. versionadded:: 2.0.0
If you need to convert a list of key-value pairs to a dictionary, you can use the ``dict`` function. Unfortunately, this function cannot be used with ``map``. For this, the ``community.general.dict`` filter can be used:
.. code-block:: yaml+jinja
- name: Create a dictionary with the dict function
debug:
msg: "{{ dict([[1, 2], ['a', 'b']]) }}"
- name: Create a dictionary with the community.general.dict filter
debug:
msg: "{{ [[1, 2], ['a', 'b']] | community.general.dict }}"
- name: Create a list of dictionaries with map and the community.general.dict filter
debug:
msg: >-
{{ values | map('zip', ['k1', 'k2', 'k3'])
| map('map', 'reverse')
| map('community.general.dict') }}
vars:
values:
- - foo
- 23
- a
- - bar
- 42
- b
This produces:
.. code-block:: ansible-output
TASK [Create a dictionary with the dict function] ****************************************
ok: [localhost] => {
"msg": {
"1": 2,
"a": "b"
}
}
TASK [Create a dictionary with the community.general.dict filter] ************************
ok: [localhost] => {
"msg": {
"1": 2,
"a": "b"
}
}
TASK [Create a list of dictionaries with map and the community.general.dict filter] ******
ok: [localhost] => {
"msg": [
{
"k1": "foo",
"k2": 23,
"k3": "a"
},
{
"k1": "bar",
"k2": 42,
"k3": "b"
}
]
}
.. versionadded:: 3.0.0
Grouping
^^^^^^^^
If you have a list of dictionaries, the Jinja2 ``groupby`` filter allows to group the list by an attribute. This results in a list of ``(grouper, list)`` namedtuples, where ``list`` contains all dictionaries where the selected attribute equals ``grouper``. If you know that for every ``grouper``, there will be a most one entry in that list, you can use the ``community.general.groupby_as_dict`` filter to convert the original list into a dictionary which maps ``grouper`` to the corresponding dictionary.
One example is ``ansible_facts.mounts``, which is a list of dictionaries where each has one ``device`` element to indicate the device which is mounted. Therefore, ``ansible_facts.mounts | community.general.groupby_as_dict('device')`` is a dictionary mapping a device to the mount information:
.. code-block:: yaml+jinja
- name: Output mount facts grouped by device name
debug:
var: ansible_facts.mounts | community.general.groupby_as_dict('device')
- name: Output mount facts grouped by mount point
debug:
var: ansible_facts.mounts | community.general.groupby_as_dict('mount')
This produces:
.. code-block:: ansible-output
TASK [Output mount facts grouped by device name] ******************************************
ok: [localhost] => {
"ansible_facts.mounts | community.general.groupby_as_dict('device')": {
"/dev/sda1": {
"block_available": 2000,
"block_size": 4096,
"block_total": 2345,
"block_used": 345,
"device": "/dev/sda1",
"fstype": "ext4",
"inode_available": 500,
"inode_total": 512,
"inode_used": 12,
"mount": "/boot",
"options": "rw,relatime,data=ordered",
"size_available": 56821,
"size_total": 543210,
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
},
"/dev/sda2": {
"block_available": 1234,
"block_size": 4096,
"block_total": 12345,
"block_used": 11111,
"device": "/dev/sda2",
"fstype": "ext4",
"inode_available": 1111,
"inode_total": 1234,
"inode_used": 123,
"mount": "/",
"options": "rw,relatime",
"size_available": 42143,
"size_total": 543210,
"uuid": "abcdef01-2345-6789-0abc-def012345678"
}
}
}
TASK [Output mount facts grouped by mount point] ******************************************
ok: [localhost] => {
"ansible_facts.mounts | community.general.groupby_as_dict('mount')": {
"/": {
"block_available": 1234,
"block_size": 4096,
"block_total": 12345,
"block_used": 11111,
"device": "/dev/sda2",
"fstype": "ext4",
"inode_available": 1111,
"inode_total": 1234,
"inode_used": 123,
"mount": "/",
"options": "rw,relatime",
"size_available": 42143,
"size_total": 543210,
"uuid": "bdf50b7d-4859-40af-8665-c637ee7a7808"
},
"/boot": {
"block_available": 2000,
"block_size": 4096,
"block_total": 2345,
"block_used": 345,
"device": "/dev/sda1",
"fstype": "ext4",
"inode_available": 500,
"inode_total": 512,
"inode_used": 12,
"mount": "/boot",
"options": "rw,relatime,data=ordered",
"size_available": 56821,
"size_total": 543210,
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
}
}
}
.. versionadded: 3.0.0
Merging lists of dictionaries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have two lists of dictionaries and want to combine them into a list of merged dictionaries, where two dictionaries are merged if they coincide in one attribute, you can use the ``lists_mergeby`` filter.
.. code-block:: yaml+jinja
- name: Merge two lists by common attribute 'name'
debug:
var: list1 | community.general.lists_mergeby(list2, 'name')
vars:
list1:
- name: foo
extra: true
- name: bar
extra: false
- name: meh
extra: true
list2:
- name: foo
path: /foo
- name: baz
path: /bazzz
This produces:
.. code-block:: ansible-output
TASK [Merge two lists by common attribute 'name'] ****************************************
ok: [localhost] => {
"list1 | community.general.lists_mergeby(list2, 'name')": [
{
"extra": false,
"name": "bar"
},
{
"name": "baz",
"path": "/bazzz"
},
{
"extra": true,
"name": "foo",
"path": "/foo"
},
{
"extra": true,
"name": "meh"
}
]
}
.. versionadded: 2.0.0
Working with times
------------------
The ``to_time_unit`` filter allows to convert times from a human-readable string to a unit. For example, ``'4h 30min 12second' | community.general.to_time_unit('hour')`` gives the number of hours that correspond to 4 hours, 30 minutes and 12 seconds.
There are shorthands to directly convert to various units, like ``to_hours``, ``to_minutes``, ``to_seconds``, and so on. The following table lists all units that can be used:
.. list-table:: Units
:widths: 25 25 25 25
:header-rows: 1
* - Unit name
- Unit value in seconds
- Unit strings for filter
- Shorthand filter
* - Millisecond
- 1/1000 second
- ``ms``, ``millisecond``, ``milliseconds``, ``msec``, ``msecs``, ``msecond``, ``mseconds``
- ``to_milliseconds``
* - Second
- 1 second
- ``s``, ``sec``, ``secs``, ``second``, ``seconds``
- ``to_seconds``
* - Minute
- 60 seconds
- ``m``, ``min``, ``mins``, ``minute``, ``minutes``
- ``to_minutes``
* - Hour
- 60*60 seconds
- ``h``, ``hour``, ``hours``
- ``to_hours``
* - Day
- 24*60*60 seconds
- ``d``, ``day``, ``days``
- ``to_days``
* - Week
- 7*24*60*60 seconds
- ``w``, ``week``, ``weeks``
- ``to_weeks``
* - Month
- 30*24*60*60 seconds
- ``mo``, ``month``, ``months``
- ``to_months``
* - Year
- 365*24*60*60 seconds
- ``y``, ``year``, ``years``
- ``to_years``
Note that months and years are using a simplified representation: a month is 30 days, and a year is 365 days. If you need different definitions of months or years, you can pass them as keyword arguments. For example, if you want a year to be 365.25 days, and a month to be 30.5 days, you can write ``'11months 4' | community.general.to_years(year=365.25, month=30.5)``. These keyword arguments can be specified to ``to_time_unit`` and to all shorthand filters.
.. code-block:: yaml+jinja
- name: Convert string to seconds
debug:
msg: "{{ '30h 20m 10s 123ms' | community.general.to_time_unit('seconds') }}"
- name: Convert string to hours
debug:
msg: "{{ '30h 20m 10s 123ms' | community.general.to_hours }}"
- name: Convert string to years (using 365.25 days == 1 year)
debug:
msg: "{{ '400d 15h' | community.general.to_years(year=365.25) }}"
This produces:
.. code-block:: ansible-output
TASK [Convert string to seconds] **********************************************************
ok: [localhost] => {
"msg": "109210.123"
}
TASK [Convert string to hours] ************************************************************
ok: [localhost] => {
"msg": "30.336145277778"
}
TASK [Convert string to years (using 365.25 days == 1 year)] ******************************
ok: [localhost] => {
"msg": "1.096851471595"
}
.. versionadded: 0.2.0
Working with versions
---------------------
If you need to sort a list of version numbers, the Jinja ``sort`` filter is problematic. Since it sorts lexicographically, ``2.10`` will come before ``2.9``. To treat version numbers correctly, you can use the ``version_sort`` filter:
.. code-block:: yaml+jinja
- name: Sort list by version number
debug:
var: ansible_versions | community.general.version_sort
vars:
ansible_versions:
- '2.8.0'
- '2.11.0'
- '2.7.0'
- '2.10.0'
- '2.9.0'
This produces:
.. code-block:: ansible-output
TASK [Sort list by version number] ********************************************************
ok: [localhost] => {
"ansible_versions | community.general.version_sort": [
"2.7.0",
"2.8.0",
"2.9.0",
"2.10.0",
"2.11.0"
]
}
.. versionadded: 2.2.0
Creating identifiers
--------------------
The following filters allow to create identifiers.
Hashids
^^^^^^^
`Hashids <https://hashids.org/>`_ allow to convert sequences of integers to short unique string identifiers. This filter needs the `hashids Python library <https://pypi.org/project/hashids/>`_ installed on the controller.
.. code-block:: yaml+jinja
- name: "Create hashid"
debug:
msg: "{{ [1234, 5, 6] | community.general.hashids_encode }}"
- name: "Decode hashid"
debug:
msg: "{{ 'jm2Cytn' | community.general.hashids_decode }}"
This produces:
.. code-block:: ansible-output
TASK [Create hashid] **********************************************************************
ok: [localhost] => {
"msg": "jm2Cytn"
}
TASK [Decode hashid] **********************************************************************
ok: [localhost] => {
"msg": [
1234,
5,
6
]
}
The hashids filters accept keyword arguments to allow fine-tuning the hashids generated:
:salt: String to use as salt when hashing.
:alphabet: String of 16 or more unique characters to produce a hash.
:min_length: Minimum length of hash produced.
.. versionadded: 3.0.0
Random MACs
^^^^^^^^^^^
You can use the ``random_mac`` filter to complete a partial `MAC address <https://en.wikipedia.org/wiki/MAC_address>`_ to a random 6-byte MAC address.
.. code-block:: yaml+jinja
- name: "Create a random MAC starting with ff:"
debug:
msg: "{{ 'FF' | community.general.random_mac }}"
- name: "Create a random MAC starting with 00:11:22:"
debug:
msg: "{{ '00:11:22' | community.general.random_mac }}"
This produces:
.. code-block:: ansible-output
TASK [Create a random MAC starting with ff:] **********************************************
ok: [localhost] => {
"msg": "ff:69:d3:78:7f:b4"
}
TASK [Create a random MAC starting with 00:11:22:] ****************************************
ok: [localhost] => {
"msg": "00:11:22:71:5d:3b"
}
You can also initialize the random number generator from a seed to create random-but-idempotent MAC addresses:
.. code-block:: yaml+jinja
"{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"
Conversions
-----------
Parsing CSV files
^^^^^^^^^^^^^^^^^
Ansible offers the :ref:`community.general.read_csv module <ansible_collections.community.general.read_csv_module>` to read CSV files. Sometimes you need to convert strings to CSV files instead. For this, the ``from_csv`` filter exists.
.. code-block:: yaml+jinja
- name: "Parse CSV from string"
debug:
msg: "{{ csv_string | community.general.from_csv }}"
vars:
csv_string: |
foo,bar,baz
1,2,3
you,this,then
This produces:
.. code-block:: ansible-output
TASK [Parse CSV from string] **************************************************************
ok: [localhost] => {
"msg": [
{
"bar": "2",
"baz": "3",
"foo": "1"
},
{
"bar": "this",
"baz": "then",
"foo": "you"
}
]
}
The ``from_csv`` filter has several keyword arguments to control its behavior:
:dialect: Dialect of the CSV file. Default is ``excel``. Other possible choices are ``excel-tab`` and ``unix``. If one of ``delimiter``, ``skipinitialspace`` or ``strict`` is specified, ``dialect`` is ignored.
:fieldnames: A set of column names to use. If not provided, the first line of the CSV is assumed to contain the column names.
:delimiter: Sets the delimiter to use. Default depends on the dialect used.
:skipinitialspace: Set to ``true`` to ignore space directly after the delimiter. Default depends on the dialect used (usually ``false``).
:strict: Set to ``true`` to error out on invalid CSV input.
.. versionadded: 3.0.0
Converting to JSON
^^^^^^^^^^^^^^^^^^
`JC <https://pypi.org/project/jc/>`_ is a CLI tool and Python library which allows to interpret output of various CLI programs as JSON. It is also available as a filter in community.general. This filter needs the `jc Python library <https://pypi.org/project/jc/>`_ installed on the controller.
.. code-block:: yaml+jinja
- name: Run 'ls' to list files in /
command: ls /
register: result
- name: Parse the ls output
debug:
msg: "{{ result.stdout | community.general.jc('ls') }}"
This produces:
.. code-block:: ansible-output
TASK [Run 'ls' to list files in /] ********************************************************
changed: [localhost]
TASK [Parse the ls output] ****************************************************************
ok: [localhost] => {
"msg": [
{
"filename": "bin"
},
{
"filename": "boot"
},
{
"filename": "dev"
},
{
"filename": "etc"
},
{
"filename": "home"
},
{
"filename": "lib"
},
{
"filename": "proc"
},
{
"filename": "root"
},
{
"filename": "run"
},
{
"filename": "tmp"
}
]
}
.. versionadded: 2.0.0
.. _ansible_collections.community.general.docsite.json_query_filter:
Selecting JSON data: JSON queries
---------------------------------
To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the ``json_query`` filter. The ``json_query`` filter lets you query a complex JSON structure and iterate over it using a loop structure.
.. note:: You must manually install the **jmespath** dependency on the Ansible controller before using this filter. This filter is built upon **jmespath**, and you can use the same syntax. For examples, see `jmespath examples <http://jmespath.org/examples.html>`_.
Consider this data structure:
.. code-block:: yaml+jinja
{
"domain_definition": {
"domain": {
"cluster": [
{
"name": "cluster1"
},
{
"name": "cluster2"
}
],
"server": [
{
"name": "server11",
"cluster": "cluster1",
"port": "8080"
},
{
"name": "server12",
"cluster": "cluster1",
"port": "8090"
},
{
"name": "server21",
"cluster": "cluster2",
"port": "9080"
},
{
"name": "server22",
"cluster": "cluster2",
"port": "9090"
}
],
"library": [
{
"name": "lib1",
"target": "cluster1"
},
{
"name": "lib2",
"target": "cluster2"
}
]
}
}
}
To extract all clusters from this structure, you can use the following query:
.. code-block:: yaml+jinja
- name: Display all cluster names
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"
To extract all server names:
.. code-block:: yaml+jinja
- name: Display all server names
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}"
To extract ports from cluster1:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
vars:
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"
.. note:: You can use a variable to make the query more readable.
To print out the ports from cluster1 in a comma separated string:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1 as a string
ansible.builtin.debug:
msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"
.. note:: In the example above, quoting literals using backticks avoids escaping quotes and maintains readability.
You can use YAML `single quote escaping <https://yaml.org/spec/current.html#id2534365>`_:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.server[?cluster==''cluster1''].port') }}"
.. note:: Escaping single quotes within single quotes in YAML is done by doubling the single quote.
To get a hash map with all ports and names of a cluster:
.. code-block:: yaml+jinja
- name: Display all server ports and names from cluster1
ansible.builtin.debug:
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}"
To extract ports from all clusters with name starting with 'server1':
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
vars:
server_name_query: "domain.server[?starts_with(name,'server1')].port"
To extract ports from all clusters with name containing 'server1':
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
vars:
server_name_query: "domain.server[?contains(name,'server1')].port"
.. note:: while using ``starts_with`` and ``contains``, you have to use `` to_json | from_json `` filter for correct parsing of data structure.
Working with Unicode
---------------------
`Unicode <https://unicode.org/main.html>`_ makes it possible to produce two strings which may be visually equivalent, but are comprised of distinctly different characters/character sequences. To address this ``Unicode`` defines `normalization forms <https://unicode.org/reports/tr15/>`_ which avoid these distinctions by choosing a unique character sequence for a given visual representation.
You can use the ``community.general.unicode_normalize`` filter to normalize ``Unicode`` strings within your playbooks.
.. code-block:: yaml+jinja
- name: Compare Unicode representations
debug:
msg: "{{ with_combining_character | community.general.unicode_normalize == without_combining_character }}"
vars:
with_combining_character: "{{ 'Mayagu\u0308ez' }}"
without_combining_character: Mayagüez
This produces:
.. code-block:: ansible-output
TASK [Compare Unicode representations] ********************************************************
ok: [localhost] => {
"msg": true
}
The ``community.general.unicode_normalize`` filter accepts a keyword argument to select the ``Unicode`` form used to normalize the input string.
:form: One of ``'NFC'`` (default), ``'NFD'``, ``'NFKC'``, or ``'NFKD'``. See the `Unicode reference <https://unicode.org/reports/tr15/>`_ for more information.
.. versionadded:: 3.7.0
.. toctree::
:maxdepth: 2
filter_guide_paths
filter_guide_abstract_informations
filter_guide_working_with_times
filter_guide_working_with_versions
filter_guide_creating_identifiers
filter_guide_conversions
filter_guide_selecting_json_data
filter_guide_working_with_unicode

View File

@@ -0,0 +1,10 @@
Abstract transformations
------------------------
.. toctree::
:maxdepth: 1
filter_guide_abstract_informations_dictionaries
filter_guide_abstract_informations_grouping
filter_guide_abstract_informations_merging_lists_of_dictionaries
filter_guide_abstract_informations_counting_elements_in_sequence

View File

@@ -0,0 +1,77 @@
Counting elements in a sequence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``community.general.counter`` filter plugin allows you to count (hashable) elements in a sequence. Elements are returned as dictionary keys and their counts are stored as dictionary values.
.. code-block:: yaml+jinja
- name: Count character occurrences in a string
debug:
msg: "{{ 'abccbaabca' | community.general.counter }}"
- name: Count items in a list
debug:
msg: "{{ ['car', 'car', 'bike', 'plane', 'bike'] | community.general.counter }}"
This produces:
.. code-block:: ansible-output
TASK [Count character occurrences in a string] ********************************************
ok: [localhost] => {
"msg": {
"a": 4,
"b": 3,
"c": 3
}
}
TASK [Count items in a list] **************************************************************
ok: [localhost] => {
"msg": {
"bike": 2,
"car": 2,
"plane": 1
}
}
This plugin is useful for selecting resources based on current allocation:
.. code-block:: yaml+jinja
- name: Get ID of SCSI controller(s) with less than 4 disks attached and choose the one with the least disks
debug:
msg: >-
{{
( disks | dict2items | map(attribute='value.adapter') | list
| community.general.counter | dict2items
| rejectattr('value', '>=', 4) | sort(attribute='value') | first
).key
}}
vars:
disks:
sda:
adapter: scsi_1
sdb:
adapter: scsi_1
sdc:
adapter: scsi_1
sdd:
adapter: scsi_1
sde:
adapter: scsi_2
sdf:
adapter: scsi_3
sdg:
adapter: scsi_3
This produces:
.. code-block:: ansible-output
TASK [Get ID of SCSI controller(s) with less than 4 disks attached and choose the one with the least disks]
ok: [localhost] => {
"msg": "scsi_2"
}
.. versionadded:: 4.3.0

View File

@@ -0,0 +1,119 @@
Dictionaries
^^^^^^^^^^^^
You can use the ``dict_kv`` filter to create a single-entry dictionary with ``value | community.general.dict_kv(key)``:
.. code-block:: yaml+jinja
- name: Create a single-entry dictionary
debug:
msg: "{{ myvar | community.general.dict_kv('thatsmyvar') }}"
vars:
myvar: myvalue
- name: Create a list of dictionaries where the 'server' field is taken from a list
debug:
msg: >-
{{ myservers | map('community.general.dict_kv', 'server')
| map('combine', common_config) }}
vars:
common_config:
type: host
database: all
myservers:
- server1
- server2
This produces:
.. code-block:: ansible-output
TASK [Create a single-entry dictionary] **************************************************
ok: [localhost] => {
"msg": {
"thatsmyvar": "myvalue"
}
}
TASK [Create a list of dictionaries where the 'server' field is taken from a list] *******
ok: [localhost] => {
"msg": [
{
"database": "all",
"server": "server1",
"type": "host"
},
{
"database": "all",
"server": "server2",
"type": "host"
}
]
}
.. versionadded:: 2.0.0
If you need to convert a list of key-value pairs to a dictionary, you can use the ``dict`` function. Unfortunately, this function cannot be used with ``map``. For this, the ``community.general.dict`` filter can be used:
.. code-block:: yaml+jinja
- name: Create a dictionary with the dict function
debug:
msg: "{{ dict([[1, 2], ['a', 'b']]) }}"
- name: Create a dictionary with the community.general.dict filter
debug:
msg: "{{ [[1, 2], ['a', 'b']] | community.general.dict }}"
- name: Create a list of dictionaries with map and the community.general.dict filter
debug:
msg: >-
{{ values | map('zip', ['k1', 'k2', 'k3'])
| map('map', 'reverse')
| map('community.general.dict') }}
vars:
values:
- - foo
- 23
- a
- - bar
- 42
- b
This produces:
.. code-block:: ansible-output
TASK [Create a dictionary with the dict function] ****************************************
ok: [localhost] => {
"msg": {
"1": 2,
"a": "b"
}
}
TASK [Create a dictionary with the community.general.dict filter] ************************
ok: [localhost] => {
"msg": {
"1": 2,
"a": "b"
}
}
TASK [Create a list of dictionaries with map and the community.general.dict filter] ******
ok: [localhost] => {
"msg": [
{
"k1": "foo",
"k2": 23,
"k3": "a"
},
{
"k1": "bar",
"k2": 42,
"k3": "b"
}
]
}
.. versionadded:: 3.0.0

View File

@@ -0,0 +1,98 @@
Grouping
^^^^^^^^
If you have a list of dictionaries, the Jinja2 ``groupby`` filter allows to group the list by an attribute. This results in a list of ``(grouper, list)`` namedtuples, where ``list`` contains all dictionaries where the selected attribute equals ``grouper``. If you know that for every ``grouper``, there will be a most one entry in that list, you can use the ``community.general.groupby_as_dict`` filter to convert the original list into a dictionary which maps ``grouper`` to the corresponding dictionary.
One example is ``ansible_facts.mounts``, which is a list of dictionaries where each has one ``device`` element to indicate the device which is mounted. Therefore, ``ansible_facts.mounts | community.general.groupby_as_dict('device')`` is a dictionary mapping a device to the mount information:
.. code-block:: yaml+jinja
- name: Output mount facts grouped by device name
debug:
var: ansible_facts.mounts | community.general.groupby_as_dict('device')
- name: Output mount facts grouped by mount point
debug:
var: ansible_facts.mounts | community.general.groupby_as_dict('mount')
This produces:
.. code-block:: ansible-output
TASK [Output mount facts grouped by device name] ******************************************
ok: [localhost] => {
"ansible_facts.mounts | community.general.groupby_as_dict('device')": {
"/dev/sda1": {
"block_available": 2000,
"block_size": 4096,
"block_total": 2345,
"block_used": 345,
"device": "/dev/sda1",
"fstype": "ext4",
"inode_available": 500,
"inode_total": 512,
"inode_used": 12,
"mount": "/boot",
"options": "rw,relatime,data=ordered",
"size_available": 56821,
"size_total": 543210,
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
},
"/dev/sda2": {
"block_available": 1234,
"block_size": 4096,
"block_total": 12345,
"block_used": 11111,
"device": "/dev/sda2",
"fstype": "ext4",
"inode_available": 1111,
"inode_total": 1234,
"inode_used": 123,
"mount": "/",
"options": "rw,relatime",
"size_available": 42143,
"size_total": 543210,
"uuid": "abcdef01-2345-6789-0abc-def012345678"
}
}
}
TASK [Output mount facts grouped by mount point] ******************************************
ok: [localhost] => {
"ansible_facts.mounts | community.general.groupby_as_dict('mount')": {
"/": {
"block_available": 1234,
"block_size": 4096,
"block_total": 12345,
"block_used": 11111,
"device": "/dev/sda2",
"fstype": "ext4",
"inode_available": 1111,
"inode_total": 1234,
"inode_used": 123,
"mount": "/",
"options": "rw,relatime",
"size_available": 42143,
"size_total": 543210,
"uuid": "bdf50b7d-4859-40af-8665-c637ee7a7808"
},
"/boot": {
"block_available": 2000,
"block_size": 4096,
"block_total": 2345,
"block_used": 345,
"device": "/dev/sda1",
"fstype": "ext4",
"inode_available": 500,
"inode_total": 512,
"inode_used": 12,
"mount": "/boot",
"options": "rw,relatime,data=ordered",
"size_available": 56821,
"size_total": 543210,
"uuid": "ab31cade-d9c1-484d-8482-8a4cbee5241a"
}
}
}
.. versionadded: 3.0.0

View File

@@ -0,0 +1,292 @@
Merging lists of dictionaries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have two or more lists of dictionaries and want to combine them into a list of merged dictionaries, where the dictionaries are merged by an attribute, you can use the ``lists_mergeby`` filter.
.. note:: The output of the examples in this section use the YAML callback plugin. Quoting: "Ansible output that can be quite a bit easier to read than the default JSON formatting." See :ref:`the documentation for the community.general.yaml callback plugin <ansible_collections.community.general.yaml_callback>`.
Let us use the lists below in the following examples:
.. code-block:: yaml
list1:
- name: foo
extra: true
- name: bar
extra: false
- name: meh
extra: true
list2:
- name: foo
path: /foo
- name: baz
path: /baz
In the example below the lists are merged by the attribute ``name``:
.. code-block:: yaml+jinja
list3: "{{ list1|
community.general.lists_mergeby(list2, 'name') }}"
This produces:
.. code-block:: yaml
list3:
- extra: false
name: bar
- name: baz
path: /baz
- extra: true
name: foo
path: /foo
- extra: true
name: meh
.. versionadded:: 2.0.0
It is possible to use a list of lists as an input of the filter:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name') }}"
This produces the same result as in the previous example:
.. code-block:: yaml
list3:
- extra: false
name: bar
- name: baz
path: /baz
- extra: true
name: foo
path: /foo
- extra: true
name: meh
The filter also accepts two optional parameters: ``recursive`` and ``list_merge``. These parameters are only supported when used with ansible-base 2.10 or ansible-core, but not with Ansible 2.9. This is available since community.general 4.4.0.
**recursive**
Is a boolean, default to ``False``. Should the ``community.general.lists_mergeby`` recursively merge nested hashes. Note: It does not depend on the value of the ``hash_behaviour`` setting in ``ansible.cfg``.
**list_merge**
Is a string, its possible values are ``replace`` (default), ``keep``, ``append``, ``prepend``, ``append_rp`` or ``prepend_rp``. It modifies the behaviour of ``community.general.lists_mergeby`` when the hashes to merge contain arrays/lists.
The examples below set ``recursive=true`` and display the differences among all six options of ``list_merge``. Functionality of the parameters is exactly the same as in the filter ``combine``. See :ref:`Combining hashes/dictionaries <combine_filter>` to learn details about these options.
Let us use the lists below in the following examples
.. code-block:: yaml
list1:
- name: myname01
param01:
x: default_value
y: default_value
list:
- default_value
- name: myname02
param01: [1, 1, 2, 3]
list2:
- name: myname01
param01:
y: patch_value
z: patch_value
list:
- patch_value
- name: myname02
param01: [3, 4, 4, {key: value}]
Example ``list_merge=replace`` (default):
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true) }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- patch_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 3
- 4
- 4
- key: value
Example ``list_merge=keep``:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='keep') }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- default_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 1
- 1
- 2
- 3
Example ``list_merge=append``:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='append') }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- default_value
- patch_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 1
- 1
- 2
- 3
- 3
- 4
- 4
- key: value
Example ``list_merge=prepend``:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='prepend') }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- patch_value
- default_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 3
- 4
- 4
- key: value
- 1
- 1
- 2
- 3
Example ``list_merge=append_rp``:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='append_rp') }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- default_value
- patch_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 1
- 1
- 2
- 3
- 4
- 4
- key: value
Example ``list_merge=prepend_rp``:
.. code-block:: yaml+jinja
list3: "{{ [list1, list2]|
community.general.lists_mergeby('name',
recursive=true,
list_merge='prepend_rp') }}"
This produces:
.. code-block:: yaml
list3:
- name: myname01
param01:
list:
- patch_value
- default_value
x: default_value
y: patch_value
z: patch_value
- name: myname02
param01:
- 3
- 4
- 4
- key: value
- 1
- 1
- 2

View File

@@ -0,0 +1,108 @@
Conversions
-----------
Parsing CSV files
^^^^^^^^^^^^^^^^^
Ansible offers the :ref:`community.general.read_csv module <ansible_collections.community.general.read_csv_module>` to read CSV files. Sometimes you need to convert strings to CSV files instead. For this, the ``from_csv`` filter exists.
.. code-block:: yaml+jinja
- name: "Parse CSV from string"
debug:
msg: "{{ csv_string | community.general.from_csv }}"
vars:
csv_string: |
foo,bar,baz
1,2,3
you,this,then
This produces:
.. code-block:: ansible-output
TASK [Parse CSV from string] **************************************************************
ok: [localhost] => {
"msg": [
{
"bar": "2",
"baz": "3",
"foo": "1"
},
{
"bar": "this",
"baz": "then",
"foo": "you"
}
]
}
The ``from_csv`` filter has several keyword arguments to control its behavior:
:dialect: Dialect of the CSV file. Default is ``excel``. Other possible choices are ``excel-tab`` and ``unix``. If one of ``delimiter``, ``skipinitialspace`` or ``strict`` is specified, ``dialect`` is ignored.
:fieldnames: A set of column names to use. If not provided, the first line of the CSV is assumed to contain the column names.
:delimiter: Sets the delimiter to use. Default depends on the dialect used.
:skipinitialspace: Set to ``true`` to ignore space directly after the delimiter. Default depends on the dialect used (usually ``false``).
:strict: Set to ``true`` to error out on invalid CSV input.
.. versionadded: 3.0.0
Converting to JSON
^^^^^^^^^^^^^^^^^^
`JC <https://pypi.org/project/jc/>`_ is a CLI tool and Python library which allows to interpret output of various CLI programs as JSON. It is also available as a filter in community.general. This filter needs the `jc Python library <https://pypi.org/project/jc/>`_ installed on the controller.
.. code-block:: yaml+jinja
- name: Run 'ls' to list files in /
command: ls /
register: result
- name: Parse the ls output
debug:
msg: "{{ result.stdout | community.general.jc('ls') }}"
This produces:
.. code-block:: ansible-output
TASK [Run 'ls' to list files in /] ********************************************************
changed: [localhost]
TASK [Parse the ls output] ****************************************************************
ok: [localhost] => {
"msg": [
{
"filename": "bin"
},
{
"filename": "boot"
},
{
"filename": "dev"
},
{
"filename": "etc"
},
{
"filename": "home"
},
{
"filename": "lib"
},
{
"filename": "proc"
},
{
"filename": "root"
},
{
"filename": "run"
},
{
"filename": "tmp"
}
]
}
.. versionadded: 2.0.0

View File

@@ -0,0 +1,80 @@
Creating identifiers
--------------------
The following filters allow to create identifiers.
Hashids
^^^^^^^
`Hashids <https://hashids.org/>`_ allow to convert sequences of integers to short unique string identifiers. This filter needs the `hashids Python library <https://pypi.org/project/hashids/>`_ installed on the controller.
.. code-block:: yaml+jinja
- name: "Create hashid"
debug:
msg: "{{ [1234, 5, 6] | community.general.hashids_encode }}"
- name: "Decode hashid"
debug:
msg: "{{ 'jm2Cytn' | community.general.hashids_decode }}"
This produces:
.. code-block:: ansible-output
TASK [Create hashid] **********************************************************************
ok: [localhost] => {
"msg": "jm2Cytn"
}
TASK [Decode hashid] **********************************************************************
ok: [localhost] => {
"msg": [
1234,
5,
6
]
}
The hashids filters accept keyword arguments to allow fine-tuning the hashids generated:
:salt: String to use as salt when hashing.
:alphabet: String of 16 or more unique characters to produce a hash.
:min_length: Minimum length of hash produced.
.. versionadded: 3.0.0
Random MACs
^^^^^^^^^^^
You can use the ``random_mac`` filter to complete a partial `MAC address <https://en.wikipedia.org/wiki/MAC_address>`_ to a random 6-byte MAC address.
.. code-block:: yaml+jinja
- name: "Create a random MAC starting with ff:"
debug:
msg: "{{ 'FF' | community.general.random_mac }}"
- name: "Create a random MAC starting with 00:11:22:"
debug:
msg: "{{ '00:11:22' | community.general.random_mac }}"
This produces:
.. code-block:: ansible-output
TASK [Create a random MAC starting with ff:] **********************************************
ok: [localhost] => {
"msg": "ff:69:d3:78:7f:b4"
}
TASK [Create a random MAC starting with 00:11:22:] ****************************************
ok: [localhost] => {
"msg": "00:11:22:71:5d:3b"
}
You can also initialize the random number generator from a seed to create random-but-idempotent MAC addresses:
.. code-block:: yaml+jinja
"{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"

View File

@@ -0,0 +1,14 @@
Paths
-----
The ``path_join`` filter has been added in ansible-base 2.10. If you want to use this filter, but also need to support Ansible 2.9, you can use ``community.general``'s ``path_join`` shim, ``community.general.path_join``. This filter redirects to ``path_join`` for ansible-base 2.10 and ansible-core 2.11 or newer, and re-implements the filter for Ansible 2.9.
.. code-block:: yaml+jinja
# ansible-base 2.10 or newer:
path: {{ ('/etc', path, 'subdir', file) | path_join }}
# Also works with Ansible 2.9:
path: {{ ('/etc', path, 'subdir', file) | community.general.path_join }}
.. versionadded:: 3.0.0

View File

@@ -0,0 +1,144 @@
.. _ansible_collections.community.general.docsite.json_query_filter:
Selecting JSON data: JSON queries
---------------------------------
To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use the ``json_query`` filter. The ``json_query`` filter lets you query a complex JSON structure and iterate over it using a loop structure.
.. note:: You must manually install the **jmespath** dependency on the Ansible controller before using this filter. This filter is built upon **jmespath**, and you can use the same syntax. For examples, see `jmespath examples <http://jmespath.org/examples.html>`_.
Consider this data structure:
.. code-block:: yaml+jinja
{
"domain_definition": {
"domain": {
"cluster": [
{
"name": "cluster1"
},
{
"name": "cluster2"
}
],
"server": [
{
"name": "server11",
"cluster": "cluster1",
"port": "8080"
},
{
"name": "server12",
"cluster": "cluster1",
"port": "8090"
},
{
"name": "server21",
"cluster": "cluster2",
"port": "9080"
},
{
"name": "server22",
"cluster": "cluster2",
"port": "9090"
}
],
"library": [
{
"name": "lib1",
"target": "cluster1"
},
{
"name": "lib2",
"target": "cluster2"
}
]
}
}
}
To extract all clusters from this structure, you can use the following query:
.. code-block:: yaml+jinja
- name: Display all cluster names
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"
To extract all server names:
.. code-block:: yaml+jinja
- name: Display all server names
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}"
To extract ports from cluster1:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
vars:
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"
.. note:: You can use a variable to make the query more readable.
To print out the ports from cluster1 in a comma separated string:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1 as a string
ansible.builtin.debug:
msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"
.. note:: In the example above, quoting literals using backticks avoids escaping quotes and maintains readability.
You can use YAML `single quote escaping <https://yaml.org/spec/current.html#id2534365>`_:
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
var: item
loop: "{{ domain_definition | community.general.json_query('domain.server[?cluster==''cluster1''].port') }}"
.. note:: Escaping single quotes within single quotes in YAML is done by doubling the single quote.
To get a hash map with all ports and names of a cluster:
.. code-block:: yaml+jinja
- name: Display all server ports and names from cluster1
ansible.builtin.debug:
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}"
To extract ports from all clusters with name starting with 'server1':
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
vars:
server_name_query: "domain.server[?starts_with(name,'server1')].port"
To extract ports from all clusters with name containing 'server1':
.. code-block:: yaml+jinja
- name: Display all ports from cluster1
ansible.builtin.debug:
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
vars:
server_name_query: "domain.server[?contains(name,'server1')].port"
.. note:: while using ``starts_with`` and ``contains``, you have to use `` to_json | from_json `` filter for correct parsing of data structure.

View File

@@ -0,0 +1,84 @@
Working with times
------------------
The ``to_time_unit`` filter allows to convert times from a human-readable string to a unit. For example, ``'4h 30min 12second' | community.general.to_time_unit('hour')`` gives the number of hours that correspond to 4 hours, 30 minutes and 12 seconds.
There are shorthands to directly convert to various units, like ``to_hours``, ``to_minutes``, ``to_seconds``, and so on. The following table lists all units that can be used:
.. list-table:: Units
:widths: 25 25 25 25
:header-rows: 1
* - Unit name
- Unit value in seconds
- Unit strings for filter
- Shorthand filter
* - Millisecond
- 1/1000 second
- ``ms``, ``millisecond``, ``milliseconds``, ``msec``, ``msecs``, ``msecond``, ``mseconds``
- ``to_milliseconds``
* - Second
- 1 second
- ``s``, ``sec``, ``secs``, ``second``, ``seconds``
- ``to_seconds``
* - Minute
- 60 seconds
- ``m``, ``min``, ``mins``, ``minute``, ``minutes``
- ``to_minutes``
* - Hour
- 60*60 seconds
- ``h``, ``hour``, ``hours``
- ``to_hours``
* - Day
- 24*60*60 seconds
- ``d``, ``day``, ``days``
- ``to_days``
* - Week
- 7*24*60*60 seconds
- ``w``, ``week``, ``weeks``
- ``to_weeks``
* - Month
- 30*24*60*60 seconds
- ``mo``, ``month``, ``months``
- ``to_months``
* - Year
- 365*24*60*60 seconds
- ``y``, ``year``, ``years``
- ``to_years``
Note that months and years are using a simplified representation: a month is 30 days, and a year is 365 days. If you need different definitions of months or years, you can pass them as keyword arguments. For example, if you want a year to be 365.25 days, and a month to be 30.5 days, you can write ``'11months 4' | community.general.to_years(year=365.25, month=30.5)``. These keyword arguments can be specified to ``to_time_unit`` and to all shorthand filters.
.. code-block:: yaml+jinja
- name: Convert string to seconds
debug:
msg: "{{ '30h 20m 10s 123ms' | community.general.to_time_unit('seconds') }}"
- name: Convert string to hours
debug:
msg: "{{ '30h 20m 10s 123ms' | community.general.to_hours }}"
- name: Convert string to years (using 365.25 days == 1 year)
debug:
msg: "{{ '400d 15h' | community.general.to_years(year=365.25) }}"
This produces:
.. code-block:: ansible-output
TASK [Convert string to seconds] **********************************************************
ok: [localhost] => {
"msg": "109210.123"
}
TASK [Convert string to hours] ************************************************************
ok: [localhost] => {
"msg": "30.336145277778"
}
TASK [Convert string to years (using 365.25 days == 1 year)] ******************************
ok: [localhost] => {
"msg": "1.096851471595"
}
.. versionadded: 0.2.0

View File

@@ -0,0 +1,30 @@
Working with Unicode
---------------------
`Unicode <https://unicode.org/main.html>`_ makes it possible to produce two strings which may be visually equivalent, but are comprised of distinctly different characters/character sequences. To address this ``Unicode`` defines `normalization forms <https://unicode.org/reports/tr15/>`_ which avoid these distinctions by choosing a unique character sequence for a given visual representation.
You can use the ``community.general.unicode_normalize`` filter to normalize ``Unicode`` strings within your playbooks.
.. code-block:: yaml+jinja
- name: Compare Unicode representations
debug:
msg: "{{ with_combining_character | community.general.unicode_normalize == without_combining_character }}"
vars:
with_combining_character: "{{ 'Mayagu\u0308ez' }}"
without_combining_character: Mayagüez
This produces:
.. code-block:: ansible-output
TASK [Compare Unicode representations] ********************************************************
ok: [localhost] => {
"msg": true
}
The ``community.general.unicode_normalize`` filter accepts a keyword argument to select the ``Unicode`` form used to normalize the input string.
:form: One of ``'NFC'`` (default), ``'NFD'``, ``'NFKC'``, or ``'NFKD'``. See the `Unicode reference <https://unicode.org/reports/tr15/>`_ for more information.
.. versionadded:: 3.7.0

View File

@@ -0,0 +1,34 @@
Working with versions
---------------------
If you need to sort a list of version numbers, the Jinja ``sort`` filter is problematic. Since it sorts lexicographically, ``2.10`` will come before ``2.9``. To treat version numbers correctly, you can use the ``version_sort`` filter:
.. code-block:: yaml+jinja
- name: Sort list by version number
debug:
var: ansible_versions | community.general.version_sort
vars:
ansible_versions:
- '2.8.0'
- '2.11.0'
- '2.7.0'
- '2.10.0'
- '2.9.0'
This produces:
.. code-block:: ansible-output
TASK [Sort list by version number] ********************************************************
ok: [localhost] => {
"ansible_versions | community.general.version_sort": [
"2.7.0",
"2.8.0",
"2.9.0",
"2.10.0",
"2.11.0"
]
}
.. versionadded: 2.2.0

View File

@@ -1,6 +1,6 @@
namespace: community
name: general
version: 4.2.0
version: 4.7.0
readme: README.md
authors:
- Ansible (https://github.com/ansible)

View File

@@ -20,6 +20,7 @@ DOCUMENTATION = '''
- List of connection information for the memcached DBs
default: ['127.0.0.1:11211']
type: list
elements: string
env:
- name: ANSIBLE_CACHE_PLUGIN_CONNECTION
ini:

View File

@@ -11,14 +11,16 @@ name: mail
type: notification
short_description: Sends failure events via email
description:
- This callback will report failures via email
- This callback will report failures via email.
author:
- Dag Wieers (@dagwieers)
requirements:
- whitelisting in configuration
options:
mta:
description: Mail Transfer Agent, server that accepts SMTP
description:
- Mail Transfer Agent, server that accepts SMTP.
type: str
env:
- name: SMTPHOST
ini:
@@ -26,39 +28,53 @@ options:
key: smtphost
default: localhost
mtaport:
description: Mail Transfer Agent Port, port at which server SMTP
description:
- Mail Transfer Agent Port.
- Port at which server SMTP.
type: int
ini:
- section: callback_mail
key: smtpport
default: 25
to:
description: Mail recipient
description:
- Mail recipient.
type: list
elements: str
ini:
- section: callback_mail
key: to
default: root
default: [root]
sender:
description: Mail sender
description:
- Mail sender.
- Note that this will be required from community.general 6.0.0 on.
type: str
ini:
- section: callback_mail
key: sender
cc:
description: CC'd recipient
description:
- CC'd recipients.
type: list
elements: str
ini:
- section: callback_mail
key: cc
bcc:
description: BCC'd recipient
description:
- BCC'd recipients.
type: list
elements: str
ini:
- section: callback_mail
key: bcc
notes:
- "TODO: expand configuration options now that plugins can leverage Ansible's configuration"
'''
import json
import os
import re
import email.utils
import smtplib
from ansible.module_utils.six import string_types
@@ -88,9 +104,13 @@ class CallbackModule(CallbackBase):
super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
self.sender = self.get_option('sender')
if self.sender is None:
self._display.deprecated(
'The sender for the mail callback has not been specified. This will be an error in the future',
version='6.0.0', collection_name='community.general')
self.to = self.get_option('to')
self.smtphost = self.get_option('mta')
self.smtpport = int(self.get_option('mtaport'))
self.smtpport = self.get_option('mtaport')
self.cc = self.get_option('cc')
self.bcc = self.get_option('bcc')
@@ -100,28 +120,34 @@ class CallbackModule(CallbackBase):
smtp = smtplib.SMTP(self.smtphost, port=self.smtpport)
b_sender = to_bytes(self.sender)
b_to = to_bytes(self.to)
b_cc = to_bytes(self.cc)
b_bcc = to_bytes(self.bcc)
b_subject = to_bytes(subject)
b_body = to_bytes(body)
b_content = b'From: %s\n' % b_sender
b_content += b'To: %s\n' % b_to
sender_address = email.utils.parseaddr(self.sender)
if self.to:
to_addresses = email.utils.getaddresses(self.to)
if self.cc:
b_content += b'Cc: %s\n' % b_cc
b_content += b'Subject: %s\n\n' % b_subject
b_content += b_body
b_addresses = b_to.split(b',')
if self.cc:
b_addresses += b_cc.split(b',')
cc_addresses = email.utils.getaddresses(self.cc)
if self.bcc:
b_addresses += b_bcc.split(b',')
bcc_addresses = email.utils.getaddresses(self.bcc)
for b_address in b_addresses:
smtp.sendmail(b_sender, b_address, b_content)
content = 'Date: %s\n' % email.utils.formatdate()
content += 'From: %s\n' % email.utils.formataddr(sender_address)
if self.to:
content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
if self.cc:
content += 'Cc: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in cc_addresses])
content += 'Message-ID: %s\n' % email.utils.make_msgid()
content += 'Subject: %s\n\n' % subject.strip()
content += body
addresses = to_addresses
if self.cc:
addresses += cc_addresses
if self.bcc:
addresses += bcc_addresses
if not addresses:
self._display.warning('No receiver has been specified for the mail callback plugin.')
smtp.sendmail(self.sender, [address for name, address in addresses], to_bytes(content))
smtp.quit()

View File

@@ -319,9 +319,9 @@ class OpenTelemetrySource(object):
@staticmethod
def url_from_args(args):
# the order matters
url_args = ("url", "api_url", "baseurl", "repo", "server_url", "chart_repo_url")
url_args = ("url", "api_url", "baseurl", "repo", "server_url", "chart_repo_url", "registry_url", "endpoint", "uri", "updates_url")
for arg in url_args:
if args.get(arg):
if args is not None and args.get(arg):
return args.get(arg)
return ""

View File

@@ -21,11 +21,11 @@ DOCUMENTATION = '''
- In 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
'''
import distutils.spawn
import platform
import subprocess
import os
from ansible.module_utils.common.process import get_bin_path
from ansible.plugins.callback import CallbackBase
@@ -47,21 +47,24 @@ class CallbackModule(CallbackBase):
self.HAPPY_VOICE = None
self.LASER_VOICE = None
self.synthesizer = distutils.spawn.find_executable('say')
if not self.synthesizer:
self.synthesizer = distutils.spawn.find_executable('espeak')
if self.synthesizer:
try:
self.synthesizer = get_bin_path('say')
if platform.system() != 'Darwin':
# 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter
self._display.warning("'say' executable found but system is '%s': ignoring voice parameter" % platform.system())
else:
self.FAILED_VOICE = 'Zarvox'
self.REGULAR_VOICE = 'Trinoids'
self.HAPPY_VOICE = 'Cellos'
self.LASER_VOICE = 'Princess'
except ValueError:
try:
self.synthesizer = get_bin_path('espeak')
self.FAILED_VOICE = 'klatt'
self.HAPPY_VOICE = 'f5'
self.LASER_VOICE = 'whisper'
elif platform.system() != 'Darwin':
# 'say' binary available, it might be GNUstep tool which doesn't support 'voice' parameter
self._display.warning("'say' executable found but system is '%s': ignoring voice parameter" % platform.system())
else:
self.FAILED_VOICE = 'Zarvox'
self.REGULAR_VOICE = 'Trinoids'
self.HAPPY_VOICE = 'Cellos'
self.LASER_VOICE = 'Princess'
except ValueError:
self.synthesizer = None
# plugin disable itself if say is not present
# ansible will not call any callback if disabled is set to True

View File

@@ -41,6 +41,16 @@ DOCUMENTATION = '''
ini:
- section: callback_syslog_json
key: syslog_facility
setup:
description: Log setup tasks.
env:
- name: ANSIBLE_SYSLOG_SETUP
type: bool
default: true
ini:
- section: callback_syslog_json
key: syslog_setup
version_added: 4.5.0
'''
import os
@@ -86,23 +96,36 @@ class CallbackModule(CallbackBase):
self.logger.addHandler(self.handler)
self.hostname = socket.gethostname()
def runner_on_failed(self, host, res, ignore_errors=False):
def v2_runner_on_failed(self, result, ignore_errors=False):
res = result._result
host = result._host.get_name()
self.logger.error('%s ansible-command: task execution FAILED; host: %s; message: %s', self.hostname, host, self._dump_results(res))
def runner_on_ok(self, host, res):
self.logger.info('%s ansible-command: task execution OK; host: %s; message: %s', self.hostname, host, self._dump_results(res))
def v2_runner_on_ok(self, result):
res = result._result
host = result._host.get_name()
if result._task.action != "gather_facts" or self.get_option("setup"):
self.logger.info('%s ansible-command: task execution OK; host: %s; message: %s', self.hostname, host, self._dump_results(res))
def runner_on_skipped(self, host, item=None):
def v2_runner_on_skipped(self, result):
host = result._host.get_name()
self.logger.info('%s ansible-command: task execution SKIPPED; host: %s; message: %s', self.hostname, host, 'skipped')
def runner_on_unreachable(self, host, res):
def v2_runner_on_unreachable(self, result):
res = result._result
host = result._host.get_name()
self.logger.error('%s ansible-command: task execution UNREACHABLE; host: %s; message: %s', self.hostname, host, self._dump_results(res))
def runner_on_async_failed(self, host, res, jid):
def v2_runner_on_async_failed(self, result):
res = result._result
host = result._host.get_name()
jid = result._result.get('ansible_job_id')
self.logger.error('%s ansible-command: task execution FAILED; host: %s; message: %s', self.hostname, host, self._dump_results(res))
def playbook_on_import_for_host(self, host, imported_file):
def v2_playbook_on_import_for_host(self, result, imported_file):
host = result._host.get_name()
self.logger.info('%s ansible-command: playbook IMPORTED; host: %s; message: imported file %s', self.hostname, host, imported_file)
def playbook_on_not_import_for_host(self, host, missing_file):
def v2_playbook_on_not_import_for_host(self, result, missing_file):
host = result._host.get_name()
self.logger.info('%s ansible-command: playbook NOT IMPORTED; host: %s; message: missing file %s', self.hostname, host, missing_file)

View File

@@ -31,7 +31,6 @@ DOCUMENTATION = '''
- name: ansible_jail_user
'''
import distutils.spawn
import os
import os.path
import subprocess
@@ -39,6 +38,7 @@ import traceback
from ansible.errors import AnsibleError
from ansible.module_utils.six.moves import shlex_quote
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.plugins.connection import ConnectionBase, BUFSIZE
from ansible.utils.display import Display
@@ -75,10 +75,10 @@ class Connection(ConnectionBase):
@staticmethod
def _search_executable(executable):
cmd = distutils.spawn.find_executable(executable)
if not cmd:
try:
return get_bin_path(executable)
except ValueError:
raise AnsibleError("%s command not found in PATH" % executable)
return cmd
def list_jails(self):
p = subprocess.Popen([self.jls_cmd, '-q', 'name'],

View File

@@ -43,10 +43,10 @@ DOCUMENTATION = '''
'''
import os
from distutils.spawn import find_executable
from subprocess import Popen, PIPE
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.text.converters import to_bytes, to_text
from ansible.plugins.connection import ConnectionBase
@@ -62,9 +62,9 @@ class Connection(ConnectionBase):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
self._host = self._play_context.remote_addr
self._lxc_cmd = find_executable("lxc")
if not self._lxc_cmd:
try:
self._lxc_cmd = get_bin_path("lxc")
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':

View File

@@ -26,7 +26,6 @@ DOCUMENTATION = '''
- name: ansible_zone_host
'''
import distutils.spawn
import os
import os.path
import subprocess
@@ -34,6 +33,7 @@ import traceback
from ansible.errors import AnsibleError
from ansible.module_utils.six.moves import shlex_quote
from ansible.module_utils.common.process import get_bin_path
from ansible.module_utils.common.text.converters import to_bytes
from ansible.plugins.connection import ConnectionBase, BUFSIZE
from ansible.utils.display import Display
@@ -64,10 +64,10 @@ class Connection(ConnectionBase):
@staticmethod
def _search_executable(executable):
cmd = distutils.spawn.find_executable(executable)
if not cmd:
try:
return get_bin_path(executable)
except ValueError:
raise AnsibleError("%s command not found in PATH" % executable)
return cmd
def list_zones(self):
process = subprocess.Popen([self.zoneadm_cmd, 'list', '-ip'],

View File

@@ -61,4 +61,11 @@ options:
- Verify TLS certificates (do not disable this in production).
type: bool
default: yes
connection_timeout:
description:
- Controls the HTTP connections timeout period (in seconds) to Keycloak API.
type: int
default: 10
version_added: 4.5.0
'''

View File

@@ -38,8 +38,10 @@ options:
version_added: 2.0.0
server_uri:
description:
- A URI to the LDAP server.
- The I(server_uri) parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host, and the port fields.
- The default value lets the underlying LDAP client library look for a UNIX domain socket in its default location.
- Note that when using multiple URIs you cannot determine to which URI your client gets connected.
- For URIs containing additional fields, particularly when using commas, behavior is undefined.
type: str
default: ldapi:///
start_tls:

36
plugins/filter/counter.py Normal file
View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Remy Keil <remy.keil@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleFilterError
from ansible.module_utils.common._collections_compat import Sequence
from collections import Counter
def counter(sequence):
''' Count elements in a sequence. Returns dict with count result. '''
if not isinstance(sequence, Sequence):
raise AnsibleFilterError('Argument for community.general.counter must be a sequence (string or list). %s is %s' %
(sequence, type(sequence)))
try:
result = dict(Counter(sequence))
except TypeError as e:
raise AnsibleFilterError(
"community.general.counter needs a sequence with hashable elements (int, float or str) - %s" % (e)
)
return result
class FilterModule(object):
''' Ansible counter jinja2 filters '''
def filters(self):
filters = {
'counter': counter,
}
return filters

View File

@@ -1,43 +1,113 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Vladimir Botka <vbotka@gmail.com>
# Copyright (c) 2020-2022, Vladimir Botka <vbotka@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError, AnsibleFilterError
from ansible.errors import AnsibleFilterError
from ansible.module_utils.six import string_types
from ansible.module_utils.common._collections_compat import Mapping, Sequence
from ansible.utils.vars import merge_hash
from ansible.release import __version__ as ansible_version
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
from collections import defaultdict
from operator import itemgetter
def lists_mergeby(l1, l2, index):
''' merge lists by attribute index. Example:
- debug: msg="{{ l1|community.general.lists_mergeby(l2, 'index')|list }}" '''
def merge_hash_wrapper(x, y, recursive=False, list_merge='replace'):
''' Wrapper of the function merge_hash from ansible.utils.vars. Only 2 paramaters are allowed
for Ansible 2.9 and lower.'''
if not isinstance(l1, Sequence):
raise AnsibleFilterError('First argument for community.general.lists_mergeby must be list. %s is %s' %
(l1, type(l1)))
if LooseVersion(ansible_version) < LooseVersion('2.10'):
if list_merge != 'replace' or recursive:
msg = ("Non default options of list_merge(default=replace) or recursive(default=False) "
"are not allowed in Ansible version 2.9 or lower. Ansible version is %s, "
"recursive=%s, and list_merge=%s.")
raise AnsibleFilterError(msg % (ansible_version, recursive, list_merge))
else:
return merge_hash(x, y)
else:
return merge_hash(x, y, recursive, list_merge)
if not isinstance(l2, Sequence):
raise AnsibleFilterError('Second argument for community.general.lists_mergeby must be list. %s is %s' %
(l2, type(l2)))
if not isinstance(index, string_types):
raise AnsibleFilterError('Third argument for community.general.lists_mergeby must be string. %s is %s' %
(index, type(index)))
def list_mergeby(x, y, index, recursive=False, list_merge='replace'):
''' Merge 2 lists by attribute 'index'. The function merge_hash from ansible.utils.vars is used.
This function is used by the function lists_mergeby.
'''
d = defaultdict(dict)
for l in (l1, l2):
for l in (x, y):
for elem in l:
if not isinstance(elem, Mapping):
raise AnsibleFilterError('Elements of list arguments for lists_mergeby must be dictionaries. Found {0!r}.'.format(elem))
msg = "Elements of list arguments for lists_mergeby must be dictionaries. %s is %s"
raise AnsibleFilterError(msg % (elem, type(elem)))
if index in elem.keys():
d[elem[index]].update(elem)
d[elem[index]].update(merge_hash_wrapper(d[elem[index]], elem, recursive, list_merge))
return sorted(d.values(), key=itemgetter(index))
def lists_mergeby(*terms, **kwargs):
''' Merge 2 or more lists by attribute 'index'. Optional parameters 'recursive' and 'list_merge'
control the merging of the lists in values. The function merge_hash from ansible.utils.vars
is used. To learn details on how to use the parameters 'recursive' and 'list_merge' see
Ansible User's Guide chapter "Using filters to manipulate data" section "Combining
hashes/dictionaries".
Example:
- debug:
msg: "{{ list1|
community.general.lists_mergeby(list2,
'index',
recursive=True,
list_merge='append')|
list }}"
'''
recursive = kwargs.pop('recursive', False)
list_merge = kwargs.pop('list_merge', 'replace')
if kwargs:
raise AnsibleFilterError("'recursive' and 'list_merge' are the only valid keyword arguments.")
if len(terms) < 2:
raise AnsibleFilterError("At least one list and index are needed.")
# allow the user to do `[list1, list2, ...] | lists_mergeby('index')`
flat_list = []
for sublist in terms[:-1]:
if not isinstance(sublist, Sequence):
msg = ("All arguments before the argument index for community.general.lists_mergeby "
"must be lists. %s is %s")
raise AnsibleFilterError(msg % (sublist, type(sublist)))
if len(sublist) > 0:
if all(isinstance(l, Sequence) for l in sublist):
for item in sublist:
flat_list.append(item)
else:
flat_list.append(sublist)
lists = flat_list
if not lists:
return []
if len(lists) == 1:
return lists[0]
index = terms[-1]
if not isinstance(index, string_types):
msg = ("First argument after the lists for community.general.lists_mergeby must be string. "
"%s is %s")
raise AnsibleFilterError(msg % (index, type(index)))
high_to_low_prio_list_iterator = reversed(lists)
result = next(high_to_low_prio_list_iterator)
for list in high_to_low_prio_list_iterator:
result = list_mergeby(list, result, index, recursive, list_merge)
return result
class FilterModule(object):
''' Ansible list filters '''

View File

@@ -5,7 +5,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
def version_sort(value, reverse=False):

View File

@@ -40,13 +40,25 @@ DOCUMENTATION = '''
type: boolean
default: no
exclude_profiles:
description: Profiles to exclude from inventory
description:
- Profiles to exclude from inventory.
- Ignored if I(include_profiles) is specified.
type: list
default: []
elements: str
include_profiles:
description:
- Profiles to include from inventory.
- If specified, all other profiles will be excluded.
- I(exclude_profiles) is ignored if I(include_profiles) is specified.
type: list
default: []
elements: str
version_added: 4.4.0
group_by:
description: Keys to group hosts by
type: list
elements: string
default: [ 'mgmt_classes', 'owners', 'status' ]
group:
description: Group to place all hosts into
@@ -68,12 +80,10 @@ user: ansible-tester
password: secure
'''
from distutils.version import LooseVersion
import socket
from ansible.errors import AnsibleError
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.common._collections_compat import MutableMapping
from ansible.module_utils.common.text.converters import to_text
from ansible.module_utils.six import iteritems
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, to_safe_group_name
@@ -95,18 +105,9 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
NAME = 'community.general.cobbler'
def __init__(self):
super(InventoryModule, self).__init__()
# from config
self.cobbler_url = None
self.exclude_profiles = [] # A list of profiles to exclude
self.connection = None
self.token = None
self.cache_key = None
self.use_cache = None
self.connection = None
def verify_file(self, path):
valid = False
@@ -178,6 +179,12 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.inventory.add_child(group_name, child)
return group_name
def _exclude_profile(self, profile):
if self.include_profiles:
return profile not in self.include_profiles
else:
return profile in self.exclude_profiles
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path)
@@ -191,15 +198,16 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
self.use_cache = cache and self.get_option('cache')
self.exclude_profiles = self.get_option('exclude_profiles')
self.include_profiles = self.get_option('include_profiles')
self.group_by = self.get_option('group_by')
for profile in self._get_profiles():
if profile['parent']:
self.display.vvvv('Processing profile %s with parent %s\n' % (profile['name'], profile['parent']))
if profile['parent'] not in self.exclude_profiles:
if not self._exclude_profile(profile['parent']):
parent_group_name = self._add_safe_group_name(profile['parent'])
self.display.vvvv('Added profile parent group %s\n' % parent_group_name)
if profile['name'] not in self.exclude_profiles:
if not self._exclude_profile(profile['name']):
group_name = self._add_safe_group_name(profile['name'])
self.display.vvvv('Added profile group %s\n' % group_name)
self.inventory.add_child(parent_group_name, group_name)
@@ -211,7 +219,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
while i < len(profile_elements) - 1:
profile_group = '-'.join(profile_elements[0:i + 1])
profile_group_child = '-'.join(profile_elements[0:i + 2])
if profile_group in self.exclude_profiles:
if self._exclude_profile(profile_group):
self.display.vvvv('Excluding profile %s\n' % profile_group)
break
group_name = self._add_safe_group_name(profile_group)
@@ -232,7 +240,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
hostname = host['hostname'] # None
interfaces = host['interfaces']
if host['profile'] in self.exclude_profiles:
if self._exclude_profile(host['profile']):
self.display.vvvv('Excluding host %s in profile %s\n' % (host['name'], host['profile']))
continue

View File

@@ -35,7 +35,6 @@ DOCUMENTATION = '''
version_added: 1.0.0
type: str
required: true
default: https://gitlab.com
api_token:
description: GitLab token for logging in.
env:

View File

@@ -16,7 +16,17 @@ DOCUMENTATION = '''
- Get inventory hosts from the Icinga2 API.
- "Uses a configuration file as an inventory source, it must end in
C(.icinga2.yml) or C(.icinga2.yaml)."
extends_documentation_fragment:
- constructed
options:
strict:
version_added: 4.4.0
compose:
version_added: 4.4.0
groups:
version_added: 4.4.0
keyed_groups:
version_added: 4.4.0
plugin:
description: Name of the plugin.
required: true
@@ -63,6 +73,20 @@ password: secure
host_filter: \"linux-servers\" in host.groups
validate_certs: false
inventory_attr: name
groups:
# simple name matching
webservers: inventory_hostname.startswith('web')
# using icinga2 template
databaseservers: "'db-template' in (icinga2_attributes.templates|list)"
compose:
# set all icinga2 attributes to a host variable 'icinga2_attrs'
icinga2_attrs: icinga2_attributes
# set 'ansible_user' and 'ansible_port' from icinga2 host vars
ansible_user: icinga2_attributes.vars.ansible_user
ansible_port: icinga2_attributes.vars.ansible_port | default(22)
'''
import json
@@ -180,7 +204,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
"""Query for all hosts """
self.display.vvv("Querying Icinga2 for inventory")
query_args = {
"attrs": ["address", "display_name", "state_type", "state", "groups"],
"attrs": ["address", "address6", "name", "display_name", "state_type", "state", "templates", "groups", "vars", "zone"],
}
if self.host_filter is not None:
query_args['host_filter'] = self.host_filter
@@ -190,6 +214,12 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
ansible_inv = self._convert_inv(results_json)
return ansible_inv
def _apply_constructable(self, name, variables):
strict = self.get_option('strict')
self._add_host_to_composed_groups(self.get_option('groups'), variables, name, strict=strict)
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), variables, name, strict=strict)
self._set_composite_vars(self.get_option('compose'), variables, name, strict=strict)
def _populate(self):
groups = self._to_json(self.get_inventory_from_icinga())
return groups
@@ -232,6 +262,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
host_attrs['state'])
self.inventory.set_variable(host_name, 'state_type',
host_attrs['state_type'])
# Adds all attributes to a variable 'icinga2_attributes'
construct_vars = dict(self.inventory.get_host(host_name).get_vars())
construct_vars['icinga2_attributes'] = host_attrs
self._apply_constructable(host_name, construct_vars)
return groups_dict
def parse(self, inventory, loader, path, cache=True):

View File

@@ -21,7 +21,18 @@ DOCUMENTATION = r'''
Linode) and not tags.
extends_documentation_fragment:
- constructed
- inventory_cache
options:
cache:
version_added: 4.5.0
cache_plugin:
version_added: 4.5.0
cache_timeout:
version_added: 4.5.0
cache_connection:
version_added: 4.5.0
cache_prefix:
version_added: 4.5.0
plugin:
description: Marks this as an instance of the 'linode' plugin.
required: true
@@ -43,15 +54,18 @@ DOCUMENTATION = r'''
description: Populate inventory with instances in this region.
default: []
type: list
elements: string
tags:
description: Populate inventory only with instances which have at least one of the tags listed here.
default: []
type: list
elements: string
version_added: 2.0.0
types:
description: Populate inventory with instances with this type.
default: []
type: list
elements: string
strict:
version_added: 2.0.0
compose:
@@ -66,6 +80,12 @@ EXAMPLES = r'''
# Minimal example. `LINODE_ACCESS_TOKEN` is exposed in environment.
plugin: community.general.linode
# You can use Jinja to template the access token.
plugin: community.general.linode
access_token: "{{ lookup('ini', 'token', section='your_username', file='~/.config/linode-cli') }}"
# For older Ansible versions, you need to write this as:
# access_token: "{{ lookup('ini', 'token section=your_username file=~/.config/linode-cli') }}"
# Example with regions, types, groups and access token
plugin: community.general.linode
access_token: foobar
@@ -104,25 +124,31 @@ import os
from ansible.errors import AnsibleError, AnsibleParserError
from ansible.module_utils.six import string_types
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.template import Templar
try:
from linode_api4 import LinodeClient
from linode_api4.objects.linode import Instance
from linode_api4.errors import ApiError as LinodeApiError
HAS_LINODE = True
except ImportError:
HAS_LINODE = False
class InventoryModule(BaseInventoryPlugin, Constructable):
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
NAME = 'community.general.linode'
def _build_client(self):
def _build_client(self, loader):
"""Build the Linode client."""
t = Templar(loader=loader)
access_token = self.get_option('access_token')
if t.is_template(access_token):
access_token = t.template(variable=access_token, disable_lookups=False)
if access_token is None:
try:
@@ -158,20 +184,23 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
for linode_group in self.linode_groups:
self.inventory.add_group(linode_group)
def _filter_by_config(self, regions, types, tags):
def _filter_by_config(self):
"""Filter instances by user specified configuration."""
regions = self.get_option('regions')
if regions:
self.instances = [
instance for instance in self.instances
if instance.region.id in regions
]
types = self.get_option('types')
if types:
self.instances = [
instance for instance in self.instances
if instance.type.id in types
]
tags = self.get_option('tags')
if tags:
self.instances = [
instance for instance in self.instances
@@ -224,76 +253,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
)
return data
def _validate_option(self, name, desired_type, option_value):
"""Validate user specified configuration data against types."""
if isinstance(option_value, string_types) and desired_type == list:
option_value = [option_value]
if option_value is None:
option_value = desired_type()
if not isinstance(option_value, desired_type):
raise AnsibleParserError(
'The option %s (%s) must be a %s' % (
name, option_value, desired_type
)
)
return option_value
def _get_query_options(self, config_data):
"""Get user specified query options from the configuration."""
options = {
'regions': {
'type_to_be': list,
'value': config_data.get('regions', [])
},
'types': {
'type_to_be': list,
'value': config_data.get('types', [])
},
'tags': {
'type_to_be': list,
'value': config_data.get('tags', [])
},
}
for name in options:
options[name]['value'] = self._validate_option(
name,
options[name]['type_to_be'],
options[name]['value']
)
regions = options['regions']['value']
types = options['types']['value']
tags = options['tags']['value']
return regions, types, tags
def verify_file(self, path):
"""Verify the Linode configuration file."""
if super(InventoryModule, self).verify_file(path):
endings = ('linode.yaml', 'linode.yml')
if any((path.endswith(ending) for ending in endings)):
return True
return False
def parse(self, inventory, loader, path, cache=True):
"""Dynamically parse Linode the cloud inventory."""
super(InventoryModule, self).parse(inventory, loader, path)
if not HAS_LINODE:
raise AnsibleError('the Linode dynamic inventory plugin requires linode_api4.')
config_data = self._read_config_data(path)
self._build_client()
self._get_instances_inventory()
def _cacheable_inventory(self):
return [i._raw_json for i in self.instances]
def populate(self):
strict = self.get_option('strict')
regions, types, tags = self._get_query_options(config_data)
self._filter_by_config(regions, types, tags)
self._filter_by_config()
self._add_groups()
self._add_instances_to_groups()
@@ -315,3 +281,44 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
variables,
instance.label,
strict=strict)
def verify_file(self, path):
"""Verify the Linode configuration file."""
if super(InventoryModule, self).verify_file(path):
endings = ('linode.yaml', 'linode.yml')
if any((path.endswith(ending) for ending in endings)):
return True
return False
def parse(self, inventory, loader, path, cache=True):
"""Dynamically parse Linode the cloud inventory."""
super(InventoryModule, self).parse(inventory, loader, path)
self.instances = None
if not HAS_LINODE:
raise AnsibleError('the Linode dynamic inventory plugin requires linode_api4.')
self._read_config_data(path)
cache_key = self.get_cache_key(path)
if cache:
cache = self.get_option('cache')
update_cache = False
if cache:
try:
self.instances = [Instance(None, i["id"], i) for i in self._cache[cache_key]]
except KeyError:
update_cache = True
# Check for None rather than False in order to allow
# for empty sets of cached instances
if self.instances is None:
self._build_client(loader)
self._get_instances_inventory()
if update_cache:
self._cache[cache_key] = self._cacheable_inventory()
self.populate()

View File

@@ -666,9 +666,13 @@ class InventoryModule(BaseInventoryPlugin):
# add network informations
self.build_inventory_network(instance_name)
# add os
self.inventory.set_variable(instance_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(instance_name)).lower())
v = self._get_data_entry('inventory/{0}/os'.format(instance_name))
if v:
self.inventory.set_variable(instance_name, 'ansible_lxd_os', v.lower())
# add release
self.inventory.set_variable(instance_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(instance_name)).lower())
v = self._get_data_entry('inventory/{0}/release'.format(instance_name))
if v:
self.inventory.set_variable(instance_name, 'ansible_lxd_release', v.lower())
# add profile
self.inventory.set_variable(instance_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(instance_name)))
# add state

View File

@@ -27,6 +27,7 @@ DOCUMENTATION = '''
exclude:
description: list of addresses to exclude
type: list
elements: string
ports:
description: Enable/disable scanning for open ports
type: boolean

View File

@@ -28,6 +28,7 @@ DOCUMENTATION = r'''
hostnames:
description: List of preference about what to use as an hostname.
type: list
elements: string
default:
- public_ipv4
choices:
@@ -37,6 +38,7 @@ DOCUMENTATION = r'''
groups:
description: List of groups.
type: list
elements: string
choices:
- location
- offer

View File

@@ -95,7 +95,7 @@ except ImportError:
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.module_utils._text import to_native
from ansible.module_utils.common.text.converters import to_native
from collections import namedtuple
import os

View File

@@ -31,6 +31,7 @@ DOCUMENTATION = '''
description:
- URL to Proxmox cluster.
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_URL) will be used instead.
- Since community.general 4.7.0 you can also use templating to specify the value of the I(url).
default: 'http://localhost:8006'
type: str
env:
@@ -40,6 +41,7 @@ DOCUMENTATION = '''
description:
- Proxmox authentication user.
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_USER) will be used instead.
- Since community.general 4.7.0 you can also use templating to specify the value of the I(user).
required: yes
type: str
env:
@@ -49,6 +51,7 @@ DOCUMENTATION = '''
description:
- Proxmox authentication password.
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_PASSWORD) will be used instead.
- Since community.general 4.7.0 you can also use templating to specify the value of the I(password).
required: yes
type: str
env:
@@ -77,6 +80,12 @@ DOCUMENTATION = '''
- When set to C(true) (default), will use the first available interface. This can be different from what you expect.
default: true
type: bool
filters:
version_added: 4.6.0
description: A list of Jinja templates that allow filtering hosts.
type: list
elements: str
default: []
strict:
version_added: 2.5.0
compose:
@@ -114,16 +123,45 @@ groups:
mailservers: "'mail' in (proxmox_tags_parsed|list)"
compose:
ansible_port: 2222
# Using the inventory to allow ansible to connect via the first IP address of the VM / Container
# (Default is connection by name of QEMU/LXC guests)
# Note: my_inv_var demonstrates how to add a string variable to every host used by the inventory.
# my.proxmox.yml
plugin: community.general.proxmox
url: http://pve.domain.com:8006
user: ansible@pve
password: secure
validate_certs: false
want_facts: true
compose:
ansible_host: proxmox_ipconfig0.ip | default(proxmox_net0.ip) | ipaddr('address')
my_inv_var_1: "'my_var1_value'"
my_inv_var_2: >
"my_var_2_value"
# Specify the url, user and password using templating
# my.proxmox.yml
plugin: community.general.proxmox
url: "{{ lookup('ansible.builtin.ini', 'url', section='proxmox', file='file.ini') }}"
user: "{{ lookup('ansible.builtin.env','PM_USER') | default('ansible@pve') }}"
password: "{{ lookup('community.general.random_string', base64=True) }}"
'''
import itertools
import re
from ansible.module_utils.common._collections_compat import MutableMapping
from distutils.version import LooseVersion
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.utils.display import Display
from ansible.template import Templar
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
# 3rd party imports
try:
@@ -134,6 +172,8 @@ try:
except ImportError:
HAS_REQUESTS = False
display = Display()
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
''' Host inventory parser for ansible using Proxmox as source. '''
@@ -274,28 +314,19 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
return result
def _get_vm_config(self, node, vmid, vmtype, name):
def _get_vm_config(self, properties, node, vmid, vmtype, name):
ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/config" % (self.proxmox_url, node, vmtype, vmid))
node_key = 'node'
node_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), node_key.lower()))
self.inventory.set_variable(name, node_key, node)
vmid_key = 'vmid'
vmid_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), vmid_key.lower()))
self.inventory.set_variable(name, vmid_key, vmid)
vmtype_key = 'vmtype'
vmtype_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), vmtype_key.lower()))
self.inventory.set_variable(name, vmtype_key, vmtype)
properties[self._fact('node')] = node
properties[self._fact('vmid')] = vmid
properties[self._fact('vmtype')] = vmtype
plaintext_configs = [
'tags',
'description',
]
for config in ret:
key = config
key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), key.lower()))
key = self._fact(config)
value = ret[config]
try:
# fixup disk images as they have no key
@@ -304,46 +335,39 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# Additional field containing parsed tags as list
if config == 'tags':
parsed_key = self.to_safe('%s%s' % (key, "_parsed"))
parsed_value = [tag.strip() for tag in value.split(",")]
self.inventory.set_variable(name, parsed_key, parsed_value)
stripped_value = value.strip()
if stripped_value:
parsed_key = key + "_parsed"
properties[parsed_key] = [tag.strip() for tag in stripped_value.split(",")]
# The first field in the agent string tells you whether the agent is enabled
# the rest of the comma separated string is extra config for the agent
if config == 'agent' and int(value.split(',')[0]):
agent_iface_key = self.to_safe('%s%s' % (key, "_interfaces"))
agent_iface_value = self._get_agent_network_interfaces(node, vmid, vmtype)
if agent_iface_value:
self.inventory.set_variable(name, agent_iface_key, agent_iface_value)
agent_iface_key = self.to_safe('%s%s' % (key, "_interfaces"))
properties[agent_iface_key] = agent_iface_value
if not (isinstance(value, int) or ',' not in value):
if config not in plaintext_configs and not isinstance(value, int) and all("=" in v for v in value.split(",")):
# split off strings with commas to a dict
# skip over any keys that cannot be processed
try:
value = dict(key.split("=") for key in value.split(","))
value = dict(key.split("=", 1) for key in value.split(","))
except Exception:
continue
self.inventory.set_variable(name, key, value)
properties[key] = value
except NameError:
return None
def _get_vm_status(self, node, vmid, vmtype, name):
def _get_vm_status(self, properties, node, vmid, vmtype, name):
ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/status/current" % (self.proxmox_url, node, vmtype, vmid))
properties[self._fact('status')] = ret['status']
status = ret['status']
status_key = 'status'
status_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), status_key.lower()))
self.inventory.set_variable(name, status_key, status)
def _get_vm_snapshots(self, node, vmid, vmtype, name):
def _get_vm_snapshots(self, properties, node, vmid, vmtype, name):
ret = self._get_json("%s/api2/json/nodes/%s/%s/%s/snapshot" % (self.proxmox_url, node, vmtype, vmid))
snapshots_key = 'snapshots'
snapshots_key = self.to_safe('%s%s' % (self.get_option('facts_prefix'), snapshots_key.lower()))
snapshots = [snapshot['name'] for snapshot in ret if snapshot['name'] != 'current']
self.inventory.set_variable(name, snapshots_key, snapshots)
properties[self._fact('snapshots')] = snapshots
def to_safe(self, word):
'''Converts 'bad' characters in a string to underscores so they can be used as Ansible groups
@@ -353,109 +377,130 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
regex = r"[^A-Za-z0-9\_]"
return re.sub(regex, "_", word.replace(" ", ""))
def _apply_constructable(self, name, variables):
strict = self.get_option('strict')
self._add_host_to_composed_groups(self.get_option('groups'), variables, name, strict=strict)
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), variables, name, strict=strict)
self._set_composite_vars(self.get_option('compose'), variables, name, strict=strict)
def _fact(self, name):
'''Generate a fact's full name from the common prefix and a name.'''
return self.to_safe('%s%s' % (self.facts_prefix, name.lower()))
def _group(self, name):
'''Generate a group's full name from the common prefix and a name.'''
return self.to_safe('%s%s' % (self.group_prefix, name.lower()))
def _can_add_host(self, name, properties):
'''Ensure that a host satisfies all defined hosts filters. If strict mode is
enabled, any error during host filter compositing will lead to an AnsibleError
being raised, otherwise the filter will be ignored.
'''
for host_filter in self.host_filters:
try:
if not self._compose(host_filter, properties):
return False
except Exception as e: # pylint: disable=broad-except
message = "Could not evaluate host filter %s for host %s - %s" % (host_filter, name, to_native(e))
if self.strict:
raise AnsibleError(message)
display.warning(message)
return True
def _add_host(self, name, variables):
self.inventory.add_host(name)
for k, v in variables.items():
self.inventory.set_variable(name, k, v)
variables = self.inventory.get_host(name).get_vars()
self._set_composite_vars(self.get_option('compose'), variables, name, strict=self.strict)
self._add_host_to_composed_groups(self.get_option('groups'), variables, name, strict=self.strict)
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), variables, name, strict=self.strict)
def _handle_item(self, node, ittype, item):
'''Handle an item from the list of LXC containers and Qemu VM. The
return value will be either None if the item was skipped or the name of
the item if it was added to the inventory.'''
if item.get('template'):
return None
properties = dict()
name, vmid = item['name'], item['vmid']
# get status, config and snapshots if want_facts == True
if self.get_option('want_facts'):
self._get_vm_status(properties, node, vmid, ittype, name)
self._get_vm_config(properties, node, vmid, ittype, name)
self._get_vm_snapshots(properties, node, vmid, ittype, name)
# ensure the host satisfies filters
if not self._can_add_host(name, properties):
return None
# add the host to the inventory
self._add_host(name, properties)
node_type_group = self._group('%s_%s' % (node, ittype))
self.inventory.add_child(self._group('all_' + ittype), name)
self.inventory.add_child(node_type_group, name)
if item['status'] == 'stopped':
self.inventory.add_child(self._group('all_stopped'), name)
elif item['status'] == 'running':
self.inventory.add_child(self._group('all_running'), name)
return name
def _populate_pool_groups(self, added_hosts):
'''Generate groups from Proxmox resource pools, ignoring VMs and
containers that were skipped.'''
for pool in self._get_pools():
poolid = pool.get('poolid')
if not poolid:
continue
pool_group = self._group('pool_' + poolid)
self.inventory.add_group(pool_group)
for member in self._get_members_per_pool(poolid):
name = member.get('name')
if name and name in added_hosts:
self.inventory.add_child(pool_group, name)
def _populate(self):
self._get_auth()
# create common groups
self.inventory.add_group(self._group('all_lxc'))
self.inventory.add_group(self._group('all_qemu'))
self.inventory.add_group(self._group('all_running'))
self.inventory.add_group(self._group('all_stopped'))
nodes_group = self._group('nodes')
self.inventory.add_group(nodes_group)
# gather vm's on nodes
self._get_auth()
hosts = []
for node in self._get_nodes():
# FIXME: this can probably be cleaner
# create groups
lxc_group = 'all_lxc'
lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), lxc_group.lower()))
self.inventory.add_group(lxc_group)
qemu_group = 'all_qemu'
qemu_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), qemu_group.lower()))
self.inventory.add_group(qemu_group)
nodes_group = 'nodes'
nodes_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), nodes_group.lower()))
self.inventory.add_group(nodes_group)
running_group = 'all_running'
running_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), running_group.lower()))
self.inventory.add_group(running_group)
stopped_group = 'all_stopped'
stopped_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), stopped_group.lower()))
self.inventory.add_group(stopped_group)
if not node.get('node'):
continue
if node.get('node'):
self.inventory.add_host(node['node'])
self.inventory.add_host(node['node'])
if node['type'] == 'node':
self.inventory.add_child(nodes_group, node['node'])
if node['type'] == 'node':
self.inventory.add_child(nodes_group, node['node'])
if node['status'] == 'offline':
continue
if node['status'] == 'offline':
continue
# get node IP address
if self.get_option("want_proxmox_nodes_ansible_host"):
ip = self._get_node_ip(node['node'])
self.inventory.set_variable(node['node'], 'ansible_host', ip)
# get node IP address
if self.get_option("want_proxmox_nodes_ansible_host"):
ip = self._get_node_ip(node['node'])
self.inventory.set_variable(node['node'], 'ansible_host', ip)
# add LXC/Qemu groups for the node
for ittype in ('lxc', 'qemu'):
node_type_group = self._group('%s_%s' % (node['node'], ittype))
self.inventory.add_group(node_type_group)
# get LXC containers for this node
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))
self.inventory.add_group(node_lxc_group)
for lxc in self._get_lxc_per_node(node['node']):
self.inventory.add_host(lxc['name'])
self.inventory.add_child(lxc_group, lxc['name'])
self.inventory.add_child(node_lxc_group, lxc['name'])
# get LXC status when want_facts == True
if self.get_option('want_facts'):
self._get_vm_status(node['node'], lxc['vmid'], 'lxc', lxc['name'])
if lxc['status'] == 'stopped':
self.inventory.add_child(stopped_group, lxc['name'])
elif lxc['status'] == 'running':
self.inventory.add_child(running_group, lxc['name'])
# get LXC config and snapshots for facts
if self.get_option('want_facts'):
self._get_vm_config(node['node'], lxc['vmid'], 'lxc', lxc['name'])
self._get_vm_snapshots(node['node'], lxc['vmid'], 'lxc', lxc['name'])
self._apply_constructable(lxc["name"], self.inventory.get_host(lxc['name']).get_vars())
# get QEMU vm's for this node
node_qemu_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_qemu' % node['node']).lower()))
self.inventory.add_group(node_qemu_group)
for qemu in self._get_qemu_per_node(node['node']):
if qemu.get('template'):
continue
self.inventory.add_host(qemu['name'])
self.inventory.add_child(qemu_group, qemu['name'])
self.inventory.add_child(node_qemu_group, qemu['name'])
# get QEMU status
self._get_vm_status(node['node'], qemu['vmid'], 'qemu', qemu['name'])
if qemu['status'] == 'stopped':
self.inventory.add_child(stopped_group, qemu['name'])
elif qemu['status'] == 'running':
self.inventory.add_child(running_group, qemu['name'])
# get QEMU config and snapshots for facts
if self.get_option('want_facts'):
self._get_vm_config(node['node'], qemu['vmid'], 'qemu', qemu['name'])
self._get_vm_snapshots(node['node'], qemu['vmid'], 'qemu', qemu['name'])
self._apply_constructable(qemu["name"], self.inventory.get_host(qemu['name']).get_vars())
# get LXC containers and Qemu VMs for this node
lxc_objects = zip(itertools.repeat('lxc'), self._get_lxc_per_node(node['node']))
qemu_objects = zip(itertools.repeat('qemu'), self._get_qemu_per_node(node['node']))
for ittype, item in itertools.chain(lxc_objects, qemu_objects):
name = self._handle_item(node['node'], ittype, item)
if name is not None:
hosts.append(name)
# gather vm's in pools
for pool in self._get_pools():
if pool.get('poolid'):
pool_group = 'pool_' + pool['poolid']
pool_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), pool_group.lower()))
self.inventory.add_group(pool_group)
for member in self._get_members_per_pool(pool['poolid']):
if member.get('name'):
if not member.get('template'):
self.inventory.add_child(pool_group, member['name'])
self._populate_pool_groups(hosts)
def parse(self, inventory, loader, path, cache=True):
if not HAS_REQUESTS:
@@ -467,12 +512,30 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
# read config from file, this sets 'options'
self._read_config_data(path)
# get connection host
self.proxmox_url = self.get_option('url').rstrip('/')
self.proxmox_user = self.get_option('user')
self.proxmox_password = self.get_option('password')
t = Templar(loader=loader)
# read options
proxmox_url = self.get_option('url')
if t.is_template(proxmox_url):
proxmox_url = t.template(variable=proxmox_url, disable_lookups=False)
self.proxmox_url = proxmox_url.rstrip('/')
proxmox_user = self.get_option('user')
if t.is_template(proxmox_user):
proxmox_user = t.template(variable=proxmox_user, disable_lookups=False)
self.proxmox_user = proxmox_user
proxmox_password = self.get_option('password')
if t.is_template(proxmox_password):
proxmox_password = t.template(variable=proxmox_password, disable_lookups=False)
self.proxmox_password = proxmox_password
self.cache_key = self.get_cache_key(path)
self.use_cache = 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._populate()

View File

@@ -23,6 +23,7 @@ DOCUMENTATION = r'''
regions:
description: Filter results on a specific Scaleway region.
type: list
elements: string
default:
- ams1
- par1
@@ -31,6 +32,13 @@ DOCUMENTATION = r'''
tags:
description: Filter results on a specific tag.
type: list
elements: string
scw_profile:
description:
- The config profile to use in config file.
- By default uses the one specified as C(active_profile) in the config file, or falls back to C(default) if that is not defined.
type: string
version_added: 4.4.0
oauth_token:
description:
- Scaleway OAuth token.
@@ -45,6 +53,7 @@ DOCUMENTATION = r'''
hostnames:
description: List of preference about what to use as an hostname.
type: list
elements: string
default:
- public_ipv4
choices:
@@ -303,7 +312,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if not oauth_token and os.path.exists(scw_config_path):
with open(scw_config_path) as fh:
scw_config = yaml.safe_load(fh)
active_profile = scw_config.get('active_profile', 'default')
ansible_profile = self.get_option('scw_profile')
if ansible_profile:
active_profile = ansible_profile
else:
active_profile = scw_config.get('active_profile', 'default')
if active_profile == 'default':
oauth_token = scw_config.get('secret_key')
else:

View File

@@ -62,28 +62,27 @@ DOCUMENTATION = '''
EXAMPLES = '''
# file must be named xen_orchestra.yaml or xen_orchestra.yml
simple_config_file:
plugin: community.general.xen_orchestra
api_host: 192.168.1.255
user: xo
password: xo_pwd
validate_certs: true
use_ssl: true
groups:
kube_nodes: "'kube_node' in tags"
compose:
ansible_port: 2222
plugin: community.general.xen_orchestra
api_host: 192.168.1.255
user: xo
password: xo_pwd
validate_certs: true
use_ssl: true
groups:
kube_nodes: "'kube_node' in tags"
compose:
ansible_port: 2222
'''
import json
import ssl
from distutils.version import LooseVersion
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
# 3rd party imports
try:
HAS_WEBSOCKET = True

View File

@@ -20,6 +20,7 @@ DOCUMENTATION = '''
_raw:
description: List of key(s) to retrieve.
type: list
elements: string
recurse:
type: boolean
description: If true, will retrieve all the values that have the given key as prefix.

View File

@@ -17,11 +17,11 @@ DOCUMENTATION = '''
_terms:
description: term or list of terms to lookup in the credit store
type: list
required: True
elements: string
required: true
table:
description: name of the credstash table to query
default: 'credential-store'
required: True
version:
description: Credstash version
region:

View File

@@ -18,6 +18,7 @@ DOCUMENTATION = '''
description: domain or list of domains to query TXT records from
required: True
type: list
elements: string
'''
EXAMPLES = """

View File

@@ -105,11 +105,15 @@ display = Display()
class LookupModule(LookupBase):
@staticmethod
def Client(vault_parameters):
return SecretsVault(**vault_parameters)
try:
vault = SecretsVault(**vault_parameters)
return vault
except TypeError:
raise AnsibleError("python-dsv-sdk==0.0.1 must be installed to use this plugin")
def run(self, terms, variables, **kwargs):
if sdk_is_missing:
raise AnsibleError("python-dsv-sdk must be installed to use this plugin")
raise AnsibleError("python-dsv-sdk==0.0.1 must be installed to use this plugin")
self.set_options(var_options=variables, direct=kwargs)

View File

@@ -23,7 +23,7 @@ DOCUMENTATION = '''
EXAMPLES = """
- name: "'unnest' all elements into single list"
ansible.builtin.debug:
msg: "all in one list {{lookup('community.general.flattened', [1,2,3,[5,6]], [a,b,c], [[5,6,1,3], [34,a,b,c]])}}"
msg: "all in one list {{lookup('community.general.flattened', [1,2,3,[5,6]], ['a','b','c'], [[5,6,1,3], [34,'a','b','c']])}}"
"""
RETURN = """

View File

@@ -14,6 +14,8 @@ DOCUMENTATION = '''
description:
- Enables Ansible to retrieve, create or update passwords from the passwordstore.org pass utility.
It also retrieves YAML style keys stored as multilines in the passwordfile.
- To avoid problems when accessing multiple secrets at once, add C(auto-expand-secmem) to
C(~/.gnupg/gpg-agent.conf). Where this is not possible, consider using I(lock=readwrite) instead.
options:
_terms:
description: query key.
@@ -77,54 +79,89 @@ DOCUMENTATION = '''
- warn
- empty
- create
lock:
description:
- How to synchronize operations.
- The default of C(write) only synchronizes write operations.
- C(readwrite) synchronizes all operations (including read). This makes sure that gpg-agent is never called in parallel.
- C(none) does not do any synchronization.
ini:
- section: passwordstore_lookup
key: lock
type: str
default: write
choices:
- readwrite
- write
- none
version_added: 4.5.0
locktimeout:
description:
- Lock timeout applied when I(lock) is not C(none).
- Time with a unit suffix, C(s), C(m), C(h) for seconds, minutes, and hours, respectively. For example, C(900s) equals C(15m).
- Correlates with C(pinentry-timeout) in C(~/.gnupg/gpg-agent.conf), see C(man gpg-agent) for details.
ini:
- section: passwordstore_lookup
key: locktimeout
type: str
default: 15m
version_added: 4.5.0
'''
EXAMPLES = """
# Debug is used for examples, BAD IDEA to show passwords on screen
- name: Basic lookup. Fails if example/test doesn't exist
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test')}}"
ansible.cfg: |
[passwordstore_lookup]
lock=readwrite
locktimeout=45s
- name: Basic lookup. Warns if example/test does not exist and returns empty string
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test missing=warn')}}"
playbook.yml: |
---
- name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test create=true')}}"
# Debug is used for examples, BAD IDEA to show passwords on screen
- name: Basic lookup. Fails if example/test does not exist
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test')}}"
- name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=create')}}"
- name: Basic lookup. Warns if example/test does not exist and returns empty string
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test missing=warn')}}"
- name: Prints 'abc' if example/test does not exist, just give the password otherwise
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=empty') | default('abc', true) }}"
- name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test create=true')}}"
- name: Different size password
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true length=42')}}"
- name: Create pass with random 16 character password. If password exists just give the password
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=create')}}"
- name: Create password and overwrite the password if it exists. As a bonus, this module includes the old password inside the pass file
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true overwrite=true')}}"
- name: Prints 'abc' if example/test does not exist, just give the password otherwise
ansible.builtin.debug:
var: mypassword
vars:
mypassword: "{{ lookup('community.general.passwordstore', 'example/test missing=empty') | default('abc', true) }}"
- name: Create an alphanumeric password
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true nosymbols=true') }}"
- name: Different size password
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true length=42')}}"
- name: Return the value for user in the KV pair user, username
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test subkey=user')}}"
- name: Create password and overwrite the password if it exists. As a bonus, this module includes the old password inside the pass file
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true overwrite=true')}}"
- name: Return the entire password file content
ansible.builtin.set_fact:
passfilecontent: "{{ lookup('community.general.passwordstore', 'example/test returnall=true')}}"
- name: Create an alphanumeric password
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true nosymbols=true') }}"
- name: Return the value for user in the KV pair user, username
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test subkey=user')}}"
- name: Return the entire password file content
ansible.builtin.set_fact:
passfilecontent: "{{ lookup('community.general.passwordstore', 'example/test returnall=true')}}"
"""
RETURN = """
@@ -135,15 +172,17 @@ _raw:
elements: str
"""
from contextlib import contextmanager
import os
import re
import subprocess
import time
import yaml
from distutils import util
from ansible.errors import AnsibleError, AnsibleAssertionError
from ansible.module_utils.common.file import FileLock
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
from ansible.module_utils.parsing.convert_bool import boolean
from ansible.utils.display import Display
from ansible.utils.encrypt import random_password
from ansible.plugins.lookup import LookupBase
@@ -154,6 +193,7 @@ display = Display()
# backhacked check_output with input for python 2.7
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
# note: contains special logic for calling 'pass', so not a drop-in replacement for check_output
def check_output2(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
@@ -175,9 +215,10 @@ def check_output2(*popenargs, **kwargs):
process.wait()
raise
retcode = process.poll()
if retcode != 0 or \
b'encryption failed: Unusable public key' in b_out or \
b'encryption failed: Unusable public key' in b_err:
if retcode == 0 and (b'encryption failed: Unusable public key' in b_out or
b'encryption failed: Unusable public key' in b_err):
retcode = 78 # os.EX_CONFIG
if retcode != 0:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
@@ -211,7 +252,7 @@ class LookupModule(LookupBase):
try:
for key in ['create', 'returnall', 'overwrite', 'backup', 'nosymbols']:
if not isinstance(self.paramvals[key], bool):
self.paramvals[key] = util.strtobool(self.paramvals[key])
self.paramvals[key] = boolean(self.paramvals[key])
except (ValueError, AssertionError) as e:
raise AnsibleError(e)
if self.paramvals['missing'] not in ['error', 'warn', 'create', 'empty']:
@@ -227,13 +268,13 @@ class LookupModule(LookupBase):
# Collect pass environment variables from the plugin's parameters.
self.env = os.environ.copy()
self.env['LANGUAGE'] = 'C' # make sure to get errors in English as required by check_output2
# Set PASSWORD_STORE_DIR if directory is set
if self.paramvals['directory']:
if os.path.isdir(self.paramvals['directory']):
self.env['PASSWORD_STORE_DIR'] = self.paramvals['directory']
else:
raise AnsibleError('Passwordstore directory \'{0}\' does not exist'.format(self.paramvals['directory']))
# Set PASSWORD_STORE_DIR
if os.path.isdir(self.paramvals['directory']):
self.env['PASSWORD_STORE_DIR'] = self.paramvals['directory']
else:
raise AnsibleError('Passwordstore directory \'{0}\' does not exist'.format(self.paramvals['directory']))
# Set PASSWORD_STORE_UMASK if umask is set
if 'umask' in self.paramvals:
@@ -261,19 +302,20 @@ class LookupModule(LookupBase):
if ':' in line:
name, value = line.split(':', 1)
self.passdict[name.strip()] = value.strip()
if os.path.isfile(os.path.join(self.paramvals['directory'], self.passname + ".gpg")):
# Only accept password as found, if there a .gpg file for it (might be a tree node otherwise)
return True
except (subprocess.CalledProcessError) as e:
if e.returncode != 0 and 'not in the password store' in e.output:
# if pass returns 1 and return string contains 'is not in the password store.'
# We need to determine if this is valid or Error.
if self.paramvals['missing'] == 'error':
raise AnsibleError('passwordstore: passname {0} not found and missing=error is set'.format(self.passname))
else:
if self.paramvals['missing'] == 'warn':
display.warning('passwordstore: passname {0} not found'.format(self.passname))
return False
else:
# 'not in password store' is the expected error if a password wasn't found
if 'not in the password store' not in e.output:
raise AnsibleError(e)
return True
if self.paramvals['missing'] == 'error':
raise AnsibleError('passwordstore: passname {0} not found and missing=error is set'.format(self.passname))
elif self.paramvals['missing'] == 'warn':
display.warning('passwordstore: passname {0} not found'.format(self.passname))
return False
def get_newpass(self):
if self.paramvals['nosymbols']:
@@ -325,11 +367,30 @@ class LookupModule(LookupBase):
else:
return None
def run(self, terms, variables, **kwargs):
result = []
@contextmanager
def opt_lock(self, type):
if self.get_option('lock') == type:
tmpdir = os.environ.get('TMPDIR', '/tmp')
lockfile = os.path.join(tmpdir, '.passwordstore.lock')
with FileLock().lock_file(lockfile, tmpdir, self.lock_timeout):
self.locked = type
yield
self.locked = None
else:
yield
def setup(self, variables):
self.locked = None
timeout = self.get_option('locktimeout')
if not re.match('^[0-9]+[smh]$', timeout):
raise AnsibleError("{0} is not a correct value for locktimeout".format(timeout))
unit_to_seconds = {"s": 1, "m": 60, "h": 3600}
self.lock_timeout = int(timeout[:-1]) * unit_to_seconds[timeout[-1]]
self.paramvals = {
'subkey': 'password',
'directory': variables.get('passwordstore'),
'directory': variables.get('passwordstore', os.environ.get(
'PASSWORD_STORE_DIR',
os.path.expanduser('~/.password-store'))),
'create': False,
'returnall': False,
'overwrite': False,
@@ -340,17 +401,27 @@ class LookupModule(LookupBase):
'missing': 'error',
}
def run(self, terms, variables, **kwargs):
self.setup(variables)
result = []
for term in terms:
self.parse_params(term) # parse the input into paramvals
if self.check_pass(): # password exists
if self.paramvals['overwrite'] and self.paramvals['subkey'] == 'password':
result.append(self.update_password())
else:
result.append(self.get_passresult())
else: # password does not exist
if self.paramvals['missing'] == 'create':
result.append(self.generate_password())
else:
result.append(None)
with self.opt_lock('readwrite'):
if self.check_pass(): # password exists
if self.paramvals['overwrite'] and self.paramvals['subkey'] == 'password':
with self.opt_lock('write'):
result.append(self.update_password())
else:
result.append(self.get_passresult())
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
result.append(self.get_passresult())
else:
result.append(self.generate_password())
else:
result.append(None)
return result

View File

@@ -14,6 +14,10 @@ description:
- Uses the Thycotic Secret Server Python SDK to get Secrets from Secret
Server using token authentication with I(username) and I(password) on
the REST API at I(base_url).
- When using self-signed certificates the environment variable
C(REQUESTS_CA_BUNDLE) can be set to a file containing the trusted certificates
(in C(.pem) format).
- For example, C(export REQUESTS_CA_BUNDLE='/etc/ssl/certs/ca-bundle.trust.crt').
requirements:
- python-tss-sdk - https://pypi.org/project/python-tss-sdk/
options:

View File

@@ -0,0 +1,343 @@
# Vendored copy of distutils/version.py from CPython 3.9.5
#
# Implements multiple version numbering conventions for the
# Python Module Distribution Utilities.
#
# PSF License (see licenses/PSF-license.txt or https://opensource.org/licenses/Python-2.0)
#
"""Provides classes to represent module version numbers (one class for
each style of version numbering). There are currently two such classes
implemented: StrictVersion and LooseVersion.
Every version number class implements the following interface:
* the 'parse' method takes a string and parses it to some internal
representation; if the string is an invalid version number,
'parse' raises a ValueError exception
* the class constructor takes an optional string argument which,
if supplied, is passed to 'parse'
* __str__ reconstructs the string that was passed to 'parse' (or
an equivalent string -- ie. one that will generate an equivalent
version number instance)
* __repr__ generates Python code to recreate the version number instance
* _cmp compares the current instance with either another instance
of the same class or a string (which will be parsed to an instance
of the same class, thus must follow the same rules)
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
try:
RE_FLAGS = re.VERBOSE | re.ASCII
except AttributeError:
RE_FLAGS = re.VERBOSE
class Version:
"""Abstract base class for version numbering classes. Just provides
constructor (__init__) and reproducer (__repr__), because those
seem to be the same for all version numbering classes; and route
rich comparisons to _cmp.
"""
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def __repr__(self):
return "%s ('%s')" % (self.__class__.__name__, str(self))
def __eq__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c == 0
def __lt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c >= 0
# Interface for version-number classes -- must be implemented
# by the following classes (the concrete ones -- Version should
# be treated as an abstract class).
# __init__ (string) - create and take same action as 'parse'
# (string parameter is optional)
# parse (string) - convert a string representation to whatever
# internal representation is appropriate for
# this style of version numbering
# __str__ (self) - convert back to a string; should be very similar
# (if not identical to) the string supplied to parse
# __repr__ (self) - generate Python code to recreate
# the instance
# _cmp (self, other) - compare two version numbers ('other' may
# be an unparsed version string, or another
# instance of your version class)
class StrictVersion(Version):
"""Version numbering for anal retentives and software idealists.
Implements the standard interface for version number classes as
described above. A version number consists of two or three
dot-separated numeric components, with an optional "pre-release" tag
on the end. The pre-release tag consists of the letter 'a' or 'b'
followed by a number. If the numeric components of two version
numbers are equal, then one with a pre-release tag will always
be deemed earlier (lesser) than one without.
The following are valid version numbers (shown in the order that
would be obtained by sorting according to the supplied cmp function):
0.4 0.4.0 (these two are equivalent)
0.4.1
0.5a1
0.5b3
0.5
0.9.6
1.0
1.0.4a3
1.0.4b1
1.0.4
The following are examples of invalid version numbers:
1
2.7.2.2
1.3.a4
1.3pl1
1.3c4
The rationale for this version numbering system will be explained
in the distutils documentation.
"""
version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
RE_FLAGS)
def parse(self, vstring):
match = self.version_re.match(vstring)
if not match:
raise ValueError("invalid version number '%s'" % vstring)
(major, minor, patch, prerelease, prerelease_num) = \
match.group(1, 2, 4, 5, 6)
if patch:
self.version = tuple(map(int, [major, minor, patch]))
else:
self.version = tuple(map(int, [major, minor])) + (0,)
if prerelease:
self.prerelease = (prerelease[0], int(prerelease_num))
else:
self.prerelease = None
def __str__(self):
if self.version[2] == 0:
vstring = '.'.join(map(str, self.version[0:2]))
else:
vstring = '.'.join(map(str, self.version))
if self.prerelease:
vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
return vstring
def _cmp(self, other):
if isinstance(other, str):
other = StrictVersion(other)
elif not isinstance(other, StrictVersion):
return NotImplemented
if self.version != other.version:
# numeric versions don't match
# prerelease stuff doesn't matter
if self.version < other.version:
return -1
else:
return 1
# have to compare prerelease
# case 1: neither has prerelease; they're equal
# case 2: self has prerelease, other doesn't; other is greater
# case 3: self doesn't have prerelease, other does: self is greater
# case 4: both have prerelease: must compare them!
if (not self.prerelease and not other.prerelease):
return 0
elif (self.prerelease and not other.prerelease):
return -1
elif (not self.prerelease and other.prerelease):
return 1
elif (self.prerelease and other.prerelease):
if self.prerelease == other.prerelease:
return 0
elif self.prerelease < other.prerelease:
return -1
else:
return 1
else:
raise AssertionError("never get here")
# end class StrictVersion
# The rules according to Greg Stein:
# 1) a version number has 1 or more numbers separated by a period or by
# sequences of letters. If only periods, then these are compared
# left-to-right to determine an ordering.
# 2) sequences of letters are part of the tuple for comparison and are
# compared lexicographically
# 3) recognize the numeric components may have leading zeroes
#
# The LooseVersion class below implements these rules: a version number
# string is split up into a tuple of integer and string components, and
# comparison is a simple tuple comparison. This means that version
# numbers behave in a predictable and obvious way, but a way that might
# not necessarily be how people *want* version numbers to behave. There
# wouldn't be a problem if people could stick to purely numeric version
# numbers: just split on period and compare the numbers as tuples.
# However, people insist on putting letters into their version numbers;
# the most common purpose seems to be:
# - indicating a "pre-release" version
# ('alpha', 'beta', 'a', 'b', 'pre', 'p')
# - indicating a post-release patch ('p', 'pl', 'patch')
# but of course this can't cover all version number schemes, and there's
# no way to know what a programmer means without asking him.
#
# The problem is what to do with letters (and other non-numeric
# characters) in a version number. The current implementation does the
# obvious and predictable thing: keep them as strings and compare
# lexically within a tuple comparison. This has the desired effect if
# an appended letter sequence implies something "post-release":
# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
#
# However, if letters in a version number imply a pre-release version,
# the "obvious" thing isn't correct. Eg. you would expect that
# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
# implemented here, this just isn't so.
#
# Two possible solutions come to mind. The first is to tie the
# comparison algorithm to a particular set of semantic rules, as has
# been done in the StrictVersion class above. This works great as long
# as everyone can go along with bondage and discipline. Hopefully a
# (large) subset of Python module programmers will agree that the
# particular flavour of bondage and discipline provided by StrictVersion
# provides enough benefit to be worth using, and will submit their
# version numbering scheme to its domination. The free-thinking
# anarchists in the lot will never give in, though, and something needs
# to be done to accommodate them.
#
# Perhaps a "moderately strict" version class could be implemented that
# lets almost anything slide (syntactically), and makes some heuristic
# assumptions about non-digits in version number strings. This could
# sink into special-case-hell, though; if I was as talented and
# idiosyncratic as Larry Wall, I'd go ahead and implement a class that
# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
# just as happy dealing with things like "2g6" and "1.13++". I don't
# think I'm smart enough to do it right though.
#
# In any case, I've coded the test suite for this module (see
# ../test/test_version.py) specifically to fail on things like comparing
# "1.2a2" and "1.2". That's not because the *code* is doing anything
# wrong, it's because the simple, obvious design doesn't match my
# complicated, hairy expectations for real-world version numbers. It
# would be a snap to fix the test suite to say, "Yep, LooseVersion does
# the Right Thing" (ie. the code matches the conception). But I'd rather
# have a conception that matches common notions about version numbers.
class LooseVersion(Version):
"""Version numbering for anarchists and software realists.
Implements the standard interface for version number classes as
described above. A version number consists of a series of numbers,
separated by either periods or strings of letters. When comparing
version numbers, the numeric components will be compared
numerically, and the alphabetic components lexically. The following
are all valid version numbers, in no particular order:
1.5.1
1.5.2b2
161
3.10a
8.02
3.4j
1996.07.12
3.2.pl0
3.1.1.6
2g6
11g
0.960923
2.2beta29
1.13++
5.5.kw
2.0b1pl0
In fact, there is no such thing as an invalid version number under
this scheme; the rules for comparison are simple and predictable,
but may not always give the results you want (for some definition
of "want").
"""
component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def parse(self, vstring):
# I've given up on thinking I can reconstruct the version string
# from the parsed tuple -- so I just store the string here for
# use by __str__
self.vstring = vstring
components = [x for x in self.component_re.split(vstring) if x and x != '.']
for i, obj in enumerate(components):
try:
components[i] = int(obj)
except ValueError:
pass
self.version = components
def __str__(self):
return self.vstring
def __repr__(self):
return "LooseVersion ('%s')" % str(self)
def _cmp(self, other):
if isinstance(other, str):
other = LooseVersion(other)
elif not isinstance(other, LooseVersion):
return NotImplemented
if self.version == other.version:
return 0
if self.version < other.version:
return -1
if self.version > other.version:
return 1
# end class LooseVersion

View File

@@ -7,11 +7,11 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from distutils.version import StrictVersion
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
try:
from urllib import quote_plus # Python 2.X
from urlparse import urljoin
@@ -79,7 +79,7 @@ def gitlab_authentication(module):
# python-gitlab library remove support for username/password authentication since 1.13.0
# Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0
# This condition allow to still support older version of the python-gitlab library
if StrictVersion(gitlab.__version__) < StrictVersion("1.13.0"):
if LooseVersion(gitlab.__version__) < LooseVersion("1.13.0"):
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
private_token=gitlab_token, api_version=4)
else:

View File

@@ -38,6 +38,7 @@ from ansible.module_utils.six.moves.urllib.parse import urlencode, quote
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils.common.text.converters import to_native, to_text
URL_REALM_INFO = "{url}/realms/{realm}"
URL_REALMS = "{url}/admin/realms"
URL_REALM = "{url}/admin/realms/{realm}"
@@ -101,6 +102,7 @@ def keycloak_argument_spec():
auth_username=dict(type='str', aliases=['username']),
auth_password=dict(type='str', aliases=['password'], no_log=True),
validate_certs=dict(type='bool', default=True),
connection_timeout=dict(type='int', default=10),
token=dict(type='str', no_log=True),
)
@@ -133,6 +135,7 @@ def get_token(module_params):
auth_username = module_params.get('auth_username')
auth_password = module_params.get('auth_password')
client_secret = module_params.get('auth_client_secret')
connection_timeout = module_params.get('connection_timeout')
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
temp_payload = {
'grant_type': 'password',
@@ -146,7 +149,7 @@ def get_token(module_params):
(k, v) for k, v in temp_payload.items() if v is not None)
try:
r = json.loads(to_native(open_url(auth_url, method='POST',
validate_certs=validate_certs,
validate_certs=validate_certs, timeout=connection_timeout,
data=urlencode(payload)).read()))
except ValueError as e:
raise KeycloakError(
@@ -228,8 +231,34 @@ class KeycloakAPI(object):
self.module = module
self.baseurl = self.module.params.get('auth_keycloak_url')
self.validate_certs = self.module.params.get('validate_certs')
self.connection_timeout = self.module.params.get('connection_timeout')
self.restheaders = connection_header
def get_realm_info_by_id(self, realm='master'):
""" Obtain realm public info by id
:param realm: realm id
:return: dict of real, representation or None if none matching exist
"""
realm_info_url = URL_REALM_INFO.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(realm_info_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
return None
else:
self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
except Exception as e:
self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
def get_realm_by_id(self, realm='master'):
""" Obtain realm representation by id
@@ -239,7 +268,7 @@ class KeycloakAPI(object):
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(realm_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(realm_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
@@ -264,7 +293,7 @@ class KeycloakAPI(object):
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
try:
return open_url(realm_url, method='PUT', headers=self.restheaders,
return open_url(realm_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(realmrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update realm %s: %s' % (realm, str(e)),
@@ -278,7 +307,7 @@ class KeycloakAPI(object):
realm_url = URL_REALMS.format(url=self.baseurl)
try:
return open_url(realm_url, method='POST', headers=self.restheaders,
return open_url(realm_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(realmrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create realm %s: %s' % (realmrep['id'], str(e)),
@@ -293,7 +322,7 @@ class KeycloakAPI(object):
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
try:
return open_url(realm_url, method='DELETE', headers=self.restheaders,
return open_url(realm_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not delete realm %s: %s' % (realm, str(e)),
@@ -311,7 +340,7 @@ class KeycloakAPI(object):
clientlist_url += '?clientId=%s' % filter
try:
return json.loads(to_native(open_url(clientlist_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(clientlist_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of clients for realm %s: %s'
@@ -342,7 +371,7 @@ class KeycloakAPI(object):
client_url = URL_CLIENT.format(url=self.baseurl, realm=realm, id=id)
try:
return json.loads(to_native(open_url(client_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(client_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
@@ -381,7 +410,7 @@ class KeycloakAPI(object):
client_url = URL_CLIENT.format(url=self.baseurl, realm=realm, id=id)
try:
return open_url(client_url, method='PUT', headers=self.restheaders,
return open_url(client_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update client %s in realm %s: %s'
@@ -396,7 +425,7 @@ class KeycloakAPI(object):
client_url = URL_CLIENTS.format(url=self.baseurl, realm=realm)
try:
return open_url(client_url, method='POST', headers=self.restheaders,
return open_url(client_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create client %s in realm %s: %s'
@@ -412,7 +441,7 @@ class KeycloakAPI(object):
client_url = URL_CLIENT.format(url=self.baseurl, realm=realm, id=id)
try:
return open_url(client_url, method='DELETE', headers=self.restheaders,
return open_url(client_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not delete client %s in realm %s: %s'
@@ -427,7 +456,7 @@ class KeycloakAPI(object):
"""
client_roles_url = URL_CLIENT_ROLES.format(url=self.baseurl, realm=realm, id=cid)
try:
return json.loads(to_native(open_url(client_roles_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(client_roles_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch rolemappings for client %s in realm %s: %s"
@@ -459,7 +488,7 @@ class KeycloakAPI(object):
"""
rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
try:
rolemappings = json.loads(to_native(open_url(rolemappings_url, method="GET", headers=self.restheaders,
rolemappings = json.loads(to_native(open_url(rolemappings_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
for role in rolemappings:
if rid == role['id']:
@@ -479,7 +508,7 @@ class KeycloakAPI(object):
"""
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS_AVAILABLE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
try:
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
@@ -495,7 +524,7 @@ class KeycloakAPI(object):
"""
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS_COMPOSITE.format(url=self.baseurl, realm=realm, id=gid, client=cid)
try:
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(available_rolemappings_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
@@ -512,7 +541,8 @@ class KeycloakAPI(object):
"""
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
try:
open_url(available_rolemappings_url, method="POST", headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs)
open_url(available_rolemappings_url, method="POST", headers=self.restheaders, data=json.dumps(role_rep),
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
@@ -528,7 +558,8 @@ class KeycloakAPI(object):
"""
available_rolemappings_url = URL_CLIENT_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=gid, client=cid)
try:
open_url(available_rolemappings_url, method="DELETE", headers=self.restheaders, validate_certs=self.validate_certs)
open_url(available_rolemappings_url, method="DELETE", headers=self.restheaders,
validate_certs=self.validate_certs, timeout=self.connection_timeout)
except Exception as e:
self.module.fail_json(msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s"
% (cid, gid, realm, str(e)))
@@ -542,7 +573,7 @@ class KeycloakAPI(object):
url = URL_CLIENTTEMPLATES.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of client templates for realm %s: %s'
@@ -561,7 +592,7 @@ class KeycloakAPI(object):
url = URL_CLIENTTEMPLATE.format(url=self.baseurl, id=id, realm=realm)
try:
return json.loads(to_native(open_url(url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain client templates %s for realm %s: %s'
@@ -607,7 +638,7 @@ class KeycloakAPI(object):
url = URL_CLIENTTEMPLATE.format(url=self.baseurl, realm=realm, id=id)
try:
return open_url(url, method='PUT', headers=self.restheaders,
return open_url(url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clienttrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update client template %s in realm %s: %s'
@@ -622,7 +653,7 @@ class KeycloakAPI(object):
url = URL_CLIENTTEMPLATES.format(url=self.baseurl, realm=realm)
try:
return open_url(url, method='POST', headers=self.restheaders,
return open_url(url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clienttrep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create client template %s in realm %s: %s'
@@ -638,7 +669,7 @@ class KeycloakAPI(object):
url = URL_CLIENTTEMPLATE.format(url=self.baseurl, realm=realm, id=id)
try:
return open_url(url, method='DELETE', headers=self.restheaders,
return open_url(url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not delete client template %s in realm %s: %s'
@@ -655,7 +686,7 @@ class KeycloakAPI(object):
"""
clientscopes_url = URL_CLIENTSCOPES.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(clientscopes_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(clientscopes_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch list of clientscopes in realm %s: %s"
@@ -672,7 +703,7 @@ class KeycloakAPI(object):
"""
clientscope_url = URL_CLIENTSCOPE.format(url=self.baseurl, realm=realm, id=cid)
try:
return json.loads(to_native(open_url(clientscope_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(clientscope_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
@@ -717,7 +748,7 @@ class KeycloakAPI(object):
"""
clientscopes_url = URL_CLIENTSCOPES.format(url=self.baseurl, realm=realm)
try:
return open_url(clientscopes_url, method='POST', headers=self.restheaders,
return open_url(clientscopes_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientscoperep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Could not create clientscope %s in realm %s: %s"
@@ -732,7 +763,7 @@ class KeycloakAPI(object):
clientscope_url = URL_CLIENTSCOPE.format(url=self.baseurl, realm=realm, id=clientscoperep['id'])
try:
return open_url(clientscope_url, method='PUT', headers=self.restheaders,
return open_url(clientscope_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(clientscoperep), validate_certs=self.validate_certs)
except Exception as e:
@@ -770,7 +801,7 @@ class KeycloakAPI(object):
# should have a good cid by here.
clientscope_url = URL_CLIENTSCOPE.format(realm=realm, id=cid, url=self.baseurl)
try:
return open_url(clientscope_url, method='DELETE', headers=self.restheaders,
return open_url(clientscope_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
@@ -788,7 +819,7 @@ class KeycloakAPI(object):
"""
protocolmappers_url = URL_CLIENTSCOPE_PROTOCOLMAPPERS.format(id=cid, url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(protocolmappers_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(protocolmappers_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch list of protocolmappers in realm %s: %s"
@@ -807,7 +838,7 @@ class KeycloakAPI(object):
"""
protocolmapper_url = URL_CLIENTSCOPE_PROTOCOLMAPPER.format(url=self.baseurl, realm=realm, id=cid, mapper_id=pid)
try:
return json.loads(to_native(open_url(protocolmapper_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(protocolmapper_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
@@ -854,7 +885,7 @@ class KeycloakAPI(object):
"""
protocolmappers_url = URL_CLIENTSCOPE_PROTOCOLMAPPERS.format(url=self.baseurl, id=cid, realm=realm)
try:
return open_url(protocolmappers_url, method='POST', headers=self.restheaders,
return open_url(protocolmappers_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper_rep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Could not create protocolmapper %s in realm %s: %s"
@@ -870,7 +901,7 @@ class KeycloakAPI(object):
protocolmapper_url = URL_CLIENTSCOPE_PROTOCOLMAPPER.format(url=self.baseurl, realm=realm, id=cid, mapper_id=mapper_rep['id'])
try:
return open_url(protocolmapper_url, method='PUT', headers=self.restheaders,
return open_url(protocolmapper_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper_rep), validate_certs=self.validate_certs)
except Exception as e:
@@ -887,7 +918,7 @@ class KeycloakAPI(object):
"""
groups_url = URL_GROUPS.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(groups_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(groups_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg="Could not fetch list of groups in realm %s: %s"
@@ -904,7 +935,7 @@ class KeycloakAPI(object):
"""
groups_url = URL_GROUP.format(url=self.baseurl, realm=realm, groupid=gid)
try:
return json.loads(to_native(open_url(groups_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(groups_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
@@ -950,7 +981,7 @@ class KeycloakAPI(object):
"""
groups_url = URL_GROUPS.format(url=self.baseurl, realm=realm)
try:
return open_url(groups_url, method='POST', headers=self.restheaders,
return open_url(groups_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(grouprep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Could not create group %s in realm %s: %s"
@@ -965,7 +996,7 @@ class KeycloakAPI(object):
group_url = URL_GROUP.format(url=self.baseurl, realm=realm, groupid=grouprep['id'])
try:
return open_url(group_url, method='PUT', headers=self.restheaders,
return open_url(group_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(grouprep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update group %s in realm %s: %s'
@@ -1002,7 +1033,7 @@ class KeycloakAPI(object):
# should have a good groupid by here.
group_url = URL_GROUP.format(realm=realm, groupid=groupid, url=self.baseurl)
try:
return open_url(group_url, method='DELETE', headers=self.restheaders,
return open_url(group_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to delete group %s: %s" % (groupid, str(e)))
@@ -1015,7 +1046,7 @@ class KeycloakAPI(object):
"""
rolelist_url = URL_REALM_ROLES.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(rolelist_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(rolelist_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for realm %s: %s'
@@ -1033,7 +1064,7 @@ class KeycloakAPI(object):
"""
role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name))
try:
return json.loads(to_native(open_url(role_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(role_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
@@ -1053,7 +1084,7 @@ class KeycloakAPI(object):
"""
roles_url = URL_REALM_ROLES.format(url=self.baseurl, realm=realm)
try:
return open_url(roles_url, method='POST', headers=self.restheaders,
return open_url(roles_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create role %s in realm %s: %s'
@@ -1067,7 +1098,7 @@ class KeycloakAPI(object):
"""
role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(rolerep['name']))
try:
return open_url(role_url, method='PUT', headers=self.restheaders,
return open_url(role_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update role %s in realm %s: %s'
@@ -1081,7 +1112,7 @@ class KeycloakAPI(object):
"""
role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name))
try:
return open_url(role_url, method='DELETE', headers=self.restheaders,
return open_url(role_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Unable to delete role %s in realm %s: %s'
@@ -1100,7 +1131,7 @@ class KeycloakAPI(object):
% (clientid, realm))
rolelist_url = URL_CLIENT_ROLES.format(url=self.baseurl, realm=realm, id=cid)
try:
return json.loads(to_native(open_url(rolelist_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(rolelist_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for client %s in realm %s: %s'
@@ -1124,7 +1155,7 @@ class KeycloakAPI(object):
% (clientid, realm))
role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name))
try:
return json.loads(to_native(open_url(role_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(role_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
@@ -1150,7 +1181,7 @@ class KeycloakAPI(object):
% (clientid, realm))
roles_url = URL_CLIENT_ROLES.format(url=self.baseurl, realm=realm, id=cid)
try:
return open_url(roles_url, method='POST', headers=self.restheaders,
return open_url(roles_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create role %s for client %s in realm %s: %s'
@@ -1170,7 +1201,7 @@ class KeycloakAPI(object):
% (clientid, realm))
role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep['name']))
try:
return open_url(role_url, method='PUT', headers=self.restheaders,
return open_url(role_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(rolerep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update role %s for client %s in realm %s: %s'
@@ -1189,7 +1220,7 @@ class KeycloakAPI(object):
% (clientid, realm))
role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name))
try:
return open_url(role_url, method='DELETE', headers=self.restheaders,
return open_url(role_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Unable to delete role %s for client %s in realm %s: %s'
@@ -1205,7 +1236,8 @@ class KeycloakAPI(object):
try:
authentication_flow = {}
# Check if the authentication flow exists on the Keycloak serveraders
authentications = json.load(open_url(URL_AUTHENTICATION_FLOWS.format(url=self.baseurl, realm=realm), method='GET', headers=self.restheaders))
authentications = json.load(open_url(URL_AUTHENTICATION_FLOWS.format(url=self.baseurl, realm=realm), method='GET',
headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs))
for authentication in authentications:
if authentication["alias"] == alias:
authentication_flow = authentication
@@ -1224,7 +1256,7 @@ class KeycloakAPI(object):
flow_url = URL_AUTHENTICATION_FLOW.format(url=self.baseurl, realm=realm, id=id)
try:
return open_url(flow_url, method='DELETE', headers=self.restheaders,
return open_url(flow_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not delete authentication flow %s in realm %s: %s'
@@ -1248,13 +1280,17 @@ class KeycloakAPI(object):
copyfrom=quote(config["copyFrom"])),
method='POST',
headers=self.restheaders,
data=json.dumps(new_name))
data=json.dumps(new_name),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
flow_list = json.load(
open_url(
URL_AUTHENTICATION_FLOWS.format(url=self.baseurl,
realm=realm),
method='GET',
headers=self.restheaders))
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs))
for flow in flow_list:
if flow["alias"] == config["alias"]:
return flow
@@ -1283,14 +1319,18 @@ class KeycloakAPI(object):
realm=realm),
method='POST',
headers=self.restheaders,
data=json.dumps(new_flow))
data=json.dumps(new_flow),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
flow_list = json.load(
open_url(
URL_AUTHENTICATION_FLOWS.format(
url=self.baseurl,
realm=realm),
method='GET',
headers=self.restheaders))
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs))
for flow in flow_list:
if flow["alias"] == config["alias"]:
return flow
@@ -1314,7 +1354,9 @@ class KeycloakAPI(object):
flowalias=quote(flowAlias)),
method='PUT',
headers=self.restheaders,
data=json.dumps(updatedExec))
data=json.dumps(updatedExec),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to update executions %s: %s" % (updatedExec, str(e)))
@@ -1333,7 +1375,9 @@ class KeycloakAPI(object):
id=executionId),
method='POST',
headers=self.restheaders,
data=json.dumps(authenticationConfig))
data=json.dumps(authenticationConfig),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
@@ -1356,7 +1400,9 @@ class KeycloakAPI(object):
flowalias=quote(flowAlias)),
method='POST',
headers=self.restheaders,
data=json.dumps(newSubFlow))
data=json.dumps(newSubFlow),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to create new subflow %s: %s" % (subflowName, str(e)))
@@ -1378,7 +1424,9 @@ class KeycloakAPI(object):
flowalias=quote(flowAlias)),
method='POST',
headers=self.restheaders,
data=json.dumps(newExec))
data=json.dumps(newExec),
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to create new execution %s: %s" % (execution["provider"], str(e)))
@@ -1399,7 +1447,9 @@ class KeycloakAPI(object):
realm=realm,
id=executionId),
method='POST',
headers=self.restheaders)
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
elif diff < 0:
for i in range(-diff):
open_url(
@@ -1408,7 +1458,9 @@ class KeycloakAPI(object):
realm=realm,
id=executionId),
method='POST',
headers=self.restheaders)
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg="Unable to change execution priority %s: %s" % (executionId, str(e)))
@@ -1428,7 +1480,9 @@ class KeycloakAPI(object):
realm=realm,
flowalias=quote(config["alias"])),
method='GET',
headers=self.restheaders))
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs))
for execution in executions:
if "authenticationConfig" in execution:
execConfigId = execution["authenticationConfig"]
@@ -1439,7 +1493,9 @@ class KeycloakAPI(object):
realm=realm,
id=execConfigId),
method='GET',
headers=self.restheaders))
headers=self.restheaders,
timeout=self.connection_timeout,
validate_certs=self.validate_certs))
execution["authenticationConfig"] = execConfig
return executions
except Exception as e:
@@ -1453,7 +1509,7 @@ class KeycloakAPI(object):
"""
idps_url = URL_IDENTITY_PROVIDERS.format(url=self.baseurl, realm=realm)
try:
return json.loads(to_native(open_url(idps_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(idps_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity providers for realm %s: %s'
@@ -1470,7 +1526,7 @@ class KeycloakAPI(object):
"""
idp_url = URL_IDENTITY_PROVIDER.format(url=self.baseurl, realm=realm, alias=alias)
try:
return json.loads(to_native(open_url(idp_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(idp_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
@@ -1490,7 +1546,7 @@ class KeycloakAPI(object):
"""
idps_url = URL_IDENTITY_PROVIDERS.format(url=self.baseurl, realm=realm)
try:
return open_url(idps_url, method='POST', headers=self.restheaders,
return open_url(idps_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(idprep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create identity provider %s in realm %s: %s'
@@ -1504,7 +1560,7 @@ class KeycloakAPI(object):
"""
idp_url = URL_IDENTITY_PROVIDER.format(url=self.baseurl, realm=realm, alias=idprep['alias'])
try:
return open_url(idp_url, method='PUT', headers=self.restheaders,
return open_url(idp_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(idprep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update identity provider %s in realm %s: %s'
@@ -1517,7 +1573,7 @@ class KeycloakAPI(object):
"""
idp_url = URL_IDENTITY_PROVIDER.format(url=self.baseurl, realm=realm, alias=alias)
try:
return open_url(idp_url, method='DELETE', headers=self.restheaders,
return open_url(idp_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Unable to delete identity provider %s in realm %s: %s'
@@ -1531,7 +1587,7 @@ class KeycloakAPI(object):
"""
mappers_url = URL_IDENTITY_PROVIDER_MAPPERS.format(url=self.baseurl, realm=realm, alias=alias)
try:
return json.loads(to_native(open_url(mappers_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(mappers_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity provider mappers for idp %s in realm %s: %s'
@@ -1549,7 +1605,7 @@ class KeycloakAPI(object):
"""
mapper_url = URL_IDENTITY_PROVIDER_MAPPER.format(url=self.baseurl, realm=realm, alias=alias, id=mid)
try:
return json.loads(to_native(open_url(mapper_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(mapper_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
@@ -1570,7 +1626,7 @@ class KeycloakAPI(object):
"""
mappers_url = URL_IDENTITY_PROVIDER_MAPPERS.format(url=self.baseurl, realm=realm, alias=alias)
try:
return open_url(mappers_url, method='POST', headers=self.restheaders,
return open_url(mappers_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not create identity provider mapper %s for idp %s in realm %s: %s'
@@ -1585,7 +1641,7 @@ class KeycloakAPI(object):
"""
mapper_url = URL_IDENTITY_PROVIDER_MAPPER.format(url=self.baseurl, realm=realm, alias=alias, id=mapper['id'])
try:
return open_url(mapper_url, method='PUT', headers=self.restheaders,
return open_url(mapper_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(mapper), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update mapper %s for identity provider %s in realm %s: %s'
@@ -1599,7 +1655,7 @@ class KeycloakAPI(object):
"""
mapper_url = URL_IDENTITY_PROVIDER_MAPPER.format(url=self.baseurl, realm=realm, alias=alias, id=mid)
try:
return open_url(mapper_url, method='DELETE', headers=self.restheaders,
return open_url(mapper_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Unable to delete mapper %s for identity provider %s in realm %s: %s'
@@ -1616,7 +1672,7 @@ class KeycloakAPI(object):
comps_url += '?%s' % filter
try:
return json.loads(to_native(open_url(comps_url, method='GET', headers=self.restheaders,
return json.loads(to_native(open_url(comps_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except ValueError as e:
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of components for realm %s: %s'
@@ -1633,7 +1689,7 @@ class KeycloakAPI(object):
"""
comp_url = URL_COMPONENT.format(url=self.baseurl, realm=realm, id=cid)
try:
return json.loads(to_native(open_url(comp_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(comp_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except HTTPError as e:
if e.code == 404:
@@ -1653,13 +1709,13 @@ class KeycloakAPI(object):
"""
comps_url = URL_COMPONENTS.format(url=self.baseurl, realm=realm)
try:
resp = open_url(comps_url, method='POST', headers=self.restheaders,
resp = open_url(comps_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(comprep), validate_certs=self.validate_certs)
comp_url = resp.getheader('Location')
if comp_url is None:
self.module.fail_json(msg='Could not create component in realm %s: %s'
% (realm, 'unexpected response'))
return json.loads(to_native(open_url(comp_url, method="GET", headers=self.restheaders,
return json.loads(to_native(open_url(comp_url, method="GET", headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs).read()))
except Exception as e:
self.module.fail_json(msg='Could not create component in realm %s: %s'
@@ -1676,7 +1732,7 @@ class KeycloakAPI(object):
self.module.fail_json(msg='Cannot update component without id')
comp_url = URL_COMPONENT.format(url=self.baseurl, realm=realm, id=cid)
try:
return open_url(comp_url, method='PUT', headers=self.restheaders,
return open_url(comp_url, method='PUT', headers=self.restheaders, timeout=self.connection_timeout,
data=json.dumps(comprep), validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not update component %s in realm %s: %s'
@@ -1689,7 +1745,7 @@ class KeycloakAPI(object):
"""
comp_url = URL_COMPONENT.format(url=self.baseurl, realm=realm, id=cid)
try:
return open_url(comp_url, method='DELETE', headers=self.restheaders,
return open_url(comp_url, method='DELETE', headers=self.restheaders, timeout=self.connection_timeout,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Unable to delete component %s in realm %s: %s'

View File

@@ -9,7 +9,8 @@ __metaclass__ = type
import traceback
from ansible.module_utils.basic import missing_required_lib
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:

View File

@@ -75,11 +75,14 @@ class LXDClient(object):
else:
raise LXDClientException('URL scheme must be unix: or https:')
def do(self, method, url, body_json=None, ok_error_codes=None, timeout=None):
def do(self, method, url, body_json=None, ok_error_codes=None, timeout=None, wait_for_container=None):
resp_json = self._send_request(method, url, body_json=body_json, ok_error_codes=ok_error_codes, timeout=timeout)
if resp_json['type'] == 'async':
url = '{0}/wait'.format(resp_json['operation'])
resp_json = self._send_request('GET', url)
if wait_for_container:
while resp_json['metadata']['status'] == 'Running':
resp_json = self._send_request('GET', url)
if resp_json['metadata']['status'] != 'Success':
self._raise_err_from_json(resp_json)
return resp_json

View File

@@ -21,6 +21,8 @@ except ImportError:
from ansible.module_utils.basic import env_fallback, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
def proxmox_auth_argument_spec():
@@ -68,6 +70,9 @@ def ansible_to_proxmox_bool(value):
class ProxmoxAnsible(object):
"""Base class for Proxmox modules"""
def __init__(self, module):
if not HAS_PROXMOXER:
module.fail_json(msg=missing_required_lib('proxmoxer'), exception=PROXMOXER_IMP_ERR)
self.module = module
self.proxmox_api = self._connect()
# Test token validity
@@ -95,3 +100,46 @@ class ProxmoxAnsible(object):
return ProxmoxAPI(api_host, verify_ssl=validate_certs, **auth_args)
except Exception as e:
self.module.fail_json(msg='%s' % e, exception=traceback.format_exc())
def version(self):
apireturn = self.proxmox_api.version.get()
return LooseVersion(apireturn['version'])
def get_node(self, node):
nodes = [n for n in self.proxmox_api.nodes.get() if n['node'] == node]
return nodes[0] if nodes else None
def get_nextvmid(self):
vmid = self.proxmox_api.cluster.nextid.get()
return vmid
def get_vmid(self, name, ignore_missing=False, choose_first_if_multiple=False):
vms = [vm['vmid'] for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm.get('name') == name]
if not vms:
if ignore_missing:
return None
self.module.fail_json(msg='No VM with name %s found' % name)
elif len(vms) > 1:
if choose_first_if_multiple:
self.module.deprecate(
'Multiple VMs with name %s found, choosing the first one. ' % name +
'This will be an error in the future. To ensure the correct VM is used, ' +
'also pass the vmid parameter.',
version='5.0.0', collection_name='community.general')
else:
self.module.fail_json(msg='Multiple VMs with name %s found, provide vmid instead' % name)
return vms[0]
def get_vm(self, vmid, ignore_missing=False):
vms = [vm for vm in self.proxmox_api.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)]
if vms:
return vms[0]
else:
if ignore_missing:
return None
self.module.fail_json(msg='VM with vmid %s does not exist in cluster' % vmid)

View File

@@ -27,20 +27,20 @@ except ImportError:
HAS_CERTIFI_PACKAGE = False
def fail_imports(module):
def fail_imports(module, needs_certifi=True):
errors = []
traceback = []
if not HAS_REDIS_PACKAGE:
errors.append(missing_required_lib('redis'))
traceback.append(REDIS_IMP_ERR)
if not HAS_CERTIFI_PACKAGE:
if not HAS_CERTIFI_PACKAGE and needs_certifi:
errors.append(missing_required_lib('certifi'))
traceback.append(CERTIFI_IMPORT_ERROR)
if errors:
module.fail_json(errors=errors, traceback='\n'.join(traceback))
def redis_auth_argument_spec():
def redis_auth_argument_spec(tls_default=True):
return dict(
login_host=dict(type='str',
default='localhost',),
@@ -50,7 +50,7 @@ def redis_auth_argument_spec():
),
login_port=dict(type='int', default=6379),
tls=dict(type='bool',
default=True),
default=tls_default),
validate_certs=dict(type='bool',
default=True
),
@@ -58,6 +58,30 @@ def redis_auth_argument_spec():
)
def redis_auth_params(module):
login_host = module.params['login_host']
login_user = module.params['login_user']
login_password = module.params['login_password']
login_port = module.params['login_port']
tls = module.params['tls']
validate_certs = 'required' if module.params['validate_certs'] else None
ca_certs = module.params['ca_certs']
if tls and ca_certs is None:
ca_certs = str(certifi.where())
if tuple(map(int, redis_version.split('.'))) < (3, 4, 0) and login_user is not None:
module.fail_json(
msg='The option `username` in only supported with redis >= 3.4.0.')
params = {'host': login_host,
'port': login_port,
'password': login_password,
'ssl_ca_certs': ca_certs,
'ssl_cert_reqs': validate_certs,
'ssl': tls}
if login_user is not None:
params['username'] = login_user
return params
class RedisAnsible(object):
'''Base class for Redis module'''
@@ -66,28 +90,8 @@ class RedisAnsible(object):
self.connection = self._connect()
def _connect(self):
login_host = self.module.params['login_host']
login_user = self.module.params['login_user']
login_password = self.module.params['login_password']
login_port = self.module.params['login_port']
tls = self.module.params['tls']
validate_certs = 'required' if self.module.params['validate_certs'] else None
ca_certs = self.module.params['ca_certs']
if tls and ca_certs is None:
ca_certs = str(certifi.where())
if tuple(map(int, redis_version.split('.'))) < (3, 4, 0) and login_user is not None:
self.module.fail_json(
msg='The option `username` in only supported with redis >= 3.4.0.')
params = {'host': login_host,
'port': login_port,
'password': login_password,
'ssl_ca_certs': ca_certs,
'ssl_cert_reqs': validate_certs,
'ssl': tls}
if login_user is not None:
params['username'] = login_user
try:
return Redis(**params)
return Redis(**redis_auth_params(self.module))
except Exception as e:
self.module.fail_json(msg='{0}'.format(str(e)))
return None

View File

@@ -167,17 +167,61 @@ class Scaleway(object):
SCALEWAY_LOCATION = {
'par1': {'name': 'Paris 1', 'country': 'FR', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/fr-par-1'},
'EMEA-FR-PAR1': {'name': 'Paris 1', 'country': 'FR', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/fr-par-1'},
'par1': {
'name': 'Paris 1',
'country': 'FR',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/fr-par-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/fr-par-1'
},
'par2': {'name': 'Paris 2', 'country': 'FR', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/fr-par-2'},
'EMEA-FR-PAR2': {'name': 'Paris 2', 'country': 'FR', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/fr-par-2'},
'EMEA-FR-PAR1': {
'name': 'Paris 1',
'country': 'FR',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/fr-par-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/fr-par-1'
},
'ams1': {'name': 'Amsterdam 1', 'country': 'NL', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/nl-ams-1'},
'EMEA-NL-EVS': {'name': 'Amsterdam 1', 'country': 'NL', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/nl-ams-1'},
'par2': {
'name': 'Paris 2',
'country': 'FR',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/fr-par-2',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/fr-par-2'
},
'waw1': {'name': 'Warsaw 1', 'country': 'PL', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/pl-waw-1'},
'EMEA-PL-WAW1': {'name': 'Warsaw 1', 'country': 'PL', "api_endpoint": 'https://api.scaleway.com/instance/v1/zones/pl-waw-1'},
'EMEA-FR-PAR2': {
'name': 'Paris 2',
'country': 'FR',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/fr-par-2',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/fr-par-2'
},
'ams1': {
'name': 'Amsterdam 1',
'country': 'NL',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/nl-ams-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/nl-ams-10'
},
'EMEA-NL-EVS': {
'name': 'Amsterdam 1',
'country': 'NL',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/nl-ams-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/nl-ams-1'
},
'waw1': {
'name': 'Warsaw 1',
'country': 'PL',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/pl-waw-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/pl-waw-1'
},
'EMEA-PL-WAW1': {
'name': 'Warsaw 1',
'country': 'PL',
'api_endpoint': 'https://api.scaleway.com/instance/v1/zones/pl-waw-1',
'api_endpoint_vpc': 'https://api.scaleway.com/vpc/v1/zones/pl-waw-1'
},
}
SCALEWAY_ENDPOINT = "https://api.scaleway.com"

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
# Once we drop support for Ansible 2.9, ansible-base 2.10, and ansible-core 2.11, we can
# remove the _version.py file, and replace the following import by
#
# from ansible.module_utils.compat.version import LooseVersion
from ._version import LooseVersion

1
plugins/modules/cargo.py Symbolic link
View File

@@ -0,0 +1 @@
packaging/language/cargo.py

View File

@@ -120,7 +120,7 @@ __version__ = '${version}'
import os
import traceback
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:

View File

@@ -161,7 +161,8 @@ __version__ = '${version}'
import json
import os
import traceback
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:

View File

@@ -42,7 +42,7 @@ options:
description:
- Whether to wait for the tasks to finish before returning.
type: str
default: True
default: 'True'
required: False
requirements:
- python = 2.7
@@ -89,7 +89,8 @@ __version__ = '${version}'
import os
import traceback
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:
@@ -132,8 +133,7 @@ class ClcBlueprintPackage:
self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR)
if not REQUESTS_FOUND:
self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR)
if requests.__version__ and LooseVersion(
requests.__version__) < LooseVersion('2.5.0'):
if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'):
self.module.fail_json(
msg='requests library version should be >= 2.5.0')

View File

@@ -66,8 +66,8 @@ options:
description:
- Whether the firewall policy is enabled or disabled
type: str
choices: [True, False]
default: True
choices: ['True', 'False']
default: 'True'
requirements:
- python = 2.7
- requests >= 2.5.0
@@ -162,7 +162,8 @@ import os
import traceback
from ansible.module_utils.six.moves.urllib.parse import urlparse
from time import sleep
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:
@@ -203,8 +204,7 @@ class ClcFirewallPolicy:
self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR)
if not REQUESTS_FOUND:
self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR)
if requests.__version__ and LooseVersion(
requests.__version__) < LooseVersion('2.5.0'):
if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'):
self.module.fail_json(
msg='requests library version should be >= 2.5.0')

View File

@@ -207,7 +207,8 @@ __version__ = '${version}'
import os
import traceback
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:

View File

@@ -48,7 +48,7 @@ options:
description:
- Port to configure on the public-facing side of the load balancer pool
type: str
choices: [80, 443]
choices: ['80', '443']
nodes:
description:
- A list of nodes that needs to be added to the load balancer pool
@@ -210,7 +210,8 @@ import json
import os
import traceback
from time import sleep
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:
@@ -255,8 +256,7 @@ class ClcLoadBalancer:
self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR)
if not REQUESTS_FOUND:
self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR)
if requests.__version__ and LooseVersion(
requests.__version__) < LooseVersion('2.5.0'):
if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'):
self.module.fail_json(
msg='requests library version should be >= 2.5.0')

View File

@@ -311,7 +311,8 @@ __version__ = '${version}'
import json
import os
import traceback
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
REQUESTS_IMP_ERR = None
try:
@@ -355,8 +356,7 @@ class ClcModifyServer:
self.module.fail_json(msg=missing_required_lib('clc-sdk'), exception=CLC_IMP_ERR)
if not REQUESTS_FOUND:
self.module.fail_json(msg=missing_required_lib('requests'), exception=REQUESTS_IMP_ERR)
if requests.__version__ and LooseVersion(
requests.__version__) < LooseVersion('2.5.0'):
if requests.__version__ and LooseVersion(requests.__version__) < LooseVersion('2.5.0'):
self.module.fail_json(
msg='requests library version should be >= 2.5.0')

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