Compare commits

..

322 Commits
3.2.0 ... 2.5.4

Author SHA1 Message Date
Felix Fontein
16eb0b8749 Release 2.5.4. 2021-06-29 05:57:50 +02:00
patchback[bot]
e8eb6c1163 [nmcli] add connection.slave-type for teamed devices (#2827) (#2899)
* [nmcli] add connection.slave-type for teamed devices

* [nmcli] add fragment with changes for #2827

* [nmcli] add tests for network team

* [nmcli] fix testing

Co-authored-by: Oriol MULA VALLS <oriol.mula@lxp.lu>
(cherry picked from commit 2d1527a564)

Co-authored-by: omula <joriol.mula@gmail.com>
2021-06-28 21:12:57 +02:00
Felix Fontein
21c16ae0b3 Prepare 2.5.4 release. 2021-06-28 07:03:25 +02:00
patchback[bot]
175c481236 pacman: Descriptive state documentation (#2894) (#2897)
* pacman: Descriptive state documentation

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

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

Co-authored-by: Martin Rys <martin@rys.pw>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit debb15efbe)

Co-authored-by: Martin <spleefer90@gmail.com>
2021-06-27 19:05:38 +02:00
patchback[bot]
85d1fecd80 Fix/gitlab project user workspace (#2881) (#2890)
* Add ability to create project under a user

* Add changelog

* Change minor_changes in changelog

As suggested in this comment https://github.com/ansible-collections/community.general/pull/2824#discussion_r653411741

* Fix user's namespace

* Delete changelog

* Add changelog

* Fix changelog

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Amin Vakil <info@aminvakil.com>

* Change user_group_id to namespace_group_id

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

* Change to namespace_id

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 2fb0877577)

Co-authored-by: Stef Graces <stef.graces@nubera.eu>
2021-06-27 14:19:05 +02:00
Felix Fontein
05aaeb3fce _mount module utils - fixed sanity checks (#2883) (#2885)
* updated _mount.py, removed ignore lines

* added changelog fragment

(cherry picked from commit acf7b106c9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-06-27 09:59:25 +02:00
patchback[bot]
d5cf5bf567 modprobe - fix task status when module cannot be loaded (#2843) (#2879)
* Initial Commit

* Adding changelog fragment

* Ensured params are present during verbose output and enhanced check_mode

* Making specific to builtins

* Removing unneccessary external call

* Acutal bugfix

(cherry picked from commit d180390dbc)

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-06-26 13:45:17 +02:00
patchback[bot]
024ef1d782 Adjust example to remove unnecessary offensive language. (#2869) (#2871)
(cherry picked from commit d2a984ded1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-25 06:49:11 +02:00
patchback[bot]
4e06d778ab [PR #2633/07085785 backport][stable-2] Dynamically add meta/runtime.yml redirects for integration tests to correctly report coverage (#2854)
* Dynamically add meta/runtime.yml redirects before integration tests. (#2633)

ci_coverage

(cherry picked from commit 07085785a3)

* Remove superfluous files.

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-22 09:13:40 +02:00
Amin Vakil
72d0c21f56 [backport][stable-2] proxmox_kvm: Fix ZFS device string parsing (#2841) (#2849)
* proxmox_kvm: Fix ZFS device string parsing (#2841)

ZFS-backed block devices may contain just the bare device name and
not have extra options like `,size=foo`, `,format=qcow2` etc. This
breaks an assumption in existing regex (which expects a comma).

Support such device strings and add a couple of testcases to validate.

* Fix

* Update plugins/modules/cloud/misc/proxmox_kvm.py

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

* Update plugins/modules/cloud/misc/proxmox_kvm.py

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

Co-authored-by: Anup Chenthamarakshan <anupcshan@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-21 12:40:28 +02:00
patchback[bot]
f9438bd3c6 npm - fix updating version specific modules (#2830) (#2838)
* npm - fix updating version specific modules

if a version specific module is used, the comparison will be used with the version and not only by name

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

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

* Update changelogs/fragments/2830-npm-version-update.yml

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

* Update changelogs/fragments/2830-npm-version-update.yml

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Update changelogs/fragments/2830-npm-version-update.yml

Co-authored-by: Amin Vakil <info@aminvakil.com>

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 1ed4394c5e)

Co-authored-by: Shahar Mor <shaharmor1@gmail.com>
2021-06-18 22:50:28 +02:00
patchback[bot]
76377dd5bf fix sudorule_add_allow_command_group (#2821) (#2832)
* fix sudorule_add_allow_command_group

fix sudorule_add_allow_command_group is not working on freeIPA 4.8.7 at least, sudorule_add_allow_command should be used instead with item sudocmdgroup

* Added changelog fragment

(cherry picked from commit ee23c26150)

Co-authored-by: TizeN85 <tenou.sylvain@outlook.com>
2021-06-17 19:42:57 +02:00
patchback[bot]
f22fd3c121 Update README (#2802) (#2828)
* Update README

* Update README.md

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Change

* Fix

* Update README.md

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

* Update README.md

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

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Update README.md

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit e9f3455b62)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-06-17 13:39:00 +02:00
patchback[bot]
640f5fd860 Rename test_pr_quick_start_guide.rst to test_pr_locally_guide.rst (#2823) (#2825)
(cherry picked from commit 13ab8f412d)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-06-17 13:38:30 +02:00
patchback[bot]
c670216e27 pamd: Add a note in docs about authselect profiles (#2815) (#2819)
pamd module does not handle or modify authselect profiles
which are basically template files for authselect. The autheselect
generates pam.d files from these profiles.

Fixes: #1954

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 4a47d121aa)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-06-16 22:25:40 +02:00
patchback[bot]
ed8de04cab Add Test PRs locally section to CONTRIBUTING.md (#2738) (#2812)
* Add Test PRs locally section to CONTRIBUTING.md

* fix formatting

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

* Adjust PR now that ansible-collections/community-docs#16 has been merged

* improve sentence

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

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit adf50b106a)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-06-15 20:20:35 +02:00
patchback[bot]
7c4e11f504 BOTMETA.yml: grant supershipit (#2807) (#2810)
(cherry picked from commit b1b34ee12e)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-06-15 19:11:24 +02:00
patchback[bot]
5ee3d77924 BOTMETA.yml: supershipit to quidame (#2801) (#2805)
(cherry picked from commit bccf317814)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-06-14 21:00:18 +02:00
patchback[bot]
9b4dd42813 Make extra sanity test runner produce ansibullbot and JUnit output. (#2794) (#2799)
(cherry picked from commit a55c96d5c1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-14 07:48:56 +02:00
patchback[bot]
049cace2e7 CI: Remove scripts that are no longer needed (#2793) (#2795)
* Remove scripts that are no longer needed.

ci_complete

* Remove sanity ignores.

(cherry picked from commit d4c4d00ad1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-14 05:43:28 +02:00
patchback[bot]
6418098602 Documentation fix for access_level parameter of gitlab_runner (#2788) (#2791)
* * Documentation fix for access_level parameter of gitlab_runner

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>

* Address reviewer's comments

Signed-off-by: Alina Buzachis <abuzachis@redhat.com>
(cherry picked from commit 343339655d)

Co-authored-by: Alina Buzachis <abuzachis@redhat.com>
2021-06-13 09:08:39 +02:00
patchback[bot]
4177da9560 scaleway: Misc doc changes (#2776) (#2785)
* Updated example section for ``variables``
* Added link about token generation
* Misc changes in doc

Fixes: #467

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 4b37b1bca6)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-06-11 19:29:07 +02:00
patchback[bot]
d451fc6292 [scaleway inventory] Fix JSON object must be str, not 'bytes' (#2771) (#2782)
* Fix JSON object decoding

* Code improvement : python 3.5 fix

* Add changelog fragment

* Update changelogs/fragments/2771-scaleway_inventory_json_accept_byte_array.yml

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

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

Co-authored-by: Loïc <loic.latreille@gmail.com>
2021-06-11 13:23:45 +02:00
Felix Fontein
b3450ab331 Next expected release is 2.5.4. 2021-06-08 13:44:52 +02:00
Felix Fontein
eac1dfdc78 Release 2.5.3. 2021-06-08 13:00:19 +02:00
patchback[bot]
930b64226c with great powers come great responsibility (#2755) (#2758)
(cherry picked from commit eef645c3f7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-06-08 10:58:47 +02:00
Felix Fontein
885bb73cc6 ModuleHelper - also uses LC_ALL to force language (#2731) (#2737)
* also uses LC_ALL to force language

* adjusted test_xfconf and test_cpanm

* added changelog fragment

* Update changelogs/fragments/2731-mh-cmd-locale.yml

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

* adjusted chglog frag per PR

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-06-08 10:54:46 +02:00
Felix Fontein
6afde82f2c Prepare 2.5.3 release. 2021-06-08 09:26:18 +02:00
patchback[bot]
62d53eb3cf zypper_repository: fix idempotency on adding repo with releasever and basearch variables (#2722) (#2752)
* zypper_repository: Check idempotency on adding repo with releasever

* Name required when adding non-repo files.

* Initial try to fix releasever

* Replace re.sub with .replace

* name releaseverrepo releaseverrepo

* Change  to ansible_distribution_version for removing repo

* improve asserts format

* add changelog

* Fix changelog formatting

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

* improve command used for retrieving releasever variable

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

* add basearch replace

* Add basearch to changelog fragment

* Check for releasever and basearch only when they are there

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-06-08 08:47:11 +02:00
patchback[bot]
1ae9bcc2dd Re-enable flatpak_remote tests (#2747) (#2748)
* Automate test repo creation, re-enable flatpak_remote tests.

* Linting.

* Another try.

(cherry picked from commit 4c50f1add7)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-07 21:48:40 +02:00
patchback[bot]
1533b5b244 Remove aminvakil from supershipit section as it is not needed anymore (#2743) (#2745)
(cherry picked from commit 7c3f2ae4af)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-06-07 17:02:21 +02:00
patchback[bot]
99295fac75 Add aminvakil to committers (#2739) (#2741)
(cherry picked from commit 1e34df7ca0)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-06-07 16:01:26 +02:00
patchback[bot]
434ff80ec6 iptables_state: fix async status call (-> action plugin) (#2711) (#2728)
* fix call to async_status (-> action plugin)

* add changelog fragment

* Apply suggestions from code review

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

* rename a local variable for readability

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

Co-authored-by: quidame <quidame@poivron.org>
2021-06-06 18:10:26 +02:00
patchback[bot]
be6d3e9aa1 Wire token param into consul_api #2124 (#2126) (#2725)
* Wire token param into consul_api #2124

* Update changelogs/fragments/2124-consul_kv-pass-token.yml

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

* #2124 renamed release fragment to match pr, removed parse_params.

* putting look back in, do some linting   #2124

* try more linting

* linting

* try overwriting defaults in parse_params with get_option vals, instead of removing that function completely.

* Revert "back to start, from 2nd approach: allow keyword arguments via parse_params for compatibility."

This reverts commit 748be8e366.

* Revert " linting"

This reverts commit 1d57374c3e.

* Revert " try more linting"

This reverts commit 91c8d06e6a.

* Revert "putting look back in, do some linting   #2124"

This reverts commit 87eeec7180.

* Revert " #2124 renamed release fragment to match pr, removed parse_params."

This reverts commit d2869b2f22.

* Revert "Update changelogs/fragments/2124-consul_kv-pass-token.yml"

This reverts commit c50b1cf9d4.

* Revert "Wire token param into consul_api #2124"

This reverts commit b60b6433a8.

* minimal chnages for this PR relative to current upstream.

* superfluous newline in changlog fragment.

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

Co-authored-by: fkuep <flo.kuepper@gmail.com>
2021-06-05 23:03:48 +02:00
patchback[bot]
b06d46f4d1 Reduce stormssh searches based on host (#2568) (#2723)
* Reduce stormssh searches based on host

Due to the stormssh searches in the whole config values, we need to reduce the search results based on the full matching of the hosts

* Removed whitespaces in the blank line

* Added changelog fragment and tests for the fix.

* Added newline at the end of the changelog fragment

* Added newline at the end of the tests

* Fixed bug with name in tests

* Changed assertion for the existing host

* Update changelogs/fragments/2568-ssh_config-reduce-stormssh-searches-based-on-host.yml

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

* Adjusted tests

* New line at the end of the tests

Co-authored-by: Anton Nikolaev <anikolaev@apple.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1a4af9bfc3)

Co-authored-by: Anton Nikolaev <drenout@gmail.com>
2021-06-05 16:03:10 +00:00
patchback[bot]
acea90ceec Terraform: ensure workspace is reset to current value (#2634) (#2721)
* fix: ensure workspace is reset to current value

* chore: linter

* chore: changelog

(cherry picked from commit c49a384a65)

Co-authored-by: christophemorio <49184206+christophemorio@users.noreply.github.com>
2021-06-04 21:12:50 +02:00
patchback[bot]
034d09532e Fix repeated word in description of fs_type (#2717) (#2718)
(cherry picked from commit a343756e6f)

Co-authored-by: Alex Willmer <al.willmer@cgi.com>
2021-06-04 21:12:37 +02:00
patchback[bot]
f815bef3d1 Fix action plugin BOTMETA entries. (#2707) (#2713)
(cherry picked from commit 4396ec9631)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-06-04 11:13:25 +02:00
patchback[bot]
e205494c8c BOTMETA.yml: remove myself from zypper_repository (#2701) (#2702)
(cherry picked from commit d93bc039b2)

Co-authored-by: Matthias Vogelgesang <matthias.vogelgesang@gmail.com>
2021-06-04 06:40:28 +02:00
patchback[bot]
1541eecd0e iptables_state: fix broken query of async_status result (#2671) (#2675)
* use get() rather than querying the key directly

* add a changelog fragment

* re-enable CI tests

* Update changelog fragment

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

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

Co-authored-by: quidame <quidame@poivron.org>
2021-05-29 13:54:32 +02:00
patchback[bot]
6cd87580da proxmox_kvm - Fixed vmid result when VM with name exists (#2648) (#2673)
* Fixed vmid result when VM with name exists

* Adding changelog fragment

(cherry picked from commit b281d3d699)

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-05-29 08:50:06 +00:00
patchback[bot]
d227ace4a0 Stop mentioning Freenode. We're on Libera.chat. (#2666) (#2668)
(cherry picked from commit 14813a6287)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-28 07:26:22 +02:00
patchback[bot]
e7770b9132 Add extra docs tests (#2663) (#2664)
* Add extra docs tests.

* Linting.

* Fix copy'n'paste error.

(cherry picked from commit 14f13904d6)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-28 06:48:57 +02:00
patchback[bot]
d0f1d9efd9 xml: Add an example for absent (#2644) (#2655)
Element node can be deleted based upon the attribute
value.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 795125fec4)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-05-27 20:19:39 +02:00
patchback[bot]
22f0747e03 Fix drain example with correct wait values (#2603) (#2657)
(cherry picked from commit 95794f31e3)

Co-authored-by: Merouane Atig <merwan@users.noreply.github.com>
2021-05-27 20:15:28 +02:00
patchback[bot]
2ee7de681a fix a regression in initialization_from_null_state() (iptables-nft > 1.8.2) (#2604) (#2645)
(cherry picked from commit 909e9fe950)

Co-authored-by: quidame <quidame@poivron.org>
2021-05-27 07:16:34 +00:00
patchback[bot]
2e20e9bb8f Temporarily disable iptables_state tests. (#2641) (#2642)
(cherry picked from commit b45298bc43)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-27 08:28:43 +02:00
patchback[bot]
9d9e2bd797 Add one-liner lookup example (#2615) (#2637)
* Add one-liner lookup example

* Remove trailing whitespace

* Update plugins/lookup/tss.py

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

* Update plugins/lookup/tss.py

Co-authored-by: Amin Vakil <info@aminvakil.com>

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 26757edfb2)

Co-authored-by: Sylvia van Os <sylvia@hackerchick.me>
2021-05-27 08:25:44 +02:00
patchback[bot]
d9aa9e8021 influxdb_user: Fix bug introduced by PR 2499 (#2614) (#2639)
* Update influxdb_user.py

Fixed function name

* Create 2614-influxdb_user-fix-issue-introduced-in-PR#2499

Added changelog

* Rename 2614-influxdb_user-fix-issue-introduced-in-PR#2499 to 2614-influxdb_user-fix-issue-introduced-in-PR#2499.yml

Fixed extension

* Update changelogs/fragments/2614-influxdb_user-fix-issue-introduced-in-PR#2499.yml

Co-authored-by: Amin Vakil <info@aminvakil.com>

Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 4aa50962cb)

Co-authored-by: sgalea87 <43749726+sgalea87@users.noreply.github.com>
2021-05-27 08:23:11 +02:00
patchback[bot]
a9eeced6d7 Use become test framework for sudosu tests. (#2629) (#2630)
(cherry picked from commit 0b4a2bea01)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-26 10:47:02 +02:00
patchback[bot]
066b306deb Add CONTRIBUTING.md (#2602) (#2625)
* Initial file shamelessly copied from community.mysql

* Add some notes on pull requests

* Add CONTRIBUTING.md link to README.md

* Add quick-start development guide link

* Apply felixfontein's suggestions

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

* add note about rebasing and merge commits

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

* add note about easyfix and waiting_on_contributor tags

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

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-05-26 10:09:19 +02:00
patchback[bot]
7426c3839e redis cache - better parsing of connection uri (#2579) (#2621)
* better parsing of connection uri

* added changelog fragment

* fixed tests for ansible 2.9

* Update tests/unit/plugins/cache/test_redis.py

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

* Update tests/unit/plugins/cache/test_redis.py

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

* Adjustments from PR

* Update test_redis.py

* Update test_redis.py

* Update plugins/cache/redis.py

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

* Update plugins/cache/redis.py

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

* Update tests/unit/plugins/cache/test_redis.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-05-26 09:59:58 +02:00
patchback[bot]
4d6735bebf jenkins_plugin: HTTP Error 405: Method Not Allowed on disable/enable plugin #2510 (#2511) (#2618)
* define POST method for pluginManager api requests

Jenkins makeEnable/makeDisable api requests requires to use POST method

* add changelog fragment

* fix my yoda lang thx to aminvakil

Co-authored-by: Amin Vakil <info@aminvakil.com>

* update changelog fragment

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 6df3685d42)

Co-authored-by: Alexander Moiseenko <brainsam@yandex.ru>
2021-05-26 07:29:09 +02:00
patchback[bot]
1ceed02048 Use str() to get exception message (#2590) (#2610)
(cherry picked from commit 63012eef82)

Co-authored-by: DasSkelett <dasskelett@gmail.com>
2021-05-25 13:59:51 +02:00
patchback[bot]
6dc31b13c3 json_query, no more 'unknown type' errors (#2607) (#2612)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit d871399220)

Co-authored-by: Brian Coca <bcoca@users.noreply.github.com>
2021-05-25 13:59:01 +02:00
patchback[bot]
c7899e384a rhsm_release: Fix the issue that rhsm_release module considers 8, 7Client and 7Workstation as invalid releases (#2571) (#2605)
* rhsm_release: Fix the issue that rhsm_release module considers 8, 7Client and 7Workstation as invalid releases.

* Fix the unit test error: The new release_matcher could pass a wider range of patterns but that would not cause extra issue to the whole module.

* Submit the changelog fragment.

* Update changelogs/fragments/2571-rhsm_release-fix-release_matcher.yaml

Co-authored-by: Amin Vakil <info@aminvakil.com>

Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 593d622438)

Co-authored-by: Tong He <68936428+unnecessary-username@users.noreply.github.com>
2021-05-24 20:28:22 +00:00
patchback[bot]
35c8bbec8a Massive adjustment in integration tests for changed and failed (#2577) (#2585)
* Replaced ".changed ==" with "is [not] changed". Same for failed

* Mr Quote refused to go

(cherry picked from commit d7e55db99b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-05-22 14:53:10 +02:00
patchback[bot]
87c37ea441 ovir4 inventory script (#2461) (#2582)
* update configparser

* changelog

* handle multiple python version

* Update changelogs/fragments/2461-ovirt4-fix-configparser.yml

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

* Update ovirt4.py

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

Co-authored-by: abikouo <79859644+abikouo@users.noreply.github.com>
2021-05-22 14:36:44 +02:00
patchback[bot]
0f7e39fa1a java_cert - fix incorrect certificate alias on pkcs12 import (#2560) (#2580)
* fix wrong certificate alias used when importing pkcs12, modify error output, stdout is more relevant than stderr

* add changelog fragment

* fix changelog fragment

(cherry picked from commit 8f083d5d85)

Co-authored-by: absynth76 <58172580+absynth76@users.noreply.github.com>
2021-05-22 13:51:24 +02:00
patchback[bot]
cde48c3c03 Add missing author name (#2570) (#2575)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 852e240525)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-05-21 19:44:05 +02:00
patchback[bot]
778c91caa7 removed supporting code for testing module "nuage" - no longer exists here (#2559) (#2562)
(cherry picked from commit 452a185a23)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-05-19 22:23:33 +02:00
patchback[bot]
61258c9216 iptables_state: fix per-table initialization command (#2525) (#2552)
* refactor initialize_from_null_state()

* Use a more neutral command (iptables -L) to load per-table needed modules.

* fix 'FutureWarning: Possible nested set at position ...' (re.sub)

* fix pylints (module + action plugin)

* unsubscriptable-object
* superfluous-parens
* consider-using-in
* unused-variable
* unused-import
* no-else-break

* cleanup other internal module_args if they exist

* add changelog fragment

* Apply suggestions from code review (changelog fragment)

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

* Remove useless plugin type in changelog fragment

Co-authored-by: Amin Vakil <info@aminvakil.com>

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 2c1ab2d384)

Co-authored-by: quidame <quidame@poivron.org>
2021-05-18 12:27:34 +02:00
patchback[bot]
99e0f8a3a0 influxdb_user: allow creation of first user with auth enabled (#2364) (#2368) (#2547)
* influxdb_user: allow creation of first user with auth enabled (#2364)

* handle potential exceptions while parsing influxdb client error

* fix changelog

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

* influxdb_user: use generic exceptions to be compatible with python 2.7

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

Co-authored-by: Xabier Napal <xabiernapal@pm.me>
2021-05-17 19:18:46 +00:00
patchback[bot]
2dd159493b yum_versionlock: disable fedora34 integration test (#2536) (#2537)
* Disable yum_versionlock integration test on Fedora 34

* Remove --assumeyes and add a comment regarding this

* Update update task name

(cherry picked from commit da7e4e1dc2)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-05-17 10:45:34 +02:00
patchback[bot]
28caeff7bd Use --assumeyes with explicit yum call. (#2533) (#2534)
(cherry picked from commit 2cc848fe1a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-17 08:27:22 +02:00
patchback[bot]
76cf21a05b fix error when cache is disabled (#2518) (#2531)
(cherry picked from commit 448b8cbcda)

Co-authored-by: Dennis Israelsson <dennis.israelsson@gmail.com>
2021-05-17 08:09:56 +02:00
patchback[bot]
64248acce6 Update influxdb_user.py Fixed Multiple No Privileges (#2499) (#2529)
* Update influxdb_user.py

Fixed Multiple No Privileges

* Update influxdb_user.py

Fixed line spaces

* Update influxdb_user.py

Fixed whitespace

* Create 2499-influxdb_user-fix-multiple-no-privileges.yml

Added changelog

(cherry picked from commit ea200c9d8c)

Co-authored-by: sgalea87 <43749726+sgalea87@users.noreply.github.com>
2021-05-17 08:09:46 +02:00
patchback[bot]
8ed5beb978 1085 updating the hcl whitelist to include all supported options (#2495) (#2527)
* 1085 updating the hcl whitelist to include all supported options

* Update changelogs/fragments/1085-consul-acl-hcl-whitelist-update.yml

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

Co-authored-by: Dillon Gilmore <dgilmor@rei.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 5b77515308)

Co-authored-by: iridian <442359+iridian-ks@users.noreply.github.com>
2021-05-17 08:09:17 +02:00
patchback[bot]
9b7194be53 Run unit tests also with Python 3.10. (#2486) (#2487)
ci_complete

(cherry picked from commit 624eb7171e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-11 08:31:12 +02:00
Felix Fontein
984d9d91b8 Next expected release will be 2.5.3. 2021-05-11 07:52:00 +02:00
Felix Fontein
071d89acac Release 2.5.2. 2021-05-11 07:07:12 +02:00
patchback[bot]
afc620fc74 Avoid incorrectly marking zfs tasks as changed (#2454) (#2483)
* Avoid incorrectly marking zfs tasks as changed

The zfs module will incorrectly mark certain tasks as having been
changed. For example, if a dataset has a quota of "1G" and the user
changes it to "1024M", the actual quota vale has not changed, but since
the module is doing a simple string comparison between "1G" and "1024M",
it marks the step as "changed".

Instead of trying to handle all the corner cases of zfs (another example
is when the zpool "altroot" property has been set), this change simply
compares the output of "zfs-get" from before and after "zfs-set" is
called

* update changelog format

* Update changelogs/fragments/2454-detect_zfs_changed.yml

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

* add note about check_mode

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

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

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

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

* clarify check mode qualifications

* rephrase to avoid hypothetical

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

Co-authored-by: sam-lunt <samuel.j.lunt@gmail.com>
2021-05-10 18:16:49 +02:00
patchback[bot]
acae2a11aa Clarify Windows (non-)support. (#2476) (#2481)
(cherry picked from commit 2e58dfe52a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-10 17:14:31 +02:00
patchback[bot]
f17690e7d0 fix stackpath_compute validate_config (#2448) (#2474)
* fix stackpath_compute validate_config

get the lenght for the client_id / client_secret to validate inventory configuration

* Add changelog fragment.

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

Co-authored-by: vbarba <victor.barba@gmail.com>
2021-05-09 22:44:39 +02:00
patchback[bot]
4ca716a1cf Small Documentation Example Of Cask Leveraging (#2462) (#2469)
* Small Documentation Example Of Cask Leveraging

- Just a lil' demo showing that we can utilize homebrew/cask/foo syntax
for given name of package to grab associated cask pacakge

Resolves: patch/sml-doc-example-update

* Slight Documentation Example Edit

- adjusting documentation example to provide better info surrounding installing
a given formula from brew via cask

Resolves: patch/sml-doc-example-update

* Small Edits To Make PEP8 Happy

- format code with autopep8 in vs code

Resolves: patch/sml-doc-example-update

* Only Making Small PEP8 Change

- reverting previous mass PEP8 format, focus on trimming whitespace on
doc example entry

Resolves: patch/sml-doc-example-update

* Remove Trailing Whitespace PEP8

- removed trailing whitespace on doc example chunk

Resolves: patch/sml-doc-example-update
(cherry picked from commit 7386326258)

Co-authored-by: Mike Russell <michael.j.russell.email@gmail.com>
2021-05-08 12:27:58 +02:00
patchback[bot]
92f1a33d80 OpenNebula one_vm.py: Fix missing keys (#2435) (#2446)
* OpenNebula one_vm.py: Fix missing keys

* fixup OpenNebula one_vm.py: Fix missing keys

(cherry picked from commit aaa561163b)

Co-authored-by: Jan Orel <jorel@opennebula.io>
2021-05-04 12:43:28 +02:00
patchback[bot]
c9e07d19d8 Remove shippable config. (#2440) (#2443)
(cherry picked from commit 1f41e66f09)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-03 22:56:34 +02:00
patchback[bot]
c7bffaf270 Clean up test entries from sysrc tests (#2330) (#2437)
* Clean up test entries from sysrc tests

* sysrc: enable tests

* sysrc: cache the files to be changed and restore them

* Update the ezjail archive host and remove obsolete file

* sysrc: set ezjail to use archives for 12.0 or less

* sysrc: Detect the version to use ftp vs ftp-archive using http

* sysrc: Skip ezjail test on FreeBSD 12.0

(cherry picked from commit 7007c68ab7)

Co-authored-by: David Lundgren <dlundgren@syberisle.net>
2021-05-03 21:32:23 +02:00
Felix Fontein
1b0f4fdd28 Make plugins pass validation. (#2414) (#2434)
(cherry picked from commit 6a72c3b338)
2021-05-03 14:51:44 +02:00
patchback[bot]
02ea90f680 linode_v4 - fixed error message (#2430) (#2432)
* fixed error message

* added changelog fragment

(cherry picked from commit 5064aa8ec6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-05-03 13:51:14 +02:00
patchback[bot]
6d08dcdef3 📝 Document nested node addition with "_" in xml module (#2371) (#2426)
* 📝 Document nested node addition with "_" in xml module

Nested node addition using "_" to indicate sub nodes, and attributes are only documented in tests and issues, where is hard to find.

* 🚨 Fix trailing space

* Apply suggestions from code review

Add missing collection prefix for modules.

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

* Add missing comments

* Update xml.py

* Fix linter warnings

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

Co-authored-by: Daniel-Sanchez-Fabregas <33929811+Daniel-Sanchez-Fabregas@users.noreply.github.com>
2021-05-03 08:08:43 +02:00
patchback[bot]
8dd00a2b9b nmcli: Compare MAC addresses case insensitively (#2416) (#2424)
* nmcli: Compare MAC addresses case insensitively

* Update changelogs/fragments/2416-nmcli_compare_mac_addresses_case_insensitively.yml

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

* Update plugins/modules/net_tools/nmcli.py

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

* Add mac to TESTCASE_BRIDGE so test_bridge_connection_unchanged covers case sensitive mac address comparison

* Update plugins/modules/net_tools/nmcli.py

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

* Convert current_value to uppercase as well in case nmcli changes behaviour

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

Co-authored-by: spike77453 <spike77453@users.noreply.github.com>
2021-05-03 08:08:10 +02:00
patchback[bot]
a090e2ff85 nmcli: Add 'slave-type bridge' to nmcli command if type is bridge-slave (#2409) (#2422)
(cherry picked from commit b5f8ae4320)

Co-authored-by: spike77453 <spike77453@users.noreply.github.com>
2021-05-03 07:59:58 +02:00
patchback[bot]
ca0b1efa5b puppet - replace stdout with console in logdest option (#2407) (#2420)
* Change stdout to console

* readd stdout, resulting in console

* add changelog

* readd stdout to docs and add a warning when it is used

* version of what???

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

* postpone deprecation in another PR

* remove console option, so it can be backported

* change changelog respectively

* Fix changelog formatting

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

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-05-03 07:59:30 +02:00
patchback[bot]
b2f01f4c20 Fix #2373 - TypeError: a bytes-like object is required, not 'str' (#2375) (#2418)
* Fix #2373

* Changelog fragment for #2373

* Update changelogs/fragments/2373-svr4pkg-fix-typeerror.yml

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Update changelogs/fragments/2373-svr4pkg-fix-typeerror.yml

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit cd957fae4c)

Co-authored-by: Daniel Werner <srmlsrml@gmail.com>
2021-05-03 07:55:55 +02:00
Felix Fontein
81b390b7dc Prepare 2.5.2. 2021-05-03 07:46:46 +02:00
Felix Fontein
9c7eed43a8 Copy schedule to stable branches. 2021-05-02 13:35:28 +02:00
patchback[bot]
6999881985 BOTMETA.yml: terraform - add a new maintainer (#2290) (#2412)
(cherry picked from commit c0221b75af)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-05-02 13:27:41 +02:00
patchback[bot]
d746293884 Add ansible-test config file. (#2404) (#2405)
(cherry picked from commit 4e90ee752e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-01 22:54:41 +02:00
patchback[bot]
7b2853d9aa composer: --no-interaction when discovering available options (#2348) (#2402)
The composer module always uses the no-interaction option if it
discovers it _after_ calling "composer help ..." but not on the help
call itself. The lack of this option caused composer to not exit when
called through the ansible module.

The same example command when ran interactively does not prompt for user
interaction and exits immediately. It is therefore currently unknown why
the same command hangs when called through the ansible composer module
or even directly with the command module.

Example command which hangs:
php /usr/local/bin/composer help install --format=json

(cherry picked from commit eb455c69a2)

Co-authored-by: George Angelopoulos <george@usermod.net>
2021-05-01 18:46:11 +02:00
patchback[bot]
e05e7babbe influxdb_retention_policy: fix duration parsing to support INF values (#2396) (#2400)
* influxdb_retention_policy: fix duration parsing to support INF values

* add changelog

(cherry picked from commit 26c3bd25f6)

Co-authored-by: Xabier Napal <xabiernapal@pm.me>
2021-05-01 14:58:30 +02:00
patchback[bot]
01773c5338 Add Fedora 34 to CI (#2384) (#2390)
* Add fedora 34 and fix typo

* Remove Fedora 32 from devel testing

* Use one newer version of Fedora for fixed ansible versions

* Revert "Use one newer version of Fedora for fixed ansible versions"

This reverts commit cbd006bd38.

* Try to skip task.

* Revert "Try to skip task."

This reverts commit ff0c899a86.

* Temporary disable Fedora 34 on setup_postgresql_db

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-05-01 14:37:29 +02:00
patchback[bot]
e46e6e4dd0 Remove resmo as composer maintainer. (#2392) (#2394)
(cherry picked from commit 276880aac1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-05-01 14:11:10 +02:00
patchback[bot]
270e3df416 Use Ansible's codecov uploader. (#2377) (#2379)
(cherry picked from commit b3f436aa63)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-30 06:01:30 +02:00
Felix Fontein
d9524bae93 Remove programming error which prevents modules to work with devel. (#2381) 2021-04-30 05:50:45 +02:00
patchback[bot]
77fc407a73 No longer required for devel's ansible-test. (#2365) (#2366)
ci_complete

(cherry picked from commit 77d4bc2942)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-27 22:37:04 +02:00
patchback[bot]
2d73089ddc BOTMETA.yml: team_suse - add a maintainer (#2354) (#2361)
(cherry picked from commit 9d13acd68e)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-27 14:14:05 +02:00
patchback[bot]
7a185cef08 Make inventory scripts executable (#2337) (#2358)
* Make inventory scripts executable

* Mark inventory scripts in vault folder as executable

* Add changelog entry for making inventory scripts exectuable

* Update changelogs/fragments/2337-mark-inventory-scripts-executable.yml

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

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

Co-authored-by: Alan Rominger <arominge@redhat.com>
2021-04-26 22:24:40 +02:00
patchback[bot]
6158b5f56b influxdb_retention_policy: ensure duration parameters are idempotent (#2281) (#2284) (#2353)
* influxdb_retention_policy: ensure duration parameters are idempotent (#2281)

* add changelog for pr #2284

(cherry picked from commit aea12899cc)

Co-authored-by: Xabier Napal <naxabier@gmail.com>
2021-04-26 07:28:10 +02:00
patchback[bot]
1b05e03384 jira - fixed base64 decode bug (#2349) (#2350)
* fixed base64 decode bug

* added changelog fragment

(cherry picked from commit 8ddb81a36f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-26 05:18:09 +00:00
patchback[bot]
0f0eb53efa Fix Python 2 compatibility issue. (#2340) (#2352)
(cherry picked from commit 5195536bd8)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-26 07:16:46 +02:00
patchback[bot]
6b58e784af Removes colin-nolan as Consul maintainer (#2342) (#2347)
(cherry picked from commit 399c0ef849)

Co-authored-by: Colin Nolan <colin-nolan@users.noreply.github.com>
2021-04-26 06:50:39 +02:00
patchback[bot]
7d644ef3d4 convert string returned by plugin to unicode (#2329) (#2339)
* convert string returned by plugin to unicode

* add changelog fragment

* fix changelog format

* fix changelog format yet again

Co-authored-by: Anubhav Chakraborty <anubchak@cisco.com>
(cherry picked from commit f11f6595cc)

Co-authored-by: Anubhav Chakraborty <47817745+coderfool@users.noreply.github.com>
2021-04-24 12:48:02 +02:00
patchback[bot]
9db69a62b2 BOTMETA.yml: haproxy - add a maintainer (#2331) (#2332)
(cherry picked from commit 2799cd4ac7)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-22 21:12:14 +02:00
patchback[bot]
1c23ab8d44 nmap: fix cache support (#2282) (#2327)
* add cache support

* pep8 e501 fix

* revert verify_file function

* revert description update

* add changelog fragment

Co-authored-by: Dennis Israelsson <github@mdh.nu>
(cherry picked from commit 31c9ed0fe6)

Co-authored-by: Dennis Israelsson <dennis.israelsson@gmail.com>
2021-04-22 07:52:19 +02:00
patchback[bot]
96c5ceee97 Replace FreeBSD 11.4 with 13.0 for devel testing. (#2324) (#2326)
(cherry picked from commit e0b731e76f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-22 05:37:57 +00:00
patchback[bot]
768512645d with_filetree:: use splitext for compatibility with template: (#2285) (#2322)
* with_filetree: use splitext for compatibility with template

The example code given deploys files with their .j2 extensions intact, which is probably not what you want.

* Explain how templates interact with splitext|first

* Update plugins/lookup/filetree.py

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

* Don't encourage setting the mode of symlinks

On ext4, maybe most filesystems, symlinks always have the artificial mode of 0777, and `chmod $mode $symlink` *writes through* the symlink to its target file.

An effect of this is that if you deploy a file and a symlink to it (e.g. this common situation: /etc/nginx/sites-available/default and /etc/nginx/sites-enabled/default -> ../sites-available/default) then `with_filetree` will forever first deploy the file with the right mode, then corrupt its mode to 0777, and every redeploy will see a change to fix, forever in a loop.

Probably `file:` should refuse `mode:` on `state: link`s, but in the meantime, avoid recommending it in `filetree`

* Use `follow: false` instead of just the mode.

This should be more cross-compatible.

https://github.com/ansible-collections/community.general/pull/2285#discussion_r616571873

* Update plugins/lookup/filetree.py

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

Co-authored-by: Nick <nick@kousu.ca>
2021-04-21 13:03:11 +00:00
patchback[bot]
66656abe17 Temporarily disable sysrc tests since they fail often. (#2318) (#2320)
(cherry picked from commit e1d28cf052)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-21 14:04:31 +02:00
patchback[bot]
022a7834df More renames. (#2307) (#2316)
(cherry picked from commit c768060d95)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-21 13:23:38 +02:00
patchback[bot]
09de2dfd77 BOTMETA.yml: lxd/lxd_profile - add a new maintainer (#2310) (#2315)
(cherry picked from commit fe2757f057)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-21 13:01:14 +02:00
patchback[bot]
bb910f6aa1 BOTMETA.yml: github/github_repo - add a new maintainer (#2309) (#2313)
(cherry picked from commit 8ab19fc50b)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-21 12:21:46 +02:00
patchback[bot]
56d8554b70 Update BOTMETA.yml (#2304) (#2305)
(cherry picked from commit f7928d3eb7)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 23:02:58 +02:00
patchback[bot]
4fa140d896 BOTMETA.yml: update team_virt (#2286) (#2303)
(cherry picked from commit fc12eca65d)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 22:30:09 +02:00
patchback[bot]
5fc3f9c766 BOTMETA.yml: update team_ipa (#2289) (#2302)
(cherry picked from commit 0231dad3e8)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 15:15:24 +02:00
patchback[bot]
0f53fba20a BOTMETA.yml: java_cert - add a new maintainer (#2288) (#2295)
(cherry picked from commit 49c07dc18b)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 13:30:33 +02:00
patchback[bot]
d6c3661e3e BOTMETA.yml: update team_gitlab (#2287) (#2293)
(cherry picked from commit 7aaa26b591)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 13:28:52 +02:00
patchback[bot]
b18c88248b BOTMETA.yml: expand team_opennebula (#2292) (#2299)
(cherry picked from commit 5b4fab80e2)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 13:28:42 +02:00
patchback[bot]
fd5e05cc77 BOTMETA.yml: inventory/proxmox - add a new maintainer (#2291) (#2297)
(cherry picked from commit 84a79c3da4)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-20 13:28:24 +02:00
patchback[bot]
56a1d3ffd6 BOTMETA.yml: callback/loganalytics - add a maintainer (#2271) (#2279)
(cherry picked from commit 04bf8137fa)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-19 19:20:35 +02:00
patchback[bot]
f1477ec8db BOTMETA.yml: monitoring/spectrum_model_attrs - add a maintainer (#2274) (#2276)
(cherry picked from commit 93046e0350)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-19 19:16:11 +02:00
patchback[bot]
2fb1dc0cf7 BOTMETA.yml: filter/version_sort - add a maintainer (#2273) (#2277)
(cherry picked from commit eb3ee83146)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-19 19:16:05 +02:00
patchback[bot]
b9b4837d72 BOTMETA.yml: filter/from_csv - add a maintainer (#2272) (#2278)
(cherry picked from commit 20401c63cd)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-19 19:15:59 +02:00
patchback[bot]
9ea8f41ebb Fix for Terraform 0.15 (#2246) (#2261)
* Fix for Terraform 0.15

removed the append of variables in terraform validate because this is deprecated in Terraform 0.15. See: https://github.com/hashicorp/terraform/blob/v0.15/CHANGELOG.md >> The -var and -var-file options are no longer available on terraform validate. These were deprecated and have had no effect since Terraform v0.12

* Create terraform-validate.yaml

* Update and rename terraform-validate.yaml to 2246-terraform-validate.yaml

* Update changelogs/fragments/2246-terraform-validate.yaml

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Update terraform.py

remove `-force` add `-auto-approve` on destroy as described in issue #2247

* Update and rename 2246-terraform-validate.yaml to 2246-terraform.yaml

* Update 2246-terraform.yaml

* add a function which check the used tf version

* add a function which check the used tf version

* Update changelogs/fragments/2246-terraform.yaml

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Update changelogs/fragments/2246-terraform.yaml

Co-authored-by: Amin Vakil <info@aminvakil.com>

* add version return to function

* changed it to pass sanity check

* change variable name

* changed to a more specialized data types

* remove use_unsafe_shell=True

* Update changelogs/fragments/2246-terraform.yaml

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

* add description

* Update changelogs/fragments/2246-terraform.yaml

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Rainer Leber <rainer.leber@sva.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 1400051890)

Co-authored-by: rainerleber <39616583+rainerleber@users.noreply.github.com>
2021-04-17 22:49:27 +02:00
patchback[bot]
b1fe3e34f3 Fix problems with pip2.6 included in CentOS 6. (#2256) (#2259)
(cherry picked from commit d09bc2525b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-17 20:16:46 +02:00
patchback[bot]
841286444e Proxmox inv fix agent string parsing (#2245) (#2255)
* Added handling for commas in the agent field for agent configuration

* Removed test statement

* Added changelog fragment

* Fixed spelling on fragment :-)

(cherry picked from commit 123b5a9a3c)

Co-authored-by: Jeffrey van Pelt <jeff@vanpelt.one>
2021-04-17 10:43:59 +02:00
patchback[bot]
4c13f10a05 Remove unnecessary required=False s in linode_v4 module (#2251) (#2254)
(cherry picked from commit 085c43b76b)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-04-17 10:21:34 +02:00
patchback[bot]
9b844fc8d5 xenserver_guest - fixed validations (#2243) (#2253)
* fixed cdrom parameter

* fixed networks and custom_params parameters

* fixed disks parameter

* fixed remaining parameters

* removed plugins/modules/cloud/xenserver/xenserver_guest.py from ignore list

* comments from PR

* comments from PR

* more adjustments from the PR

(cherry picked from commit 69a9a77b65)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-17 09:51:16 +02:00
Felix Fontein
92514ee143 Next release will be 2.5.2. 2021-04-14 11:30:28 +02:00
Felix Fontein
6621eb8b87 Release 2.5.1. 2021-04-14 10:02:27 +02:00
patchback[bot]
f4b4a2813a funcd connection plugin is now usable/loadable (#2235) (#2241)
* funcd connection plugin is now usable/loadable

* Update changelogs/fragments/allow_funcd_to_load.yml

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

Co-authored-by: Brian Coca <bcoca@users.noreply.github.com>
2021-04-14 10:00:39 +02:00
patchback[bot]
6f2cb85fae Use nomad_job_info in nomad_job_info examples (#2233) (#2239)
(cherry picked from commit f97d5ca701)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-04-14 10:00:27 +02:00
patchback[bot]
5cdc70bda9 jira - fixed isinstance error (#2236) (#2237)
* fixed isinstance error

* added changelog fragment

(cherry picked from commit bfd6d2b3aa)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-14 10:00:18 +02:00
Felix Fontein
89498d3650 Prepare 2.5.1 release. 2021-04-14 09:15:20 +02:00
Felix Fontein
c553351563 Next expected release is 2.5.1. 2021-04-13 13:52:07 +02:00
Felix Fontein
72c1a17bd9 Release 2.5.0. 2021-04-13 12:53:56 +02:00
patchback[bot]
694584f907 Add Jira attach operation (#2192) (#2231)
* Add Jira attach operation

Adds the `attach` operation to the `web_infrastructure.jira` module,
which allows a user to attach a file to an issue. The user can supply
either the path to a file, which will be read from storage, or a file
name and content (as bytes).

* Apply suggestions from code review

* Update plugins/modules/web_infrastructure/jira.py

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

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

Co-authored-by: Brandon McNama <brandonmcnama@outlook.com>
2021-04-13 08:06:52 +02:00
patchback[bot]
73e2c2eb85 Proxmox_Inv: Adding agent network interaces fact (#2148) (#2228)
* Added agent network interaces fact

* Adding changelog fragment

* More concise looping over interfaces

* Adding unit test case for agent interfaces

* Correcting whitespace issue

* Commented new dummy json returns with corresponding method

(cherry picked from commit 8ab356520d)

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-04-12 20:58:36 +00:00
patchback[bot]
f3ddc8757d spectrum_model_attrs: Initial commit (#1802) (#2229)
* spectrum_model_attrs: Initial commit

* spectrum_model_attrs: sanity check fixes (1)

* Apply suggestions from code review

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

* Apply suggestions from code review:
 * Removed ANSIBLE_METADATA.
 * List all currently supported names in DOCUMENTATION block.
 * Don't escape declarations that are long enough to fit on one
 line.

* Apply suggestions from code review:
  * YAML bools in DOCUMENTATION block.
  * Various DOCUMENTATION block aesthetics.
  * RETURN block proper format.
  * 'yes' -> True declaration in argument spec.
  * import urlencode from python 2 and 3 changed to
    six.moves.urllib.quote.

* spectrum_model_attrs: integration test added.

* Update plugins/modules/monitoring/spectrum_model_attrs.py

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Update plugins/modules/monitoring/spectrum_model_attrs.py

Co-authored-by: Amin Vakil <info@aminvakil.com>

* spectrum_model_attrs: lint error fixes.

Co-authored-by: Tyler Gates <tgates@citco.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 1f001cafd9)

Co-authored-by: tgates81 <31669870+tgates81@users.noreply.github.com>
2021-04-12 20:54:00 +00:00
patchback[bot]
9241b853c0 java_keystore: improve error handling and returned results (#2183) (#2227)
* java_keystore - improve error handling and returned results

* set check_rc=False to return results as documented when module fails
* set LANG, LC_ALL and LC_MESSAGES to C to rely keytool output parsing
* fix pylint's `no-else-return` and `unused-variable` hints
* update related unit tests accordingly
* add a changelog fragment

update unit test (remove stdout_lines from returned dict)

fix unit test: failure is now expected when alias does not exist

* Update changelogs/fragments/2183-java_keystore_improve_error_handling.yml

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

* fix integration test: overwrite keystore at the same location

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

Co-authored-by: quidame <quidame@poivron.org>
2021-04-12 22:13:36 +02:00
patchback[bot]
1053b3c658 Grant supershipit to new maintainers (#2214) (#2222)
* Grant supershipit to a new maintainer

* Add maintainer

(cherry picked from commit 7356451aa1)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-04-12 11:24:13 +02:00
Felix Fontein
d9daa6b851 Fix typo. 2021-04-12 10:35:27 +02:00
Felix Fontein
a876fa0262 Prepare 2.5.0 release. 2021-04-11 17:30:47 +02:00
patchback[bot]
f64ace97af Added modules ipa_otpconfig and ipa_otptoken (#2122) (#2219)
* Added module for ipa_otpconfig

* Make no_log=False explicit.

* Updated inputs to be int type instead of strings to align to expected inputs.  Updated output message

* Add changelog fragment

* Remove changelog fragment as this is a new module

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

Add version_added field to module description.

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

* Updated punctuation in examples

* Add unit test for ipa_otpconfig

* Add ipa_otptoken module with unit test

* Updated documentation in unit test

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Added some documentation updates to make it conform to ansible standards

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

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

* Address review comments

Co-authored-by: Chris Costa <chris.costa@compellingtech.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 31645ded11)

Co-authored-by: justchris1 <30219018+justchris1@users.noreply.github.com>
2021-04-11 15:53:33 +02:00
patchback[bot]
b701b5893f npm: Add no_bin_links option (#2146) (#2217)
* Add no-bin-links option to npm

* Add changelog

* Fix changelog format

* Add integration test

* Change node package from thelounge to ncp

(cherry picked from commit fa13826273)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-04-11 06:25:22 +02:00
patchback[bot]
24667e12d0 Added fields to the ipa_config module (#2116) (#2216)
* Added fields to the ipa_config module: ipadefaultprimarygroup, ipagroupsearchfields, ipahomesrootdir, ipamaxusernamelength, ipapwdexpadvnotify, ipasearchrecordslimit, ipasearchtimelimit, ipauserauthtype, ipausersearchfields

* Fixed typos in documentation spec

* Updated a field that was missing the version_added decoration

* Add changelog fragment

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

Cleanup example to be consistent with others.

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

* Cleanup example to be consistent with others.

* Fixed changelog fragment

* Updated punctuation in examples

* Switched some elements to use int instead of str, and fixed duplicated example

* Change type of field for ipauserauthtype to list of str, add support for ipaconfigstring and ipakrbauthzdata

* Update fragment to represent adding support for ipaconfigstring and ipakrbauthzdata

* Update changelogs/fragments/2116-add-fields-to-ipa-config-module.yml

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

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

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

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

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

* Address review comments by making inputs into group search and user search fields a list of strings, even though IPA does not treat it as a multiselect field

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

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

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

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

Co-authored-by: Chris Costa <chris.costa@compellingtech.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 5502e4ec17)

Co-authored-by: justchris1 <30219018+justchris1@users.noreply.github.com>
2021-04-11 06:25:04 +02:00
patchback[bot]
9d93760564 Bugfix: PyGithub does not support explicit port in base_url (#2204) (#2215)
* Bugfix: PyGithub does not support explicit port in base_url

* Fix unit tests

* Fix unit tests

* Added changelog

* Update changelogs/fragments/2204-github_repo-fix-baseurl_port.yml

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

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

Co-authored-by: Álvaro Torres Cogollo <atorrescogollo@gmail.com>
2021-04-09 12:16:29 +02:00
patchback[bot]
ec78558559 New module: Add Pritunl VPN organization module (net_tools/pritunl/) (#804) (#2212)
(cherry picked from commit f0b7c6351e)

Co-authored-by: Florian Dambrine <Lowess@users.noreply.github.com>
2021-04-09 05:35:07 +02:00
patchback[bot]
d5c8d7ddcc inventory/proxmox: added constructable and added keyed_groups, groups and compose (#2180) (#2211)
* added constructable and added keyed_groups, groups and compose

* Update changelogs/fragments/2162-proxmox-constructable.yml

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

* added constructed to extends_documentation_fragment and version_added to all the items

* renamed _apply_rules to _apply_constructable for more clarity

* Update changelogs/fragments/2162-proxmox-constructable.yml

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

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

Co-authored-by: Ilija Matoski <ilijamt@gmail.com>
2021-04-09 05:34:52 +02:00
patchback[bot]
6338048c73 Add path_join compatibility shim (#2172) (#2206)
* Add path_join compatibility shim.

* Add myself as maintainer.

(cherry picked from commit 4b6722d938)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-08 08:31:35 +02:00
patchback[bot]
92b388817f Add dict filter (#2171) (#2205)
* Add dict and list_to_dict filters.

* Remove list_to_dict filter.

* Add myself as maintainer.

(cherry picked from commit b6ae47c455)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-08 08:26:13 +02:00
patchback[bot]
c72b337327 module_helper - fixed decorator cause_changes (#2203) (#2207)
* fixed decorator cause_changes

* added changelog fragment

* typo

(cherry picked from commit 0cd0f0eaf6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-08 08:26:04 +02:00
patchback[bot]
e5080b7847 Fix issue where multiselect field in userauthtype did not allow multiple values (#2174) (#2202)
* Fix issue where multiselect field in userauthtype did not allow multiple values

* Add changelogfragment for change

* Update changelogs/fragments/2174-ipa-user-userauthtype-multiselect.yml

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

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

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

* Update changelogs/fragments/2174-ipa-user-userauthtype-multiselect.yml

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

Co-authored-by: Chris Costa <chris.costa@compellingtech.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 595d590862)

Co-authored-by: justchris1 <30219018+justchris1@users.noreply.github.com>
2021-04-07 21:48:31 +02:00
patchback[bot]
079925fe66 ipa_user sshpubkey can now support multi word comments in the key (#2159) (#2201)
* ipa_user sshpubkey can now support multi word comments in the key

* Add documentation fragment for pull request

* Update changelogs/fragments/2159-ipa-user-sshpubkey-multi-word-comments.yaml

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

* Cleaner implementation of multi word comments

Co-authored-by: Chris Costa <chris.costa@compellingtech.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 7f91821bcc)

Co-authored-by: justchris1 <30219018+justchris1@users.noreply.github.com>
2021-04-07 20:55:33 +02:00
patchback[bot]
19a87874f7 Update java_cert module (#2008) (#2199)
* porting https://github.com/ansible/ansible/pull/56778 as requested in https://github.com/ansible-collections/community.general/issues/821

* fix imports, add back trust_cacerts option

* try to fix import, ansible-lint fixes

* modify import to use ansible.module_utils.six instead

* cleanup indentation for tests/integration/targets/java_cert/tasks/main.yml file

* remove external crypto dependency - switch to openssl, work on password obfuscation, using files compare to reduce logic

* java_cert - remove latest run_command using password in arguments

* fix sanity check

* rename changelog fragment file - wrong extension

* add openssl dependency

* fix openssl_bin parameter missing on _get_digest_from_x509_file function call

* remove useless close files, fix paragraph, fix changelog, clean import re

* fix missing dots at end-of-line in changelogs fragments

* fix reminder case

* fix changelog

* restore .gitignore

* fix indentation on integration test files, delete useless json file

* fix typo importing tasks in tests/integration/targets/java_cert/tasks/main.yml

* Update changelogs/fragments/2008-update-java-cert-replace-cert-when-changed.yml

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

* Update tests/integration/targets/java_cert/tasks/state_change.yml

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* Update plugins/modules/system/java_cert.py

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

* fix hardcoded executable keytool, use re.sub instead of import, add required cert_url or cert_alias parameter when absent, fix python script and cert_url test

* fix pylint issue with setupSSLServeR.py

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

Co-authored-by: absynth76 <58172580+absynth76@users.noreply.github.com>
2021-04-07 20:41:58 +02:00
patchback[bot]
809cdda9ef Fix HAProxy draining (#1993) (#2198)
* Fix HAProxy draining by manually entering the 'MAINT' state

Inspired by rldleblanc: https://github.com/ansible/ansible/issues/37591#issuecomment-610130611

Signed-off-by: Norman Ziegner <norman.ziegner@ufz.de>

* Add changelog fragment

Signed-off-by: Norman Ziegner <norman.ziegner@ufz.de>

* Fix drain function docstring

Signed-off-by: Norman Ziegner <norman.ziegner@ufz.de>

* Fix typos

Signed-off-by: Norman Ziegner <norman.ziegner@ufz.de>

* Update changelog fragment

Signed-off-by: Norman Ziegner <norman.ziegner@ufz.de>
(cherry picked from commit 7145204594)

Co-authored-by: Norman Ziegner <normo157@gmail.com>
2021-04-07 20:15:51 +02:00
patchback[bot]
bec6f732ad jira - changing the logic for transition (#1978) (#2195)
* attempt at fixing the issue

* Update plugins/modules/web_infrastructure/jira.py

* Fixed setting of "fields" element in the payload

* added changelog fragment

* added accountId parameter + minor fixes in docs

* added integration test for jira

* adjustments per PR

* Update plugins/modules/web_infrastructure/jira.py

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

* Update plugins/modules/web_infrastructure/jira.py

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

* Update plugins/modules/web_infrastructure/jira.py

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

* Update plugins/modules/web_infrastructure/jira.py

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

* Update plugins/modules/web_infrastructure/jira.py

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

* adjustments per PR

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-07 08:39:06 +02:00
patchback[bot]
d2cdca416c Applying ModuleHelper variable mgmt to xfconf -> improvements on MH (#2188) (#2191)
* applying MH variable mgmt to xfconf - improvements on MH

* added changelog fragment

(cherry picked from commit 9aec9b502e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-06 21:51:12 +02:00
patchback[bot]
0f1ccc07c5 xfconf - state absent was not honoring check_mode (#2185) (#2186)
* state absent was not honoring check_mode

* added changelog fragment

(cherry picked from commit 9a5191d1f9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-06 17:26:52 +02:00
patchback[bot]
deb1071666 [PR #2130/6bea8215 backport][stable-2] ansible/ansible's stable-2.11 branch has been created. (#2184)
* ansible/ansible's stable-2.11 branch has been created. (#2130)

(cherry picked from commit 6bea8215c9)

* Update ignore-2.12.txt.

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-06 08:31:47 +02:00
patchback[bot]
eb9c5eb796 replace inline clear password by environment variable (#2177) (#2182)
* replace inline clear password by environment variable on a per-command basis.

* add changelog fragment
* update related unit tests

* Update changelogs/fragments/2177-java_keystore_1668_dont_expose_secrets_on_cmdline.yml

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

* fix unit test: force result without lambda

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

Co-authored-by: quidame <quidame@poivron.org>
2021-04-05 18:45:06 +02:00
patchback[bot]
5c8504323e ModuleHelper variables management (#2162) (#2178)
* added metadata for variables in module helper

* adjustments

* added separate support for tracking changes

* rewrote the diff code

* added integration test for module_helper

* using ansible.module_utils.common.dict_transformations.dict_merge

* improved dependency management

* restore ModuleHelper to base classes of CmdStateModuleHelper

* added assertions to ensure the failing module name appears in the error messages

* added test code for state-based modules

* fixed test name

* renamed class to VarMeta

* small fixes

* fixes from the PR

* fixed VarDict.__set_attr__

* added VarDict.__getitem__()

* added changelog fragment

* adjustments per PR

* ModuleHelper.output is now aware of conflicting variable names

* Update plugins/module_utils/module_helper.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-05 15:39:08 +02:00
patchback[bot]
ab391c2cfa java_keystore/fix 1667 improve temp files storage (#2163) (#2176)
* improve temporary files storage (naming/removal)

* update unit tests

* Update changelogs/fragments/2163-java_keystore_1667_improve_temp_files_storage.yml

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

* add dedicated function to randomize PKCS#12 filename

fix unit tests (also mock the new function)

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

Co-authored-by: quidame <quidame@poivron.org>
2021-04-05 15:19:17 +02:00
patchback[bot]
a14b525bdc removed unreachable code (#2157) (#2170)
* removed unreachable code

* added changelog fragment

(cherry picked from commit b81a7cdd16)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-05 09:50:16 +02:00
patchback[bot]
996ef6ab49 rewritten as list literals (#2160) (#2168)
* rewritten as list literals

* added changelog fragment

(cherry picked from commit b97e31dd55)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-05 09:50:07 +02:00
patchback[bot]
055c8dac9c fixed calls to list.extend() (#2161) (#2166)
* fixed calls to list.extend()

* added changelog fragment

* Update changelogs/fragments/2161-pkgutil-list-extend.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-04 23:59:59 +02:00
patchback[bot]
f4a9c7cc8b [WIP] Committer guidelines (#2077) (#2153)
* First idea for committer guidelines.

* Update commit-rights.md

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

* Update commit-rights.md

Co-authored-by: John R Barker <john@johnrbarker.com>

* Apply suggestions from code review

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

* Improve 'do not' list.

* Add improvements from ansible/ansible#73782.

* Apply suggestions from code review

Co-authored-by: Amin Vakil <info@aminvakil.com>

* Apply suggestions from code review

* Update commit-rights.md

* Update commit-rights.md

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
Co-authored-by: John R Barker <john@johnrbarker.com>
Co-authored-by: Amin Vakil <info@aminvakil.com>
(cherry picked from commit 95156a11a1)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-04-03 11:09:28 +00:00
patchback[bot]
0c1f96290a using get_bin_path() on atomic modules (#2144) (#2151)
* using get_bin_path() on atomic modules

* added changelog fragment

* Update changelogs/fragments/2144-atomic_get_bin_path.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-02 22:35:56 +02:00
patchback[bot]
d260f7ffda kibana_plugin: fixed remove call + run_command with list instead of str (#2143) (#2149)
* fixed remove call + run_command with list instead of str

* fixed the other calls to run_command()

* added changelog fragment

* adjustment on run_command params

* Update changelogs/fragments/2143-kibana_plugin-fixed-function-calls.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-02 22:25:57 +02:00
patchback[bot]
35d81adabf apache2_mod_proxy - minor improvements/fixes (#2142) (#2145)
* minor improvements/fixes

- moved imports from the bottom of the code to the top (ansible-style).
- pythonified/simplified get_member_status()/set_member_status()
- reduced clutter in Balancer.__init__()

* added changelog fragment

(cherry picked from commit 1d1cbc4f56)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-04-01 09:01:38 +02:00
patchback[bot]
10a61c9dc3 fixed str formatting (#2139) (#2141)
(cherry picked from commit f1dbef4143)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-31 14:15:05 +02:00
patchback[bot]
6f47bcc399 fix type information for vmadm.resolvers (#2136) (#2138)
* fix type information for vmadm.resolvers

* Update changelogs/fragments/2135-vmadm-resolvers-type-fix.yml

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

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

Co-authored-by: Gaige B Paulsen <github@gbp.gaige.net>
2021-03-31 12:00:29 +02:00
Felix Fontein
7140b456ae Next release will be 2.5.0. 2021-03-30 13:39:08 +02:00
Felix Fontein
8c67a5bda9 Release 2.4.0. 2021-03-30 12:39:01 +02:00
patchback[bot]
4ae436a8cc Callback plugin: Azure Log Analytics (#2091) (#2133)
* adding plugins/callback/loganalytics.py

* * fixed sanity check issues
* adjusted documentation and license sections

* added changelogs fragment

* * added unit test
* documentation updated

* updated changelogs

* further docuement update

* minor fixes

* updated unittest

* suggested updates from community

* remove AnsibleError section

(cherry picked from commit 19db6f24f7)

Co-authored-by: zhcli <49675498+zhcli@users.noreply.github.com>
2021-03-30 12:37:52 +02:00
Felix Fontein
5f5c07a942 Add release summary. 2021-03-30 12:14:33 +02:00
patchback[bot]
1cef1359d0 git_config - fixed bug with scope file (#2125) (#2132)
* fixed bug

- scope file was not working
- added test to guarantee that behaviour
- marked integration test as destructive, because it overwrites ~/.gitconfig

* added changelog fragment

* Update tests/integration/targets/git_config/tasks/setup_no_value.yml

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

* Update tests/integration/targets/git_config/tasks/get_set_state_present_file.yml

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

* Update tests/integration/targets/git_config/tasks/get_set_state_present_file.yml

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

* Update tests/integration/targets/git_config/aliases

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

* Update changelogs/fragments/2125-git-config-scope-file.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-30 09:20:04 +02:00
patchback[bot]
0d28bfb67e vdo: add force option (#2110) (#2123)
* vdo: add force option

* Add changelog

* Improve the diff the next time something is added :)

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

* Add warning text placeholder by felixfontein

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

* Add warning text

* Apply suggestion for warning text from rhawalsh

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

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-03-27 15:41:58 +01:00
patchback[bot]
ef304ed824 remove billdodd from team_redfish (#2118) (#2120)
(cherry picked from commit 0de196413f)

Co-authored-by: Bill Dodd <billdodd@gmail.com>
2021-03-26 20:08:05 +01:00
patchback[bot]
bf17f289b3 AZP: update default container version (#2112) (#2114)
(cherry picked from commit 0bc76c98b0)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2021-03-26 13:09:43 +01:00
patchback[bot]
0eff87d0be opennebula: add one_template module (#2046) (#2111)
* opennebula: add one_template module

A basic module for maintaining VM templates which should be flexible enough
for most needs ...

* fixup! opennebula: add one_template module

* fixup! fixup! opennebula: add one_template module

(cherry picked from commit cdc415ea1f)

Co-authored-by: Georg Gadinger <nilsding@nilsding.org>
2021-03-26 07:47:38 +01:00
Abhijeet Kasurde
f00fabfa48 Typo fix in changelog (#2030)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-03-26 07:24:37 +01:00
patchback[bot]
426cbafa06 ipa_service - Correct pluralisation of "hosts" in example (#2103) (#2105)
(cherry picked from commit 2558cd3f01)

Co-authored-by: Alex Willmer <al.willmer@cgi.com>
2021-03-26 07:09:53 +01:00
patchback[bot]
93fe1f9a3e Bugfix: Respect PATH env variable in zypper modules (#2094) (#2109)
* Bugfix: Respect PATH env variable in zypper modules

* Improve changelogs/fragments/2094-bugfix-respect-PATH-env-variable-in-zypper-modules.yaml

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

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

Co-authored-by: Stefan Richter <sealor@users.noreply.github.com>
2021-03-25 22:57:53 +01:00
patchback[bot]
4e944772d5 Updated vdo maintainer to rhawalsh. (#2102) (#2107)
bgurney-rh does not work with VDO projects anymore.  This change re-points
maintainer pings to rhawalsh instead.

(cherry picked from commit 62cd38a9a0)

Co-authored-by: Andy Walsh <33293922+rhawalsh@users.noreply.github.com>
2021-03-25 22:46:04 +01:00
patchback[bot]
50abeee579 Add a Pulp 2 related note to pulp_repo (#2096) (#2100)
(cherry picked from commit de8e2a83e2)

Co-authored-by: Matthias Dellweg <2500@gmx.de>
2021-03-24 18:13:04 +01:00
patchback[bot]
eccc8d88b6 Add support for sudo su - using password auth (#2054) (#2097)
* Add support for `sudo su -` using password auth

Allow users to run Ansible tasks through `sudo su -` using password auth

- Feature Pull Request

sudosu

So I have been using this at various customers for bootstrapping Ansible mostly.

Often you have an existing setup where there is a user that has root-access enabled through sudo, but only to run `su` to log using the user's password.
In these specific cases the root password is unique to the system and therefore not an easy way to automate bootstrapping.

Having a `sudo su -` become option **with password prompt** is not possible with the existing become methods (neither sudo nor su can be used) by abusing `become_exe` or `become_flags`.

This fixes ansible/ansible#12686

* Fix all reported issues

* Add unit tests

* Apply suggestions from code review

* Update plugins/become/sudosu.py

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

* Update tests/unit/plugins/become/test_sudosu.py

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

* Update tests/unit/plugins/become/test_sudosu.py

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

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

Co-authored-by: Dag Wieers <dag@wieers.com>
2021-03-24 17:48:53 +01:00
patchback[bot]
6d2d364a00 add new module xcc_redfish_command to manage Lenovo servers using Redfish APIs (#2007) (#2095)
* add new module xcc_redfish_command to manage Lenovo servers using Redfish APIs

* Update plugins/modules/remote_management/lenovoxcc/xcc_redfish_command.py

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

* fix some errors detected by ansible-test sanity

* end all descriptions (except short_description) with a period

* fix return definition problem and other errors detected by ansible-test sanity

* Always use true/false for booleans in YAML

* It is usually a good idea to leave away required: false

* fix errors detected by ansible-test sanity

* fix elements of command is not defined

* check whether resource_uri is specified for Raw commands

* if no Members property, return false; if empty array, return true

* get @odata.etag from patch body instead of getting again

* add request_body checking

* add unit test for the module

* fix errors detected by ansible-test sanity --test pep8

* update class name xcc_RedfishUtils to XCCRedfishUtils to follow convention; import AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args, exit_json, fail_json from ansible_collections.community.general.tests.unit.plugins.modules.utils instead of inline them

* support using security token for auth

* fix line too long error

* As 2.3.0 got released yesterday, move to 2.4.0

* add maintainers for lenovoxcc

* update to make sure that it's sorted alphabetically

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

Co-authored-by: panyy3 <panyy3@lenovo.com>
2021-03-24 16:43:11 +01:00
patchback[bot]
e781dd3c9b fixed documentation for oneview modules (#2092) (#2093)
(cherry picked from commit 94cf07efbf)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-24 16:41:03 +01:00
Felix Fontein
362f899a99 Next expected release is 2.4.0. 2021-03-23 13:30:16 +01:00
Felix Fontein
b44f6b8114 Release 2.3.0. 2021-03-23 12:21:35 +01:00
patchback[bot]
53a145ecb0 Install collections in CI directly with git to work around the Galaxy CloudFlare PITA. (#2082) (#2086)
(cherry picked from commit 7fe9dd7a60)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-03-23 07:42:21 +01:00
patchback[bot]
b22b44088f Temporarily disable copr integration tests due to failures with remote repository. (#2083) (#2085)
(cherry picked from commit 09351d9010)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-03-23 07:17:20 +01:00
patchback[bot]
e0a1aa2f46 Fixed documentation (#2062) (#2081)
(cherry picked from commit 88994ef2b7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-22 20:55:53 +01:00
patchback[bot]
53e7e48834 improve force_archive parameter documentation of archive module (#2052) (#2079)
* improve documentation for force_archive parameter

* add link to unarchive module

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

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

Co-authored-by: Triantafyllos <ttsak@hotmail.com>
2021-03-22 20:55:37 +01:00
Bill Dodd
62e3a2ed2f Add support for Redfish session create, delete, and authenticate (#2027) (#2053)
* Add support for Redfish session create, delete, and authenticate (#2027)

* Add support for Redfish session create and delete

* add changelog fragment

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

* fix inadvertant spaces around equals
2021-03-22 18:27:25 +01:00
Felix Fontein
ecede6ca99 Prepare 2.3.0 release. 2021-03-22 07:58:24 +01:00
patchback[bot]
e1ac1fa6db stacki_host - configured params to use fallback instead of default (#2072) (#2076)
* configuredd params to use fallback instead of default

* added changelog fragment

(cherry picked from commit 5fc56676c2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-21 15:43:12 +01:00
patchback[bot]
81cef0bd05 New Filter plugin from_csv (#2037) (#2074)
* Added from_csv filter and integration tests

* Cleaning up whitespace

* Adding changelog fragment

* Updated changelog fragment name

* Removed temp fragment

* Refactoring csv functions Part 1

* Syncing refactored csv modules/filters

* Adding unit tests for csv Module_Util

* Updating changelog fragment

* Correcting whitespace in unit test

* Improving changelog fragment

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

* Update changelogs/fragments/2037-add-from-csv-filter.yml

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

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-03-21 13:56:32 +01:00
patchback[bot]
a2bb118e95 Add gandi_livedns module (#328) (#2070)
* Add gandi_livedns module

This module uses REST API to register, update and delete domain name
entries in Gandi DNS service (https://www.gandi.net/en/domain).

* Apply suggestions from code review

* Update plugins/module_utils/gandi_livedns_api.py

Co-authored-by: Gregory Thiemonge <greg@thiemonge.org>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 81f3ad45c9)

Co-authored-by: Gregory Thiemonge <44313235+gthiemonge@users.noreply.github.com>
2021-03-21 13:22:14 +01:00
patchback[bot]
bf9bcd9bb4 snmp_facts - added timeout and retries params to module (#2065) (#2073)
* added timeout and retries params to module

* added changelog fragment

* Update plugins/modules/net_tools/snmp_facts.py

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

* Update plugins/modules/net_tools/snmp_facts.py

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

* removed default for retries per suggestion in PR

* Update plugins/modules/net_tools/snmp_facts.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-21 11:52:40 +01:00
patchback[bot]
9bfd61e117 New module: Add Pritunl VPN user module (net_tools/pritunl/) (#803) (#2071)
(cherry picked from commit 68fc48cd1f)

Co-authored-by: Florian Dambrine <Lowess@users.noreply.github.com>
2021-03-21 11:46:33 +01:00
patchback[bot]
ca81a5cf2f ipa_sudorule add support for setting runasextusers (#2031) (#2068)
* Add support for setting runasextusers

* fix formatting

* add changelog fragment

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

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

* Update changelogs/fragments/2031-ipa_sudorule_add_runasextusers.yml

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

Co-authored-by: quasd <qquasd@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit ff9f98795e)

Co-authored-by: quasd <quasd@users.noreply.github.com>
2021-03-21 11:24:07 +01:00
patchback[bot]
853dd21eab archive - a first refactoring (#2061) (#2069)
* a first refactoring on archive

* added changelog fragment

* suggestion from PR

(cherry picked from commit 606eb0df15)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-21 11:23:55 +01:00
patchback[bot]
6f267d8f35 archive - created an integration test that archives broken links (#2063) (#2066)
* created an integration test that archives broken links

* sanity fix

(cherry picked from commit f5a9584ae6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-21 10:37:43 +01:00
patchback[bot]
1f975eff56 Fix nios modules to work with ansible-core 2.11 (#2057) (#2059)
* Fix nios modules to work with ansible-core 2.11.

* Adjust tests.

(cherry picked from commit 24f8be834a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-03-20 14:10:24 +01:00
patchback[bot]
0ca922248f Adding xmadsen and renxulei as Redfish maintainers (#2047) (#2056)
(cherry picked from commit a23fc67f1f)

Co-authored-by: Mike Raineri <mraineri@gmail.com>
2021-03-20 10:43:29 +01:00
patchback[bot]
ef7ade6a56 Adding purge parameter to proxmox for use with lxc delete requests (#2013) (#2050)
* added purge as optional module parameter

* Adding changelog fragment

* Adding version to documentation for purge

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

* Updating changelog

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

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

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-03-19 19:58:44 +01:00
patchback[bot]
d721283846 Fix IndexError in SetManagerNic (#2040) (#2049)
* fix IndexError in SetManagerNic

* add changelog fragment

(cherry picked from commit 0b2ebabd29)

Co-authored-by: Bill Dodd <billdodd@gmail.com>
2021-03-19 19:58:27 +01:00
patchback[bot]
af410f5572 update linode team (#2039) (#2043)
(cherry picked from commit 8225b745f3)

Co-authored-by: Charlie Kenney <Charlesc.kenney@gmail.com>
2021-03-19 07:43:52 +01:00
patchback[bot]
442dabbcc6 fix: scaleway inventory pagination (#2036) (#2042)
* fix: scaleway inventory pagination

* add changelog

* Update changelogs/fragments/2036-scaleway-inventory.yml

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

Co-authored-by: Antoine Barbare <abarbare@online.net>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit fe61be3e11)

Co-authored-by: abarbare <antoinebarbare@gmail.com>
2021-03-18 23:32:01 +01:00
patchback[bot]
bbb155409e Improvements and fixes to ModuleHelper, with (some) tests. (#2024) (#2034)
* Improvements and fixes to ModuleHelper, with (some) tests.

* added changelog fragment

* adjusted changelog frag - get_bin_path() handling is actually a bugfix

(cherry picked from commit 4fbef900e1)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-17 14:15:48 +01:00
patchback[bot]
a83556af80 allow passing the --allow-root flag to kibana_plugin module (#2014) (#2022)
* kibana_plugin module parameter force is a boolean

* allow passing the --allow-root flag to kibana_plugin module

* add changelog fragment for kibana_plugin --allow-root

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Amin Vakil <info@aminvakil.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 3162ed6795)

Co-authored-by: dacodas <dacoda.strack@gmail.com>
2021-03-15 14:05:10 +01:00
patchback[bot]
13a5e5a1ba Adding tags as module parameter to proxmox_kvm (#2000) (#2023)
* Adding tags as module parameter

* Added changelog fragment

* Correcting typo in changelog fragment

* Correcting punctuation in docs

* Including version to tags parameter description

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

* Correct tag validation and parsing logic condition

Original test was for key and not value

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

* Improving usability with default null behavior

* Removing default case and related unneccessary complexity

* Display regex in tags description as code

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

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

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-03-15 14:05:02 +01:00
patchback[bot]
466bd89bd4 Tidy up sanity checks ignore lines modules (batch 8) (#2006) (#2019)
* fixed validation-modules for plugins/modules/cloud/smartos/smartos_image_info.py

* fixed validation-modules for plugins/modules/cloud/rackspace/rax_scaling_group.py

* fixed validation-modules for plugins/modules/cloud/rackspace/rax_cdb_user.py

* fixed validation-modules for plugins/modules/cloud/rackspace/rax.py

* Tidy up sanity checks ignore lines modules (batch 8)

* added changelog fragment

* rolled back removal of parameter from rax.py

(cherry picked from commit f8859af377)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-14 11:55:07 +01:00
patchback[bot]
bd4d5fe9db More false-positives (not flagged by sanity tests yet). (#2010) (#2016)
(cherry picked from commit 49d9a257ef)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-03-13 13:48:18 +01:00
patchback[bot]
cf889faf42 Remove password requirement when creating lxc containers (#1999) (#2011)
* Removed requirement for password

* Updated documentation for password

* Adding changelog fragment

* Update changelogs/fragments/1999-proxmox-fix-issue-1955.yml

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

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

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-03-12 20:35:11 +01:00
patchback[bot]
ea313503dd Mark non-secret leaking module options with no_log=False (#2001) (#2005)
* Mark non-secret leaking module options with no_log=False.

* Add changelog fragment.

(cherry picked from commit 1ea080762b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-03-12 09:17:05 +01:00
patchback[bot]
57fa6526c4 Excluded qemu templates in pools (#1991) (#2003)
* Excluded qemu templates in pools

* Added changelog fragment

* Made check more robust

(cherry picked from commit 178209be27)

Co-authored-by: Jeffrey van Pelt <jeff@vanpelt.one>
2021-03-12 08:24:24 +01:00
patchback[bot]
ae4bee2627 jenkins_job - added validate_certs parameter, setting the PYTHONHTTPSVERIFY env var (#1977) (#1996)
* added validate_certs parameter, setting the PYTHONHTTPSVERIFY env var

* added changelog fragment

* Update plugins/modules/web_infrastructure/jenkins_job.py

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

* Update plugins/modules/web_infrastructure/jenkins_job.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-12 07:25:35 +01:00
patchback[bot]
87000ae491 Allow tags strings containing commas in proxmox inventory plug-in (#1949) (#1998)
* Included explicit parsing for proxmox guest tags and updated corresponding unit test with tags key

* Including changelog fragment for PR 1949

* Removed ellipsis from test

Proxmox only permits periods when surrounded by alphanumeric characters

* Corrected punctuation for changelog entry

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

* Allowing tags string to contain commas

* Incorporated new parsed tags fact with bugfix

* Correcting whitespace issues

* Update changelogs/fragments/1949-proxmox-inventory-tags.yml

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

* Update plugins/inventory/proxmox.py

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

* Update changelogs/fragments/1949-proxmox-inventory-tags.yml

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

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

Co-authored-by: Ajpantuso <ajpantuso@gmail.com>
2021-03-12 07:25:18 +01:00
Felix Fontein
46e221cbc6 Next expected release is 2.3.0. 2021-03-08 13:23:12 +01:00
Felix Fontein
3f2111582d Release 2.2.0. 2021-03-08 12:38:28 +01:00
patchback[bot]
bd8634e04e Tidy up sanity checks ignore lines modules (batch 7) (#1970) (#1984)
* fixed validation-modules for plugins/modules/cloud/heroku/heroku_collaborator.py

* fixed validation-modules for plugins/modules/cloud/linode/linode_v4.py

* fixed validation-modules for plugins/modules/remote_management/manageiq/manageiq_provider.py

* fixed validation-modules for plugins/modules/remote_management/manageiq/manageiq_policies.py

* fixed validation-modules for plugins/modules/remote_management/manageiq/manageiq_alert_profiles.py

* fixed validation-modules for plugins/modules/remote_management/manageiq/manageiq_tags.py

* fixed validation-modules for plugins/modules/cloud/opennebula/one_host.py

* fixed validation-modules for plugins/modules/cloud/opennebula/one_image_info.py

* fixed validation-modules for plugins/modules/cloud/opennebula/one_vm.py

* fixed validation-modules for plugins/modules/cloud/scaleway/scaleway_lb.py

* fixed validation-modules for plugins/modules/cloud/scaleway/scaleway_compute.py

* fixed validation-modules for plugins/modules/remote_management/oneview/oneview_network_set_info.py

* fixed validation-modules for plugins/modules/remote_management/oneview/oneview_ethernet_network_info.py

* fixed validation-modules for plugins/modules/remote_management/oneview/oneview_datacenter_info.py

* fixed validation-modules for plugins/modules/remote_management/oneview/oneview_enclosure_info.py

* Tidy up sanity checks ignore lines modules (batch 7)

* added changelog fragment

* Missed a couple of lines in ingnore-2.11.txt

* fixed validation-modules for plugins/modules/cloud/packet/packet_volume_attachment.py

* Adjusted ignore files and changelog for packet_volume_attachment.py

* Rolled back ignore line for linode module

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

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

* fixes from the PR

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-08 08:58:07 +01:00
patchback[bot]
1ae57fc5dd ini_file - allows adding empty string as a value (#1972) (#1981)
* Added integration test and fixed bug

* added changelog fragment

* Update changelogs/fragments/1972-ini_file-empty-str-value.yml

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

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

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-08 07:31:47 +01:00
patchback[bot]
1e5e0824d2 Extending manageiq modules with parameter resource_id (#719) (#1980)
* Extending modules with resource_id

* Added documentation

* Fixed syntax
Changed resource_type back to required true
Added description identifier

* Added changelog fragment.

* fixed syntax

* Improved changelog fragment content.

* Updated description

* Changed if statement

* Changed changelog fragement filename

* version bump

* removed duplicate type

* Apply suggestions from code review

* Update plugins/modules/remote_management/manageiq/manageiq_tags.py

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

Co-authored-by: phospi <phoffmann@spirit21.com>
2021-03-08 07:15:51 +01:00
Felix Fontein
7eaf795774 Prepare 2.2.0 release. 2021-03-08 06:59:10 +01:00
Felix Fontein
3dc25edeac Remove part of shippable config that's not needed for bot.
(cherry picked from commit ff4e4c055c)
2021-03-06 14:06:13 +01:00
patchback[bot]
a67ee6cead Added new module github_repo (#1683) (#1974)
* Added new module github_repo

* Fixed sanity errors

* Fixed sanity errors

* Unit tests for github_repo module

* Fixed import-before-documentation

* Added PyGithub dependency for unit tests

* Fixed errata

* Require Python >= 2.7

* Support for check_mode and other improvements

* Fixed import-before-documentation

* Improved module parameter requirements, check mode and docs

* Code improvements

* Fixed version tag

(cherry picked from commit 53c6b49673)

Co-authored-by: Álvaro Torres Cogollo <atorrescogollo@gmail.com>
2021-03-06 13:51:43 +01:00
patchback[bot]
9c5461dc12 Deprecation of parameters triggering the parameter-invalid sanity-check (#1927) (#1971)
* fixed validation-modules for plugins/modules/packaging/language/composer.py

* fixed validation-modules for plugins/modules/packaging/os/apt_rpm.py

* fixed validation-modules for plugins/modules/packaging/os/homebrew.py

* fixed validation-modules for plugins/modules/packaging/os/homebrew_cask.py

* fixed validation-modules for plugins/modules/packaging/os/opkg.py

* fixed validation-modules for plugins/modules/packaging/os/pacman.py

* fixed validation-modules for plugins/modules/packaging/os/slackpkg.py

* fixed validation-modules for plugins/modules/packaging/os/urpmi.py

* fixed validation-modules for plugins/modules/packaging/os/xbps.py

* fixed validation-modules for plugins/modules/source_control/github/github_deploy_key.py

* fixed validation-modules for plugins/modules/system/puppet.py

* added changelog fragment

* adjustments from PR + fixes in changelog frag

* fixed deprecation of param "show_diff" in module "puppet"

* Update changelogs/fragments/1927-removed-parameter-invalid.yml

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

* Update plugins/modules/system/puppet.py

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

* removed unnecessary ignore lines, adjustment in changelog frag

* no need to explicitly call deprecate() when param marked for removal

* Update changelogs/fragments/1927-removed-parameter-invalid.yml

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

* Adjustments in changelog fragment, per PR

* bumping deprecation to 7.0.0

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-03-05 08:41:55 +01:00
patchback[bot]
0b59a71ae7 Bugfix/manageiq inventory (#720) (#1963)
* Extending modules with resource_id

* Added documentation

* Revert previous PR

* Added filter for active vm's

* Added changelog fragment

* Update changelogs/fragments/720-cloudforms_inventory.yml

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

Co-authored-by: phospi <phoffmann@spirit21.com>
2021-03-04 08:29:21 +01:00
patchback[bot]
720de141b5 Fix: nmcli - Ensure slave-type for bond-slave (#1882) (#1961)
* Fix: nmcli - Ensure slave-type for bond-slave

Hello 🙂 

When using bond-slave type, by default command sent to nmcl is:

['/usr/bin/nmcli', 'con', 'add', 'type', 'bond-slave', 'con-name', 'enp129s0f0', 'connection.interface-name', 'enp129s0f0', 'connection.autoconnect', 'yes', 'connection.master', 'bond0']

Which is not enough, nmcli will complain that connection.slave-type is missing. This small fix solve this issue.

If this change is approved, I will add the changelog fragment.

* Fix: nmcli - Adding changelog fragment for 1882

* Update changelogs/fragments/1882-fix-nmcli-ensure-slave-type-for-bond-slave.yml

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

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

Co-authored-by: Ox <oxedions@gmail.com>
2021-03-04 08:27:40 +01:00
patchback[bot]
7ec6025690 zfs: avoid errors with creation-only properties (#1833) (#1959)
* avoid errors with creation-only properties

* add changelog fragment

* Apply suggestion to changelog fragment

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

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

Co-authored-by: sam-lunt <samuel.j.lunt@gmail.com>
2021-03-04 08:27:27 +01:00
patchback[bot]
53a5cdaed7 consul_io inventory script: fixes awx and python 3 kv_group (#620) (#1956)
* feat(env): extending configuration options by env variables

* feat(env): extending config option docs

* feat(consul_io): fix byte chain decoding for python3

* fix(pep8): E128

* changelog added

* Update changelogs/fragments/620-consul_io-env-variables-conf-based.yml

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

* Update changelogs/fragments/620-consul_io-env-variables-conf-based.yml

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

* Update changelogs/fragments/620-consul_io-env-variables-conf-based.yml

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

* fix(typo): adding dots

Co-authored-by: Davy Bondeau <davy.bondeau@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 3f882ee6a2)

Co-authored-by: atbore-phx <atbore-phx@users.noreply.github.com>
2021-03-04 08:27:19 +01:00
patchback[bot]
693efb35b3 Jenkins build module (#745) (#1957)
* Jenkins build module

A module for queuing and deleting jenkins builds.

* CI fixes

* More CI fixes.

* Even more CI fixes

* Fixing symlink

* Update plugins/modules/web_infrastructure/jenkins_build.py

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

* removed ansible meta section

* Added unit tests.

* fix tests

* more test fixes.

* Completed tests.

Mocked jenkins api calls.
Fixed some logging.

* Update plugins/modules/web_infrastructure/jenkins_build.py

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

* Update plugins/modules/web_infrastructure/jenkins_build.py

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

* Update plugins/modules/web_infrastructure/jenkins_build.py

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

* Update plugins/modules/web_infrastructure/jenkins_build.py

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

* Cleaned up default items

And removed supports check mode flag.

* setting name param required

* Update plugins/modules/web_infrastructure/jenkins_build.py

Co-authored-by: Brett Milford <brettmilford@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit ad8aa1b1e6)

Co-authored-by: Brett <19863984+brettmilford@users.noreply.github.com>
2021-03-04 08:27:10 +01:00
patchback[bot]
07cd51a33b Adding another example for tss lookup (#1945) (#1948)
* Adding another example for tss lookup

A more detailed example using self-hosted secrets server as investigated in #1943

* Update plugins/lookup/tss.py

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

* Better line breaking

* Update plugins/lookup/tss.py

Seconded!

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

* Remove newline to pass tests

* Update plugins/lookup/tss.py

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

Co-authored-by: Jim Speir <jimbo80982@gmail.com>
2021-03-02 22:23:28 +01:00
patchback[bot]
c80416164b Feat: nmcli - Add method4 and method6 (#1894) (#1944)
* Feat: nmcli - Add method4 and method6

Allows to manipulate ipv4.method and ipv6.method.

Is mandatory to manage Bond interfaces with no native vlans but only tagged vlans.

* Fix: nmcli - Add changelog fragment for 1894

* Fix: nmcli - Add choices for method4 and method6

* Update plugins/modules/net_tools/nmcli.py

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

* Update changelogs/fragments/1894-feat-nmcli-add-method4-and-method6.yml

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

* Update plugins/modules/net_tools/nmcli.py

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

* Fix: nmcli - Update documentation

* Update plugins/modules/net_tools/nmcli.py

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

* Update plugins/modules/net_tools/nmcli.py

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

* Fix: nmcli - Simplify code

* Update plugins/modules/net_tools/nmcli.py

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

* Fix: nmcli - Update ip6 documentation

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

Co-authored-by: Ox <oxedions@gmail.com>
2021-03-02 13:09:38 +01:00
Felix Fontein
a61bc5ab34 Also mention plugins/modules added in 1.1.0, 1.2.0 and 1.3.0 in 2.0.0 changelog, as it claims to contain all changes since 1.0.0. (#1934) 2021-03-01 13:02:08 +01:00
patchback[bot]
8ac8fa0aa9 Improved ModuleHelper.run_command() (#1867) (#1938)
* Improved run_command signature and behaviour

- extra_params has been removed from the signature
- params now can be either str or dict (containing the param value)

* Reverted the removal of the method parameter, and added changelog fragment

* Update changelogs/fragments/1867-modhelper-cmdmixin-dict-params.yml

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

* Update plugins/module_utils/module_helper.py

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

* adjustement per PR

* Update plugins/module_utils/module_helper.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-28 15:34:46 +01:00
patchback[bot]
b76994ee6e grove: message -> message_content (#1929) (#1936)
* grove: message -> message_content

* Remove no longer needed ignore.txt lines.

(cherry picked from commit bec43041a9)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-27 23:11:44 +01:00
patchback[bot]
746bd3ea5d Actually use option. (#1928) (#1937)
(cherry picked from commit b4c136125e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-27 23:11:37 +01:00
patchback[bot]
68baf56ea6 Add version_sort filter to properly sort list of versions (#1916) (#1932)
* Add version_sort filter to properly sort list of versions

* Fix all comments from Felix

- add changelog fragment
- fix test by removing runme.sh/yml and renaming to filter_version_sort
- use fully qualified name of filter in test case

* Remove wrong plugin.test changelog fragment

Ups...

* Properly name the file version_sort.py

* Update changelogs/fragments/1916-add-version-sort-filter.yml

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

Co-authored-by: Eric L <ewl+git@lavar.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 4a8d6cf7cc)

Co-authored-by: Eric L <ericzolf@users.noreply.github.com>
2021-02-27 19:54:39 +01:00
patchback[bot]
87377dd23f Proxmox inventory: Add some sanitization to url parameter (#1914) (#1931)
* Added rstrip to the URL field to prevent issues when users add a trailing / in the config of this module

* Added changelog fragment

* Sorry Mr. Linter, I have removed the empty line :-)

* Fixed punctuation

* Fixed punctuation

(cherry picked from commit 20bd065e77)

Co-authored-by: Jeffrey van Pelt <jeff@vanpelt.one>
2021-02-27 17:23:02 +01:00
patchback[bot]
29f028e33b bugfix: xfs_quota feedback on projects not initialized has changed (#1596) (#1923)
* bugfix: xfs_quota feedback on projects not initialized has changed

* changelog fragment

* Update changelogs/fragments/1596-xfs_quota-feedback_on_projects_not_initialized_has_changed.yml

Thanks for this, felixfontein

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

* xfs_quota is not necessarily in PATH

* pep8 and formatting

* Test was wrong. It needs to be changed

* formatting

* pep8 and formatting

* xfs_quota is not necessarily in PATH

* pep8 and formatting

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

Co-authored-by: William Leemans <bushvin@users.noreply.github.com>
2021-02-27 09:57:58 +01:00
patchback[bot]
196e8fe4e3 yum_versionlock: do lock/unlock concurrently (#1912) (#1920)
* Change all packages at once in yum_versionlock module

* Re-enable tests

* Convert package list to packages string

* Fix module

* Change variable name to make it appropriate

* Fix module check_mode

* Revert "Fix module" and apply felixfontein suggestion

This reverts commit 5936da3198.

* Rename package to packages

* Only change packages which are needed

* Ignore if list is empty

* Add changelog

(cherry picked from commit 811b609b05)

Co-authored-by: Amin Vakil <info@aminvakil.com>
2021-02-26 23:37:30 +01:00
Felix Fontein
83c6d18bc0 Improve meta/runtime.yml deprecation messages. (#1918) (#1919)
(cherry picked from commit 5447910a0b)
2021-02-26 23:05:56 +01:00
patchback[bot]
1314b0d7b2 Tidy up sanity checks (2021/Batch 3 - who's counting) (#1885) (#1910)
* fixed validation-modules for plugins/modules/packaging/language/pip_package_info.py

* fixed validation-modules for plugins/modules/packaging/language/maven_artifact.py

* fixed validation-modules for plugins/modules/packaging/language/bundler.py

* fixed validation-modules for plugins/modules/notification/pushbullet.py

* fixed validation-modules for plugins/modules/monitoring/sensu/sensu_handler.py

* fixed validation-modules for plugins/modules/monitoring/sensu/sensu_check.py

* fixed validation-modules for plugins/modules/monitoring/sensu/sensu_client.py

* fixed validation-modules for plugins/modules/monitoring/icinga2_host.py

* fixed validation-modules for plugins/modules/monitoring/datadog/datadog_monitor.py

* fixed validation-modules for plugins/modules/monitoring/datadog/datadog_event.py

* fixed validation-modules for plugins/modules/clustering/znode.py

* fixed validation-modules for plugins/modules/clustering/etcd3.py

* fixed validation-modules for plugins/modules/clustering/consul/consul_session.py

* fixed validation-modules for plugins/modules/clustering/consul/consul_kv.py

* fixed validation-modules for plugins/modules/clustering/consul/consul.py

* fixed validation-modules for plugins/modules/cloud/profitbricks/profitbricks.py

* fixed validation-modules for plugins/modules/cloud/profitbricks/profitbricks_volume.py

* fixed validation-modules for plugins/modules/cloud/packet/packet_sshkey.py

* fixed validation-modules for plugins/modules/cloud/oneandone/oneandone_server.py

* fixed validation-modules for plugins/modules/cloud/oneandone/oneandone_private_network.py

* fixed validation-modules for plugins/modules/cloud/oneandone/oneandone_monitoring_policy.py

* fixed validation-modules for plugins/modules/cloud/oneandone/oneandone_load_balancer.py

* fixed validation-modules for plugins/modules/cloud/oneandone/oneandone_firewall_policy.py

* fixed validation-modules for plugins/modules/cloud/webfaction/webfaction_app.py

* fixed validation-modules for plugins/modules/cloud/webfaction/webfaction_db.py

* fixed validation-modules for plugins/modules/cloud/webfaction/webfaction_domain.py

* fixed validation-modules for plugins/modules/cloud/webfaction/webfaction_mailbox.py

* fixed validation-modules for plugins/modules/cloud/webfaction/webfaction_site.py

* fixed validation-modules for plugins/modules/remote_management/lxca/lxca_cmms.py

* fixed validation-modules for plugins/modules/remote_management/lxca/lxca_nodes.py

* missed one "elements" in sensu_handler

* Tidy up batch of sanity checks ignore lines

* missed lines in ignore-2.9.txt

* fixed validation-modules for plugins/modules/clustering/consul/consul_acl.py

* Update ignore-2.9.txt

Removed consul_acl.py from ignore-2.9.txt

* Apply suggestions from code review

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

* Update plugins/modules/notification/pushbullet.py

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

* Update plugins/modules/cloud/oneandone/oneandone_monitoring_policy.py

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

* added changelog fragment

* Update plugins/modules/cloud/oneandone/oneandone_monitoring_policy.py

* Update changelogs/fragments/1885-sanity-check-fixes-batch3.yml

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

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 76d9fe4ec6)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-26 11:57:51 +01:00
patchback[bot]
be94a014c8 Disable way too slow yum_versionlock tests. (#1907) (#1909)
(cherry picked from commit afe9d0fdb3)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-26 11:37:15 +01:00
patchback[bot]
039c3da7dc BOTMETA.yml: Remove vfauth as etcd3 maintainer (#1900) (#1904)
(cherry picked from commit 71706031c7)

Co-authored-by: Victor Fauth <victor@fauth.pro>
2021-02-25 15:52:30 +01:00
patchback[bot]
2480250f1b cobbler_sync cobbler_system fix TLS check when validate_certs (#1880) (#1902)
Ref: https://www.python.org/dev/peps/pep-0476/
Issue #1878
add changelog fragment

Co-authored-by: Nicolas Marcq <nicolas.marcq@hpe.com>
(cherry picked from commit 36dea9ab97)

Co-authored-by: Nicolas Marcq <nico.marcq@gmail.com>
2021-02-25 15:17:44 +01:00
patchback[bot]
860f0e12c0 proxmox_kvm: trivial patch for github issue #1875 (#1895) (#1899)
* proxmox_kvm: trivial patch for Github issue #1875

* proxmox_kvm: add a changelog fragment

* Update changelogs/fragments/1895-proxmox-kvm-fix-issue-1875.yml

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

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

Co-authored-by: Tristan Le Guern <tristan.leguern-presta@deveryware.com>
2021-02-25 13:07:40 +01:00
patchback[bot]
2f56fd7b2a Tidy up sanity checks ignore lines for source_control/* modules (#1893) (#1896)
* fixed validation-modules for plugins/modules/source_control/git*

* Tidy up sanity checks ignore lines for source_control/* modules

* removed unnecessary ignore lines from 2.9 and 2.11

(cherry picked from commit cf5e9bf44c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-25 10:05:46 +01:00
patchback[bot]
084879632a fixed Python 3 keys() usage (#1861) (#1891)
* fixed python3 keys()

* added changelog fragment

* Update plugins/modules/cloud/spotinst/spotinst_aws_elastigroup.py

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

* Update plugins/cache/redis.py

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

* rolledback redis.py per PR

* Update plugins/modules/monitoring/sensu/sensu_check.py

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

* removed unnecessary ignore lines

* adding memcached and one case in redis is indeed necessary

* Update changelogs/fragments/1861-python3-keys.yml

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

* Update changelogs/fragments/1861-python3-keys.yml

* Update changelogs/fragments/1861-python3-keys.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-24 19:36:37 +01:00
patchback[bot]
4eef56b7b3 Remove unneeded fields (with typos). (#1887) (#1888)
(cherry picked from commit e353390e6c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-23 23:48:34 +01:00
patchback[bot]
13929acf02 Since gitlab_project_members is a copy if gitlab_group_members with small modifications, it needs to contain the copyright notices of that module as well as the authors. (#1874) (#1884)
(cherry picked from commit 0b9893959f)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-23 10:55:40 +01:00
patchback[bot]
070bcf80c4 New module proxmox_storage_info (#1844) (#1879)
* proxmox_storage_info: new module

Simple info module dedicated to the retrieval of information about the
storages available on a Proxmox VE cluster.

* Update plugins/modules/cloud/misc/proxmox_storage_info.py

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

* Update plugins/modules/cloud/misc/proxmox_storage_info.py

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

* Update plugins/modules/cloud/misc/proxmox_storage_info.py

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

* Update plugins/modules/cloud/misc/proxmox_storage_info.py

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

* Update plugins/modules/cloud/misc/proxmox_storage_info.py

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

Co-authored-by: Tristan Le Guern <tristan.leguern-presta@deveryware.com>
2021-02-22 18:36:23 +01:00
patchback[bot]
0cf2a5ad05 deploy_helper: fix a bug when not defining release on state=clean (#1859) (#1877)
* Fix a bug when not defining release on state=clean

* Add changelog fragment

(cherry picked from commit abfbe2a48d)

Co-authored-by: Ramon de la Fuente <ramon@future500.nl>
2021-02-22 09:29:36 +01:00
patchback[bot]
76a64ea733 Improve infoblox inventory script dependencies. (#1871) (#1873)
(cherry picked from commit c0f3a63e18)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-21 22:30:51 +01:00
patchback[bot]
115eab2cfa added gitlab_project_members (#1829) (#1870)
* added gitlab_project_members

* fix code style

* added some arg to doc

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

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

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

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

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

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

* integration test for gitlab_project_members module

Co-authored-by: Sergey Mikhaltsov <s.mikhaltsov@leadgid.ru>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 389b004879)

Co-authored-by: Sergey Mikhaltsov <metanovii@gmail.com>
2021-02-21 18:19:10 +01:00
patchback[bot]
dbba813e23 Fixed imc_rest session logout (#1743) (#1869)
* Fixed imc_rest session logout

* Update plugins/modules/remote_management/imc/imc_rest.py

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

* Update changelogs/fragments/1735-imc-sessions.yml

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

* Trying with try/finally

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-21 18:16:39 +01:00
patchback[bot]
7daf78962b Disable flatpack_remote test due to expired key. (#1862) (#1865)
(cherry picked from commit 57f56b02d8)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-20 10:51:34 +01:00
patchback[bot]
cf9fff5238 proxmox_kvm: add integration tests (#1849) (#1854)
(cherry picked from commit 682674dd5f)

Co-authored-by: Tristan Le Guern <tristan.leguern-presta@deveryware.com>
2021-02-18 12:15:24 +01:00
Felix Fontein
d8d68babe4 Revert "Revert new feature so that we can make a bugfix release. Will re-revert this afterwards."
This reverts commit afba9a11af.
2021-02-17 22:59:37 +01:00
Felix Fontein
3f46cdc588 Release 2.1.1. 2021-02-17 21:49:42 +01:00
Felix Fontein
ea530784b8 Adjust version. 2021-02-17 21:46:40 +01:00
patchback[bot]
dc2fa05b1f proxmox_kvm: fix undefined local variable status (#1847) (#1851)
* proxmox_kvm: undefined local variable status

* proxmox_kvm: Add a changelog fragment

* Update changelogs/fragments/1847-proxmox-kvm-fix-status.yml

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

* proxmox_kvm: fix the RETURN document

* proxmox_kvm: fix name variable when state=current

The variable name is not always defined as the module can be called with
just a vmid.

Before:

> "msg": "VM None with vmid = 118 is stopped"

After:

> "msg": "VM test-instance with vmid = 118 is stopped"

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

Co-authored-by: Tristan Le Guern <tristan.leguern-presta@deveryware.com>
2021-02-17 21:44:02 +01:00
Felix Fontein
b2e51272ad Prepare 2.1.0 release. 2021-02-17 21:33:57 +01:00
Felix Fontein
afba9a11af Revert new feature so that we can make a bugfix release. Will re-revert this afterwards.
Revert "runit - deprecate param dist (#1838) (#1845)"

This reverts commit c3ac479ae2.
2021-02-17 21:32:16 +01:00
patchback[bot]
c3ac479ae2 runit - deprecate param dist (#1838) (#1845)
* Deprecate param dist

* added changelog fragment

* added changelog fragment

* Removed ignore lines for runit

(cherry picked from commit e0dd4b240f)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-17 08:01:13 +01:00
Felix Fontein
7e367244f7 Next expected release is 2.2.0. 2021-02-16 13:36:12 +01:00
Felix Fontein
331d2c7651 Release 2.1.0. 2021-02-16 12:13:27 +01:00
patchback[bot]
b35a262378 StatsD Module (#1793) (#1842)
* Pushing my WIP

* Update DOCUMENTATION

* Update EXAMPLES

* More friendly name

* Finish up the counter and gauge logic

* Cleanup DOCUMENTATION and add metric_type

* Apply autopep8

* Fixup the exits

* Stubbing out unit tests

* Whitespace

* Whitespace

* Removing unused modules

* Remove unused modules

* Might have have a prefix

* Rearrange imported modules

* Cleanup the if/elif blob

* Require python >= 2.7

* Update DOCUMENTATION

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

* Update DOCUMENTATION

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

* Add import guarding on statsd

* Add missing future import

* Include missing_required_lib

* Fixing sanity tests

* Fixing delta default and choices

* Formatting

* Close tcp connection

* Refactoring and unit tests

* Fix pep8 sanity tests

* Putting requirements.txt back to main

* Apply suggestions from code review

Co-authored-by: Mark Mercado <mmercado@digitalocean.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 6165438689)

Co-authored-by: Mark Mercado <mamercad@gmail.com>
2021-02-16 12:09:58 +01:00
patchback[bot]
7d400663b6 Previously LXD profiles were overwritten, now these are merged. (#1813) (#1836)
* added ``merge_profile`` parameter to merge configurations from the play to an existing profile

* add fragment

* cosmetic changes

Co-authored-by: Frank Dornheim <“dornheim@posteo.de@users.noreply.github.com”>
(cherry picked from commit 6dd4cd0eb7)

Co-authored-by: Frank Dornheim <524257+conloos@users.noreply.github.com>
2021-02-16 10:58:34 +01:00
patchback[bot]
0d0884b069 Tidy up validations + bug fixes + deprecations (#1830) (#1841)
* fixed validation-modules for plugins/modules/database/misc/elasticsearch_plugin.py

* fixed validation-modules for plugins/modules/database/misc/kibana_plugin.py

* fixed validation-modules for plugins/modules/database/misc/riak.py

* fixed validation-modules for plugins/modules/database/vertica/vertica_info.py

* fixed validation-modules for plugins/modules/database/vertica/vertica_role.py

* fixed validation-modules for plugins/modules/database/vertica/vertica_schema.py

* fixed validation-modules for plugins/modules/database/vertica/vertica_user.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_domain.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_host_ports.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_host.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_pool.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_vol.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_vol_map.py

* fixed validation-modules for plugins/modules/storage/ibm/ibm_sa_host_ports.py

* fixed validation-modules for plugins/modules/system/runit.py

* fixed validation-modules for plugins/modules/source_control/bzr.py

* fixed validation-modules for plugins/modules/source_control/hg.py

* fixed validation-modules for plugins/modules/storage/emc/emc_vnx_sg_member.py

* fixed validation-modules for plugins/modules/identity/opendj/opendj_backendprop.py

* fixed validation-modules for plugins/modules/files/iso_extract.py

* fixed validation-modules for plugins/modules/monitoring/logstash_plugin.py

* fixed validation-modules for plugins/modules/database/aerospike/aerospike_migrations.py

* Tidy up a number of sanity checks for some modules

* added changelog fragment

* Some parameters in vertica_* had their aliases documented as the name, and sometimes vice-versa as well

* Adjustments per PR

* Rolled back sanity ignores for runit

* Update changelogs/fragments/1830-valmod_docmissingtype_batch1.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-16 09:10:13 +00:00
patchback[bot]
dd400e8c21 Tidy up all pylint:blacklisted-name ignore lines (#1819) (#1839)
* fixed validation-modules for plugins/callback/hipchat.py

* fixed validation-modules for plugins/connection/lxc.py

* fixed validation-modules for plugins/modules/cloud/lxc/lxc_container.py

* fixed validation-modules for plugins/modules/monitoring/statusio_maintenance.py

* fixed validation-modules for plugins/modules/system/alternatives.py

* fixed validation-modules for plugins/modules/system/beadm.py

* fixed validation-modules for plugins/modules/system/cronvar.py

* fixed validation-modules for plugins/modules/system/dconf.py

* fixed validation-modules for plugins/modules/system/interfaces_file.py

* fixed validation-modules for plugins/modules/system/java_cert.py

* fixed validation-modules for plugins/modules/system/lvg.py

* fixed validation-modules for plugins/modules/system/lvol.py

* fixed validation-modules for plugins/modules/system/parted.py

* fixed validation-modules for plugins/modules/system/timezone.py

* fixed validation-modules for plugins/modules/web_infrastructure/rundeck_acl_policy.py

* Tidy up all pylint:blacklisted-name sanity checks ignore lines

* Missed one in statusio_maintenace.py

* fixed validation-modules for plugins/modules/system/filesystem.py

* Missed one in gconftool2.py

* Missed one in alternatives.py

* Using dummies now

* fixed indentation

* Made all the changes about replacing _ with dummy

* Rollback bug fixed

* Rollback bug fixed, part II

* added changelog fragment

* Improved changelog frag message per PR

(cherry picked from commit 03b7b39424)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-16 08:46:20 +01:00
patchback[bot]
a60f9bc78b dnsimple: Add support for CAA records (#1814) (#1835)
(cherry picked from commit 03fd6bd008)

Co-authored-by: Craig Roberts <github@craig.craig0990.co.uk>
2021-02-16 07:55:35 +01:00
Felix Fontein
47714ecf79 Add release summary for 1.2.0. 2021-02-16 07:48:13 +01:00
patchback[bot]
d15ed4135b Tidy up validate-modules:parameter-list-no-elements (batch 1) (#1795) (#1834)
* fixed validation-modules for plugins/modules/storage/netapp/na_ontap_gather_facts.py

* fixed validation-modules for plugins/modules/source_control/gitlab/gitlab_runner.py

* fixed validation-modules for plugins/modules/packaging/os/redhat_subscription.py

* fixed validation-modules for plugins/modules/notification/twilio.py

* fixed validation-modules for plugins/modules/notification/slack.py

* fixed validation-modules for plugins/modules/notification/sendgrid.py

* fixed validation-modules for plugins/modules/notification/rocketchat.py

* fixed validation-modules for plugins/modules/notification/office_365_connector_card.py

* fixed validation-modules for plugins/modules/notification/nexmo.py

* fixed validation-modules for plugins/modules/notification/mail.py

* fixed validation-modules for plugins/modules/net_tools/omapi_host.py

* fixed validation-modules for plugins/modules/net_tools/nsupdate.py

* fixed validation-modules for plugins/modules/net_tools/dnsimple.py

* fixed validation-modules for plugins/modules/monitoring/pagerduty.py

* fixed validation-modules for plugins/modules/monitoring/librato_annotation.py

* fixed validation-modules for plugins/modules/identity/onepassword_info.py

* fixed validation-modules for plugins/modules/identity/keycloak/keycloak_client.py

* fixed validation-modules for plugins/modules/files/xml.py

* fixed validation-modules for plugins/modules/cloud/softlayer/sl_vm.py

* fixed validation-modules for plugins/modules/cloud/smartos/vmadm.py

* fixed validation-modules for plugins/modules/cloud/pubnub/pubnub_blocks.py

* fixed validation-modules for plugins/modules/cloud/packet/packet_device.py

* fixed validation-modules for plugins/modules/cloud/lxd/lxd_container.py

* fixed validation-modules for plugins/module_utils/oracle/oci_utils.py

* fixed validation-modules for plugins/doc_fragments/oracle_creatable_resource.py

* Tidy up validate-modules:parameter-list-no-elements for some modules

* fixed validation-modules for plugins/modules/monitoring/statusio_maintenance.py

* Fixed pending issues from CI validation

* Fixed xml module elements for add_children & set_children

* added changelog fragment

* typo

* fix wording in changelog frag

(cherry picked from commit f33323ca89)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-16 07:38:50 +01:00
patchback[bot]
bd61228e40 proxmox_kvm: 500 error args parameter (#1783) (#1832)
* don't add args if set to 'no_defaults'

* never add force even if false, will require archive parameter other which is not implemented

* remove trailing whitespace

* add changelog fragment

* Update changelogs/fragments/1783-proxmox-kvm-fix-args-500-error.yaml

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

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

Co-authored-by: almdudler777 <43605831+almdudler777@users.noreply.github.com>
2021-02-16 07:10:40 +01:00
patchback[bot]
26d7c28b33 ease limitation for nios_host_record DNS Bypass (#1788) (#1826)
* ease limitation for nios_host_record DNS Bypass, the bypass should be allowed when configure_dns is disabled and view is set other than default

* add changelog fragment

Co-authored-by: Nils <ext-nils.haglund@elisa.fi>
(cherry picked from commit 8fae693d9c)

Co-authored-by: shieni <shieni@users.noreply.github.com>
2021-02-15 09:10:18 +01:00
patchback[bot]
2e533daffa Fix undeclared result for nomad_job_info module (#1721) (#1823)
* Fix unassigned variable

* Create 1721-fix-nomad_job_info-no-jobs-failure.yml

* refactor usage of variables in nomad_job_info

* Update changelogs/fragments/1721-fix-nomad_job_info-no-jobs-failure.yml

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

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

Co-authored-by: Víctor Suárez Fernández <15276132+vicsufer@users.noreply.github.com>
2021-02-15 09:04:44 +01:00
patchback[bot]
6c50119eab Added VMID to all returns (#1715) (#1824)
* Added VMID to all returns

Also added in the docs promised return of MAC and devices when state ==
current.

Fixes: #1641

* Revert devices and mac as get_vminfo works differently then I expected

* Added status output to a few more calls

* Update RETURNS docs

* Remove vmid where it is not available

* Added changelog fragment

* Update changelogs/fragments/1715-proxmox_kvm-add-vmid-to-returns.yml

You're right, this message is way better then mine.. :-)

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

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

Co-authored-by: Jeffrey van Pelt <jeff@vanpelt.one>
2021-02-15 08:57:38 +01:00
patchback[bot]
bc3435b993 Tidy up validation for storage/zfs modules (#1766) (#1821)
* fixed validation-modules for plugins/modules/storage/zfs/zfs.py

* fixed validation-modules for plugins/modules/storage/zfs/zfs_delegate_admin.py

* fixed validation-modules for plugins/modules/storage/zfs/zfs_facts.py

* fixed validation-modules for plugins/modules/storage/zfs/zpool_facts.py

* Tidy up validate-modules ignores for storage/zfs modules

* removed ignore lines in 2.11 files as well

* added changelog fragment per PR

* Update changelogs/fragments/1766-zfs-fixed-sanity.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-15 07:27:23 +00:00
patchback[bot]
370f5d8082 Implemented fix pointed in issue (#1760) (#1818)
(cherry picked from commit 41bc7816f3)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-14 16:05:59 +01:00
patchback[bot]
e77c5413c9 Adjusted django_manage integration test files to reduce ignore lines in sanity tests (#1805) (#1810)
(cherry picked from commit e247300523)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-13 12:49:36 +01:00
patchback[bot]
800ee1bae0 Tidy up validate-modules ignores for cloud/centurylink modules (#1771) (#1811)
* fixed validation-modules for plugins/modules/cloud/centurylink/clc_alert_policy.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_blueprint_package.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_firewall_policy.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_loadbalancer.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_modify_server.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_publicip.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_server_snapshot.py

* fixed validation-modules for plugins/modules/cloud/centurylink/clc_server.py

* Tidy up validate-modules ignores for cloud/centurylink modules

* added changelog fragment per PR

(cherry picked from commit 865acdd4cf)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-13 12:35:18 +01:00
patchback[bot]
8de8d21062 Make selective callback work with ansible-core 2.11. (#1807) (#1809)
(cherry picked from commit 367c3c43ff)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-13 12:24:10 +01:00
patchback[bot]
81e71b5034 Improved parameter handling on proxmox modules (#1765) (#1801)
* Improved parameter handling on proxmox modules

* removed unused imports

* rollback change in plugins/modules/cloud/misc/proxmox_user_info.py

* added changelog fragment

* Update changelogs/fragments/1765-proxmox-params.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-12 17:08:14 +01:00
patchback[bot]
44ce63ed85 Change type str -> path in argspec. (#1741) (#1800)
(cherry picked from commit f12df1d21b)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-12 08:23:40 +01:00
patchback[bot]
a3c9c688b9 Removed parameter-list-no-elements validation errors from redfish modules (#1761) (#1799)
* Removed parameter-list-no-elements validation errors from redfish modules

* added changelog fragment per PR

* Update changelogs/fragments/1761-redfish-tidy-up-validation.yml

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-12 07:14:07 +01:00
patchback[bot]
a332ed4429 Prevented the expansion of parameters in run_command() (#1794) (#1796)
(cherry picked from commit 436bbb0077)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-12 06:38:37 +01:00
patchback[bot]
91571f8bff Update CI (#1782) (#1787)
* Update targets for CI for devel branch; move some targets to stable-2.10.

* Skipping test on RHEL 8.3 (it is already skipped on RHEL 8.2).

* Linting.

* Shut 2.9/2.10 pylint complaints up.

(cherry picked from commit e9551df5ed)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-11 11:10:42 +01:00
patchback[bot]
43856eaa6f Fix typo in aerospike_migration module. (#1740) (#1785)
(cherry picked from commit 9a6031ab4e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-11 07:31:05 +01:00
patchback[bot]
ae87b5479a only set param features when variable is not empty (#1763) (#1781)
* only set param features when variable is not empty

* Apply suggestions from code review

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

Co-authored-by: Topper Harly <topperharly@gmx.net>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 562ff7efb7)

Co-authored-by: topperharly <topperharly@users.noreply.github.com>
2021-02-10 22:32:01 +01:00
patchback[bot]
42cd462780 redfish module_utils: case insesitive search for situations where the hostname/FQDN on iLO is in caps (#1744) (#1780)
* case insesitive search for situations where the hostname/FQDN on iLO is in caps

* handle explicit and implicit nic_addr variable, added changelog fragment

* changelog linter fix

* changelog typo fix

Co-authored-by: Łukasz Kurdziel <Lukasz.Kurdziel@GAINCapital.com>
(cherry picked from commit 93e0aa7557)

Co-authored-by: lukurde <47138492+lukurde@users.noreply.github.com>
2021-02-10 20:37:49 +01:00
patchback[bot]
d871378574 xfconf: feature flag to disable facts and deprecation warning (#1747) (#1778)
* Added feature flag to disable facts and its associated deprecatoin warning

* added changelog fragment

* Update plugins/modules/system/xfconf.py

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

* Update plugins/modules/system/xfconf.py

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

* Update plugins/modules/system/xfconf.py

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

* Fixed deprecation message

* Fixed changelog frag

* Update changelogs/fragments/1475-xfconf-facts.yml

* Update plugins/modules/system/xfconf.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-10 20:37:31 +01:00
patchback[bot]
983b292399 timezone: add gentoo and alpine linux support (#1722) (#1779)
* add alpine linux as NosystemdTimezone

* syntax error fix and more self variables, so it works now...

* use timezone name instead of timezone path for setup-timezone command

* alpine linux zoneinfo links to /etc/zoneinfo instead of /usr/share/zoneinfo, so correct re.search() pattern

* add changelog fragment

* add gentoo linux support

* Update 1722_timezone.yml

* refactor code

(cherry picked from commit 9aef0ed17e)

Co-authored-by: Anatoly Pugachev <matorola@gmail.com>
2021-02-10 20:37:15 +01:00
patchback[bot]
6831aa5501 document what filesystem types are supported by 'resizefs' option (#1753) (#1775)
* document what filesystem types are supported by 'resizefs' option

* add changelog fragment

* remove info about lvol documentation changes in changelog fragment

(cherry picked from commit d1e54d2fd1)

Co-authored-by: quidame <quidame@poivron.org>
2021-02-10 13:09:33 +01:00
patchback[bot]
2d8a94a459 azure-pipelines: update container version (#1770) (#1773)
(cherry picked from commit e898e52d1b)

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
2021-02-10 10:12:56 +01:00
patchback[bot]
f721e76fdc Tidy up validate-modules ignores for remote_management/ipmi modules (#1767) (#1769)
* fixed validation-modules for plugins/modules/remote_management/ipmi/ipmi_boot.py

* fixed validation-modules for plugins/modules/remote_management/ipmi/ipmi_power.py

* Tidy up validate-modules ignores for remote_management/ipmi modules

(cherry picked from commit 89ffb04dff)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-02-10 08:24:33 +01:00
Felix Fontein
3eadb9d637 Revert "Revert new features since the 2.0.0 release so we can release 2.0.1 from this branch."
This reverts commit 1d90e91528.
2021-02-09 15:42:39 +01:00
Felix Fontein
033582b696 Next expected release is 2.1.0. 2021-02-09 15:42:39 +01:00
Felix Fontein
974997594f Release 2.0.1. 2021-02-09 13:34:53 +01:00
Felix Fontein
fa8ce6dea8 Add 2.0.1 relesae summary. 2021-02-09 13:32:06 +01:00
Felix Fontein
1d90e91528 Revert new features since the 2.0.0 release so we can release 2.0.1 from this branch.
Revert "datadog_monitor: Add missing monitor types query alert, trace-analytics alert, rum alert (#1723) (#1733)"
Revert "homebrew_tap: Add support for brew search path (#1708) (#1709)"

This reverts commits f613983cb4 and 646ca74810.
2021-02-09 13:30:39 +01:00
patchback[bot]
a90e2c8002 Various fixes for updating existing gitlab users (#1724) (#1757)
* fixes various issues related to updating an ...

... existing gitlab user, in detail:

  - fixes updating admin status not working
  - fixes user passwords not updated
  - fixes confirmation skipping param ignored for user updates
  - added tests for code changes

* fixing sanity issues

* fixing sanity issues 02

* fixing sanity issues 03

* fixing sanity issues 04

* fixing unit test failures

* fixing unit test failures 02

* add changelog fragment

* fixing unit test failures 03

* forgot to add changelog fragment

* fix changelog sanity issues

* fix changelog sanity issues 02

* incorporate review suggestions

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

Co-authored-by: morco <thegreatwiper@web.de>
2021-02-09 12:02:03 +01:00
patchback[bot]
c506375f2a Fix CI (#1752) (#1754)
* Limit cryptography to < 3.4 for Python < 3.6.

* Work around old pip versions.

* Use constraints file when installing stormssh.

* Work around old pip in RHEL8.2, CentOS 8, Ubuntu 18.04, and OpenSuSE 15

(cherry picked from commit 909ac92fe2)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-09 10:28:39 +01:00
patchback[bot]
4def9439bd Fix a bunch of potential security issues (secret leaking) (#1736) (#1751)
* Fix a bunch of potential security issues (secret leaking).

* oneandone_server was already ok.

* Add more parameters for pagerduty_alert.

* Add more no_log=True.

(cherry picked from commit 29bd5a9486)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-08 17:04:38 +01:00
patchback[bot]
023654473b Make sure mercurial is also installed on OpenSuSE. (#1734) (#1738)
(cherry picked from commit 701a89eb1c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-05 08:29:28 +01:00
patchback[bot]
a216f15dd9 parted: fix regex for version match and partition size output (#1695) (#1732)
* Fix 2 regex in parted related to parted version string and to parsing partition size output.

* Added changelog fragment.

* Updated changelog as per recommendation.

* Fix the regex matching the parted version. The space character at the end of the string may or may not be always present

* provided sample version output and corrected regex to match

* add/correct changelog fragment

* split parted_version function to allow creating a test unit

* test unit for parted version info

* ansible-test sanity fixes

* review fix

* Update changelogs/fragments/1695-parted-updatedregex.yaml

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

* comment fixes

* better function name

* Update plugins/modules/system/parted.py

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

* comment fixes

Co-authored-by: Claude Robitaille <claude@cbcr.me>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 43da5b88db)

Co-authored-by: Anatoly Pugachev <matorola@gmail.com>
2021-02-05 07:51:43 +01:00
patchback[bot]
f613983cb4 datadog_monitor: Add missing monitor types query alert, trace-analytics alert, rum alert (#1723) (#1733)
* Add missing Datadog monitor types
This commit adds the following monitor types: query alert, trace-analytics alert, rum alert

* changelog PR1723 datadog_monitor types

* datadog_monitor 1723 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 f509f2c896)

Co-authored-by: Rick Sherman <rick@shermdog.com>
2021-02-05 06:51:27 +00:00
patchback[bot]
c22199794d Add no_log to some module arguments (#1725) (#1730)
* Add no_log to some module arguments

This will prevent potentially sensitive information from being printed to
the console.

See: CVE-2021-20191

* Update changelogs/fragments/CVE-2021-20191_no_log.yml

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

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

Co-authored-by: David Moreau Simard <dmsimard@redhat.com>
2021-02-04 21:54:11 +01:00
patchback[bot]
24b1d92e84 module filesystem: partially fix idempotency issue #1457 (resizefs) (#1478) (#1720)
* Use 'xfs_info' to query fs size, that doesn't always require the device be
  mounted. Although still query mountpoint first for backward compatibility.
* Do not fail whith fstype=xfs and resizefs=yes if filesystem already fills
  its underlying device.
* Include xfs in the tasks that test idempotency of resizefs option
* Add changelogs/fragments/1478-filesystem-fix-1457-resizefs-idempotency.yml

(cherry picked from commit aa95d8a5b7)

Co-authored-by: quidame <quidame@poivron.org>
2021-02-03 10:42:29 +01:00
patchback[bot]
4bc44e4062 sensu-silence: fix json parsing of sensu API response (#1703) (#1718)
* sensu-silence: fix json parsing of sensu API response

* use ansible helper function to decode bytestream

* add changelog fragment

* Update changelogs, link to PR

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

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

Co-authored-by: Stefan Walluhn <stefan.walluhn@aboutsource.net>
2021-02-03 07:52:59 +01:00
patchback[bot]
06fd6d8742 Fedora 30 and 31 are EOL and will eventually be removed from devel. (#1705) (#1711)
(cherry picked from commit 6af3c96d8e)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-02-01 18:30:45 +01:00
Felix Fontein
dd0ae4a003 Announce DellEMC migration. (#1706) 2021-02-01 18:29:56 +01:00
patchback[bot]
646ca74810 homebrew_tap: Add support for brew search path (#1708) (#1709)
* homebrew_tap: Add support for brew search path

User can specify search path for brew executable.

Fixes: #1702

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

* Change version

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

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

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-02-01 11:32:50 +01:00
patchback[bot]
d60c107818 BOTMETA.yml: add logstash plugin maintainer (#1700) (#1701)
Co-authored-by: Andrew Klychkov <andrew.klychkov@gmail.com>
(cherry picked from commit 9c648c8e3a)

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
2021-01-29 11:01:21 +01:00
patchback[bot]
ef2d14f24e Add Name and/or Id properties to resource inventory output (#1691) (#1698)
* add Name and/or Id properties to resource inventory output

* add changelog fragment

(cherry picked from commit 00f5f7dfe7)

Co-authored-by: Bill Dodd <billdodd@gmail.com>
2021-01-29 07:40:22 +01:00
Felix Fontein
b3cde9b8a4 Next expected release is 2.1.0. 2021-01-28 15:01:39 +01:00
Felix Fontein
dc4222df0d Fix links. 2021-01-28 13:52:13 +01:00
Felix Fontein
b9a89d6d0f Release 2.0.0. 2021-01-28 13:43:42 +01:00
Felix Fontein
f48913d91b Add release summary. 2021-01-28 13:42:22 +01:00
396 changed files with 17873 additions and 15433 deletions

50
.github/BOTMETA.yml vendored
View File

@@ -1,5 +1,7 @@
automerge: true
files:
plugins/:
supershipit: quidame Ajpantuso
changelogs/fragments/:
support: community
$actions:
@@ -58,8 +60,6 @@ files:
maintainers: giner
$filters/from_csv.py:
maintainers: Ajpantuso
$filters/hashids:
maintainers: Ajpantuso
$filters/jc.py:
maintainers: kellyjonbrazil
$filters/list.py:
@@ -83,8 +83,6 @@ files:
maintainers: $team_linode
labels: cloud linode
keywords: linode dynamic inventory script
$inventories/lxd.py:
maintainers: conloos
$inventories/proxmox.py:
maintainers: $team_virt ilijamt
$inventories/scaleway.py:
@@ -115,8 +113,6 @@ files:
$lookups/nios:
maintainers: $team_networking sganesh-infoblox
labels: infoblox networking
$lookups/random_string.py:
maintainers: Akasurde
$module_utils/:
labels: module_utils
$module_utils/gitlab.py:
@@ -139,9 +135,6 @@ files:
$module_utils/memset.py:
maintainers: glitchcrab
labels: cloud memset
$module_utils/mh/:
maintainers: russoz
labels: module_helper
$module_utils/module_helper.py:
maintainers: russoz
labels: module_helper
@@ -157,6 +150,7 @@ files:
$module_utils/redfish_utils.py:
maintainers: $team_redfish
labels: redfish_utils
$module_utils/remote_management/dellemc/: rajeevarakkal
$module_utils/remote_management/lxca/common.py: navalkp prabhosa
$module_utils/scaleway.py:
maintainers: $team_scaleway
@@ -200,6 +194,8 @@ files:
maintainers: glitchcrab
$modules/cloud/misc/cloud_init_data_facts.py:
maintainers: resmo
$modules/cloud/misc/helm.py:
maintainers: flaper87
$modules/cloud/misc/proxmox.py:
maintainers: $team_virt UnderGreen
labels: proxmox virt
@@ -344,14 +340,10 @@ files:
$modules/database/mssql/mssql_db.py:
maintainers: vedit Jmainguy kenichi-ogawa-1988
labels: mssql_db
$modules/database/saphana/hana_query.py:
maintainers: rainerleber
$modules/database/vertica/:
maintainers: dareko
$modules/files/archive.py:
maintainers: bendoh
$modules/files/filesize.py:
maintainers: quidame
$modules/files/ini_file.py:
maintainers: jpmens noseka1
$modules/files/iso_extract.py:
@@ -365,6 +357,8 @@ files:
maintainers: dagwieers magnus919 tbielawa cmprescott sm4rk0
labels: m:xml xml
ignore: magnus919
$modules/identity/onepassword_facts.py:
maintainers: Rylon
$modules/identity/ipa/:
maintainers: $team_ipa
$modules/identity/ipa/ipa_pwpolicy.py:
@@ -377,8 +371,6 @@ files:
maintainers: $team_keycloak
$modules/identity/keycloak/keycloak_group.py:
maintainers: adamgoossens
$modules/identity/keycloak/keycloak_realm.py:
maintainers: kris2kris
$modules/identity/onepassword_info.py:
maintainers: Rylon
$modules/identity/opendj/opendj_backendprop.py:
@@ -471,6 +463,8 @@ files:
maintainers: akostyuk
$modules/net_tools/ipwcli_dns.py:
maintainers: cwollinger
$modules/net_tools/ldap/ldap_attr.py:
maintainers: jtyr
$modules/net_tools/ldap/ldap_attrs.py:
maintainers: drybjed jtyr noles
$modules/net_tools/ldap/ldap_entry.py:
@@ -569,7 +563,7 @@ files:
maintainers: dmtrs
ignore: resmo
$modules/packaging/language/cpanm.py:
maintainers: fcuny russoz
maintainers: fcuny
$modules/packaging/language/easy_install.py:
maintainers: mattupstate
$modules/packaging/language/gem.py:
@@ -649,9 +643,6 @@ files:
maintainers: elasticdog indrajitr tchernomax
labels: pacman
ignore: elasticdog
$modules/packaging/os/pacman_key.py:
maintainers: grawlinson
labels: pacman
$modules/packaging/os/pkgin.py:
maintainers: $team_solaris L2G jasperla szinck martinm82
labels: pkgin solaris
@@ -722,6 +713,12 @@ files:
ignore: matze
$modules/remote_management/cobbler/:
maintainers: dagwieers
$modules/remote_management/dellemc/:
maintainers: rajeevarakkal
$modules/remote_management/dellemc/idrac_server_config_profile.py:
maintainers: jagadeeshnv
$modules/remote_management/dellemc/ome_device_info.py:
maintainers: Sajna-Shetty
$modules/remote_management/hpilo/:
maintainers: haad
ignore: dagwieers
@@ -741,6 +738,8 @@ files:
maintainers: evertmulder
$modules/remote_management/manageiq/manageiq_tenant.py:
maintainers: evertmulder
$modules/remote_management/oneview/oneview_datacenter_facts.py:
maintainers: aalexmonteiro madhav-bharadwaj ricardogpsf soodpr
$modules/remote_management/oneview/:
maintainers: adriane-cardozo fgbulsoni tmiotto
$modules/remote_management/oneview/oneview_datacenter_info.py:
@@ -789,6 +788,12 @@ files:
maintainers: yeukhon
$modules/storage/emc/emc_vnx_sg_member.py:
maintainers: remixtj
$modules/storage/glusterfs/:
maintainers: devyanikota
$modules/storage/glusterfs/gluster_peer.py:
maintainers: sac
$modules/storage/glusterfs/gluster_volume.py:
maintainers: rosmo
$modules/storage/hpe3par/ss_3par_cpg.py:
maintainers: farhan7500 gautamphegde
$modules/storage/ibm/:
@@ -810,6 +815,9 @@ files:
maintainers: johanwiren
$modules/storage/zfs/zfs_delegate_admin.py:
maintainers: natefoo
$modules/system/python_requirements_facts.py:
maintainers: willthames
ignore: ryansb
$modules/system/aix:
maintainers: $team_aix
labels: aix
@@ -942,6 +950,10 @@ files:
labels: xfconf
$modules/system/xfs_quota.py:
maintainers: bushvin
$modules/web_infrastructure/jenkins_job_facts.py:
maintainers: stpierre
$modules/web_infrastructure/nginx_status_facts.py:
maintainers: resmo
$modules/web_infrastructure/apache2_mod_proxy.py:
maintainers: oboukili
$modules/web_infrastructure/apache2_module.py:

View File

@@ -1,135 +0,0 @@
---
name: Bug report
description: Create a report to help us improve
body:
- type: markdown
attributes:
value: |
Verify first that your issue is not [already reported on GitHub][issue search].
Also test if the latest release and devel branch are affected too.
*Complete **all** sections as described, this form is processed automatically.*
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
- type: textarea
attributes:
label: Summary
description: Explain the problem briefly below.
placeholder: >-
When I try to do X with the collection from the main branch on GitHub, Y
breaks in a way Z under the env E. Here are all the details I know
about this problem...
validations:
required: true
- type: dropdown
attributes:
label: Issue Type
# FIXME: Once GitHub allows defining the default choice, update this
options:
- Bug Report
validations:
required: true
- type: textarea
attributes:
# For smaller collections we could use a multi-select and hardcode the list
# May generate this list via GitHub action and walking files under https://github.com/ansible-collections/community.general/tree/main/plugins
# Select from list, filter as you type (`mysql` would only show the 3 mysql components)
# OR freeform - doesn't seem to be supported in adaptivecards
label: Component Name
description: >-
Write the short name of the module, plugin, task or feature below,
*use your best guess if unsure*.
placeholder: dnf, apt, yum, pip, user etc.
validations:
required: true
- type: textarea
attributes:
label: Ansible Version
description: >-
Paste verbatim output from `ansible --version` between
tripple backticks.
value: |
```console (paste below)
$ ansible --version
```
validations:
required: true
- type: textarea
attributes:
label: Configuration
description: >-
If this issue has an example piece of YAML that can help to reproduce this problem, please provide it.
This can be a piece of YAML from, e.g., an automation, script, scene or configuration.
Paste verbatim output from `ansible-config dump --only-changed` between quotes
value: |
```console (paste below)
$ ansible-config dump --only-changed
```
- type: textarea
attributes:
label: OS / Environment
description: >-
Provide all relevant information below, e.g. target OS versions,
network device firmware, etc.
placeholder: RHEL 8, CentOS Stream etc.
validations:
required: false
- type: textarea
attributes:
label: Steps to Reproduce
description: |
Describe exactly how to reproduce the problem, using a minimal test-case. It would *really* help us understand your problem if you could also pased any playbooks, configs and commands you used.
**HINT:** You can paste https://gist.github.com links for larger files.
value: |
<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
```
validations:
required: true
- type: textarea
attributes:
label: Expected Results
description: >-
Describe what you expected to happen when running the steps above.
placeholder: >-
I expected X to happen because I assumed Y.
that it did not.
validations:
required: true
- type: textarea
attributes:
label: Actual Results
description: |
Describe what actually happened. If possible run with extra verbosity (`-vvvv`).
Paste verbatim command output between quotes.
value: |
```console (paste below)
```
- type: checkboxes
attributes:
label: Code of Conduct
description: |
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
options:
- label: I agree to follow the Ansible Code of Conduct
required: true
...

View File

@@ -1,27 +0,0 @@
---
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: false # default: true
contact_links:
- name: Security bug report
url: https://docs.ansible.com/ansible-core/devel/community/reporting_bugs_and_features.html?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
about: |
Please learn how to report security vulnerabilities here.
For all security related bugs, email security@ansible.com
instead of using this issue tracker and you will receive
a prompt response.
For more information, see
https://docs.ansible.com/ansible/latest/community/reporting_bugs_and_features.html
- name: Ansible Code of Conduct
url: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
about: Be nice to other members of the community.
- name: Talks to the community
url: https://docs.ansible.com/ansible/latest/community/communication.html?utm_medium=github&utm_source=issue_template_chooser#mailing-list-information
about: Please ask and answer usage questions here
- name: Working groups
url: https://github.com/ansible/community/wiki
about: Interested in improving a specific area? Become a part of a working group!
- name: For Enterprise
url: https://www.ansible.com/products/engine?utm_medium=github&utm_source=issue_template_chooser_ansible_collections
about: Red Hat offers support for the Ansible Automation Platform

View File

@@ -1,111 +0,0 @@
---
name: Documentation Report
description: Ask us about docs
# NOTE: issue body is enabled to allow screenshots
body:
- type: markdown
attributes:
value: |
Verify first that your issue is not [already reported on GitHub][issue search].
Also test if the latest release and devel branch are affected too.
*Complete **all** sections as described, this form is processed automatically.*
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
- type: textarea
attributes:
label: Summary
description: |
Explain the problem briefly below, add suggestions to wording or structure.
**HINT:** Did you know the documentation has an `Edit on GitHub` link on every page?
placeholder: >-
I was reading the Collection documentation of version X and I'm having
problems understanding Y. It would be very helpful if that got
rephrased as Z.
validations:
required: true
- type: dropdown
attributes:
label: Issue Type
# FIXME: Once GitHub allows defining the default choice, update this
options:
- Documentation Report
validations:
required: true
- type: input
attributes:
label: Component Name
description: >-
Write the short name of the rst file, module, plugin, task or
feature below, *use your best guess if unsure*.
placeholder: mysql_user
validations:
required: true
- type: textarea
attributes:
label: Ansible Version
description: >-
Paste verbatim output from `ansible --version` between
tripple backticks.
value: |
```console (paste below)
$ ansible --version
```
validations:
required: false
- type: textarea
attributes:
label: Configuration
description: >-
Paste verbatim output from `ansible-config dump --only-changed` between quotes.
value: |
```console (paste below)
$ ansible-config dump --only-changed
```
validations:
required: false
- type: textarea
attributes:
label: OS / Environment
description: >-
Provide all relevant information below, e.g. OS version,
browser, etc.
placeholder: Fedora 33, Firefox etc.
validations:
required: false
- type: textarea
attributes:
label: Additional Information
description: |
Describe how this improves the documentation, e.g. before/after situation or screenshots.
**Tip:** It's not possible to upload the screenshot via this field directly but you can use the last textarea in this form to attach them.
**HINT:** You can paste https://gist.github.com links for larger files.
placeholder: >-
When the improvement is applied, it makes it more straightforward
to understand X.
validations:
required: false
- type: checkboxes
attributes:
label: Code of Conduct
description: |
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
options:
- label: I agree to follow the Ansible Code of Conduct
required: true
...

View File

@@ -1,69 +0,0 @@
---
name: Feature request
description: Suggest an idea for this project
body:
- type: markdown
attributes:
value: |
Verify first that your issue is not [already reported on GitHub][issue search].
Also test if the latest release and devel branch are affected too.
*Complete **all** sections as described, this form is processed automatically.*
[issue search]: https://github.com/ansible-collections/community.general/search?q=is%3Aissue&type=issues
- type: textarea
attributes:
label: Summary
description: Describe the new feature/improvement briefly below.
placeholder: >-
I am trying to do X with the collection from the main branch on GitHub and
I think that implementing a feature Y would be very helpful for me and
every other user of ansible-core because of Z.
validations:
required: true
- type: dropdown
attributes:
label: Issue Type
# FIXME: Once GitHub allows defining the default choice, update this
options:
- Feature Idea
validations:
required: true
- type: input
attributes:
label: Component Name
description: >-
Write the short name of the module, plugin, task or feature below,
*use your best guess if unsure*.
placeholder: dnf, apt, yum, pip, user etc.
validations:
required: true
- type: textarea
attributes:
label: Additional Information
description: |
Describe how the feature would be used, why it is needed and what it would solve.
**HINT:** You can paste https://gist.github.com links for larger files.
value: |
<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
```
validations:
required: false
- type: checkboxes
attributes:
label: Code of Conduct
description: |
Read the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html?utm_medium=github&utm_source=issue_form--ansible-collections) first.
options:
- label: I agree to follow the Ansible Code of Conduct
required: true
...

File diff suppressed because it is too large Load Diff

View File

@@ -29,4 +29,8 @@ Also, consider taking up a valuable, reviewed, but abandoned pull request which
You can also read [our Quick-start development guide](https://github.com/ansible/community-docs/blob/main/create_pr_quick_start_guide.rst).
## Test pull requests
If you want to test a PR locally, refer to [our testing guide](https://github.com/ansible/community-docs/blob/main/test_pr_locally_guide.rst) for instructions on how do it quickly.
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.

View File

@@ -1,14 +1,20 @@
# Community General Collection
[![Build Status](https://dev.azure.com/ansible/community.general/_apis/build/status/CI?branchName=stable-3)](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
[![Build Status](https://dev.azure.com/ansible/community.general/_apis/build/status/CI?branchName=stable-2)](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
[![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.general)](https://codecov.io/gh/ansible-collections/community.general)
This repo contains the `community.general` Ansible Collection. The collection includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
This repository contains the `community.general` Ansible Collection. The collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
You can find [documentation for this collection on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
Please note that this collection does **not** support Windows targets. Only connection plugins included in this collection might support Windows targets, and will explicitly mention that in their documentation if they do so.
## Code of Conduct
We follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our interactions within this project.
If you encounter abusive behavior violating the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html), please refer to the [policy violations](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html#policy-violations) section of the Code of Conduct for information on how to raise a complaint.
## Tested with Ansible
Tested with the current Ansible 2.9, ansible-base 2.10 and ansible-core 2.11 releases and the current development version of ansible-core. Ansible versions before 2.9.10 are not supported.
@@ -23,7 +29,9 @@ Please check the included content on the [Ansible Galaxy page for this collectio
## Using this collection
Before using the General community collection, you need to install the collection with the `ansible-galaxy` CLI:
This collection is shipped with the Ansible package. So if you have it installed, no more action is required.
If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/community/general) manually with the `ansible-galaxy` command-line tool:
ansible-galaxy collection install community.general
@@ -34,19 +42,29 @@ collections:
- name: community.general
```
Note that if you install the collection manually, it will not be upgraded automatically when you upgrade the Ansible package. To upgrade the collection to the latest available version, run the following command:
```bash
ansible-galaxy collection install community.general --upgrade
```
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/community/general):
```bash
ansible-galaxy collection install community.general:==X.Y.Z
```
See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
## Contributing to this collection
If you want to develop new content for this collection or improve what is already here, the easiest way to work on the collection is to clone it into one of the configured [`COLLECTIONS_PATH`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#collections-paths), and work on it there.
The content of this collection is made by good people like you, a community of individuals collaborating on making the world better through developing automation software.
For example, if you are working in the `~/dev` directory:
All types of contributions are very welcome.
```
cd ~/dev
git clone git@github.com:ansible-collections/community.general.git collections/ansible_collections/community/general
export COLLECTIONS_PATH=$(pwd)/collections:$COLLECTIONS_PATH
```
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/main/CONTRIBUTING.md)!
The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
@@ -58,16 +76,15 @@ See [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collectio
### Communication
We have a dedicated Working Group for Ansible development.
We announce important development changes and releases through Ansible's [The Bullhorn newsletter](https://eepurl.com/gZmiEP). If you are a collection developer, be sure you are subscribed.
You can find other people interested on the following [Libera.chat](https://libera.chat/) IRC channels -
- `#ansible` - For general use questions and support.
- `#ansible-devel` - For discussions on developer topics and code related to features or bugs in ansible-core.
- `#ansible-community` - For discussions on community topics and community meetings, and for general development questions for community collections.
Join us in the `#ansible` (general use questions and support), `#ansible-community` (community and collection development questions), and other [IRC channels](https://docs.ansible.com/ansible/devel/community/communication.html#irc-channels) on [Libera.chat](https://libera.chat).
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
For more information about communities, meetings and agendas see [Community Wiki](https://github.com/ansible/community/wiki/Community).
For more information about [communication](https://docs.ansible.com/ansible/latest/community/communication.html)
For more information about communication, refer to the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
### Publishing New Version
@@ -80,7 +97,7 @@ Basic instructions without release branches:
## Release notes
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-3/CHANGELOG.rst).
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-2/CHANGELOG.rst).
## Roadmap

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
---
sections:
- title: Guides
toctree:
- filter_guide

View File

@@ -1,753 +0,0 @@
.. _ansible_collections.community.general.docsite.filter_guide:
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.

View File

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

View File

@@ -1,5 +1,31 @@
---
requires_ansible: '>=2.9.10'
action_groups:
ovirt:
- ovirt_affinity_label_facts
- ovirt_api_facts
- ovirt_cluster_facts
- ovirt_datacenter_facts
- ovirt_disk_facts
- ovirt_event_facts
- ovirt_external_provider_facts
- ovirt_group_facts
- ovirt_host_facts
- ovirt_host_storage_facts
- ovirt_network_facts
- ovirt_nic_facts
- ovirt_permission_facts
- ovirt_quota_facts
- ovirt_scheduling_policy_facts
- ovirt_snapshot_facts
- ovirt_storage_domain_facts
- ovirt_storage_template_facts
- ovirt_storage_vm_facts
- ovirt_tag_facts
- ovirt_template_facts
- ovirt_user_facts
- ovirt_vm_facts
- ovirt_vmpool_facts
plugin_routing:
connection:
docker:
@@ -11,24 +37,9 @@ plugin_routing:
redirect: community.google.gcp_storage_file
hashi_vault:
redirect: community.hashi_vault.hashi_vault
nios:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios lookup plugin has been deprecated.
Please use infoblox.nios_modules.nios_lookup instead.
nios_next_ip:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_next_ip lookup plugin has been deprecated.
Please use infoblox.nios_modules.nios_next_ip instead.
nios_next_network:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_next_network lookup plugin has been
deprecated. Please use infoblox.nios_modules.nios_next_network instead.
modules:
ali_instance_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.ali_instance_info instead.
docker_compose:
@@ -130,13 +141,11 @@ plugin_routing:
gcp_forwarding_rule:
tombstone:
removal_version: 2.0.0
warning_text: Use google.cloud.gcp_compute_forwarding_rule or google.cloud.gcp_compute_global_forwarding_rule
instead.
warning_text: Use google.cloud.gcp_compute_forwarding_rule or google.cloud.gcp_compute_global_forwarding_rule instead.
gcp_healthcheck:
tombstone:
removal_version: 2.0.0
warning_text: Use google.cloud.gcp_compute_health_check, google.cloud.gcp_compute_http_health_check
or google.cloud.gcp_compute_https_health_check instead.
warning_text: Use google.cloud.gcp_compute_health_check, google.cloud.gcp_compute_http_health_check or google.cloud.gcp_compute_https_health_check instead.
gcp_target_proxy:
tombstone:
removal_version: 2.0.0
@@ -147,22 +156,37 @@ plugin_routing:
warning_text: Use google.cloud.gcp_compute_url_map instead.
gcpubsub:
redirect: community.google.gcpubsub
gcpubsub_facts:
tombstone:
removal_version: 3.0.0
warning_text: Use community.google.gcpubsub_info instead.
gcpubsub_info:
redirect: community.google.gcpubsub_info
gcpubsub_facts:
redirect: community.google.gcpubsub_info
deprecation:
removal_version: 3.0.0
warning_text: Use community.google.gcpubsub_info instead.
gcspanner:
tombstone:
removal_version: 2.0.0
warning_text: Use google.cloud.gcp_spanner_database and/or google.cloud.gcp_spanner_instance
instead.
warning_text: Use google.cloud.gcp_spanner_database and/or google.cloud.gcp_spanner_instance instead.
github_hooks:
tombstone:
removal_version: 2.0.0
warning_text: Use community.general.github_webhook and community.general.github_webhook_info
instead.
warning_text: Use community.general.github_webhook and community.general.github_webhook_info instead.
gluster_heal_info:
deprecation:
removal_version: 3.0.0
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_heal_info instead.
gluster_peer:
deprecation:
removal_version: 3.0.0
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_peer instead.
gluster_volume:
deprecation:
removal_version: 3.0.0
warning_text: The gluster modules have migrated to the gluster.gluster collection. Use gluster.gluster.gluster_volume instead.
helm:
deprecation:
removal_version: 3.0.0
warning_text: The helm module in community.general has been deprecated. Use community.kubernetes.helm instead.
hetzner_failover_ip:
redirect: community.hrobot.failover_ip
hetzner_failover_ip_info:
@@ -172,19 +196,15 @@ plugin_routing:
hetzner_firewall_info:
redirect: community.hrobot.firewall_info
hpilo_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.hpilo_info instead.
idrac_firmware:
redirect: dellemc.openmanage.idrac_firmware
idrac_redfish_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.idrac_redfish_info instead.
idrac_server_config_profile:
redirect: dellemc.openmanage.idrac_server_config_profile
jenkins_job_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.jenkins_job_info instead.
katello:
@@ -204,25 +224,23 @@ plugin_routing:
kubevirt_vm:
redirect: community.kubevirt.kubevirt_vm
ldap_attr:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.ldap_attrs instead.
logicmonitor:
tombstone:
removal_version: 1.0.0
warning_text: The logicmonitor_facts module is no longer maintained and the
API used has been disabled in 2017.
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
logicmonitor_facts:
tombstone:
removal_version: 1.0.0
warning_text: The logicmonitor_facts module is no longer maintained and the
API used has been disabled in 2017.
warning_text: The logicmonitor_facts module is no longer maintained and the API used has been disabled in 2017.
memset_memstore_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.memset_memstore_info instead.
memset_server_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.memset_server_info instead.
na_cdot_aggregate:
@@ -258,242 +276,159 @@ plugin_routing:
removal_version: 2.0.0
warning_text: Use netapp.ontap.na_ontap_volume instead.
na_ontap_gather_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use netapp.ontap.na_ontap_info instead.
nginx_status_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.nginx_status_info instead.
nios_a_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_a_record module has been deprecated.
Please use infoblox.nios_modules.nios_a_record instead.
nios_aaaa_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_aaaa_record module has been deprecated.
Please use infoblox.nios_modules.nios_aaaa_record instead.
nios_cname_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_cname_record module has been deprecated.
Please use infoblox.nios_modules.nios_cname_record instead.
nios_dns_view:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_dns_view module has been deprecated.
Please use infoblox.nios_modules.nios_dns_view instead.
nios_fixed_address:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_fixed_address module has been deprecated.
Please use infoblox.nios_modules.nios_fixed_address instead.
nios_host_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_host_record module has been deprecated.
Please use infoblox.nios_modules.nios_host_record instead.
nios_member:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_member module has been deprecated.
Please use infoblox.nios_modules.nios_member instead.
nios_mx_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_mx_record module has been deprecated.
Please use infoblox.nios_modules.nios_mx_record instead.
nios_naptr_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_naptr_record module has been deprecated.
Please use infoblox.nios_modules.nios_naptr_record instead.
nios_network:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_network module has been deprecated.
Please use infoblox.nios_modules.nios_network instead.
nios_network_view:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_network_view module has been deprecated.
Please use infoblox.nios_modules.nios_network_view instead.
nios_nsgroup:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_nsgroup module has been deprecated.
Please use infoblox.nios_modules.nios_nsgroup instead.
nios_ptr_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_ptr_record module has been deprecated.
Please use infoblox.nios_modules.nios_ptr_record instead.
nios_srv_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_srv_record module has been deprecated.
Please use infoblox.nios_modules.nios_srv_record instead.
nios_txt_record:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_txt_record module has been deprecated.
Please use infoblox.nios_modules.nios_txt_record instead.
nios_zone:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios_zone module has been deprecated.
Please use infoblox.nios_modules.nios_zone instead.
ome_device_info:
redirect: dellemc.openmanage.ome_device_info
one_image_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.one_image_info instead.
onepassword_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.onepassword_info instead.
oneview_datacenter_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_datacenter_info instead.
oneview_enclosure_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_enclosure_info instead.
oneview_ethernet_network_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_ethernet_network_info instead.
oneview_fc_network_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_fc_network_info instead.
oneview_fcoe_network_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_fcoe_network_info instead.
oneview_logical_interconnect_group_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_logical_interconnect_group_info
instead.
warning_text: Use community.general.oneview_logical_interconnect_group_info instead.
oneview_network_set_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_network_set_info instead.
oneview_san_manager_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.oneview_san_manager_info instead.
online_server_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.online_server_info instead.
online_user_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.online_user_info instead.
ovirt:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_vm instead.
ovirt_affinity_label_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_affinity_label_info instead.
ovirt_api_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_api_info instead.
ovirt_cluster_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_cluster_info instead.
ovirt_datacenter_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_datacenter_info instead.
ovirt_disk_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_disk_info instead.
ovirt_event_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_event_info instead.
ovirt_external_provider_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_external_provider_info instead.
ovirt_group_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_group_info instead.
ovirt_host_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_host_info instead.
ovirt_host_storage_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_host_storage_info instead.
ovirt_network_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_network_info instead.
ovirt_nic_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_nic_info instead.
ovirt_permission_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_permission_info instead.
ovirt_quota_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_quota_info instead.
ovirt_scheduling_policy_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_scheduling_policy_info instead.
ovirt_snapshot_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_snapshot_info instead.
ovirt_storage_domain_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_storage_domain_info instead.
ovirt_storage_template_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_storage_template_info instead.
ovirt_storage_vm_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_storage_vm_info instead.
ovirt_tag_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_tag_info instead.
ovirt_template_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_template_info instead.
ovirt_user_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_user_info instead.
ovirt_vm_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_vm_info instead.
ovirt_vmpool_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use ovirt.ovirt.ovirt_vmpool_info instead.
postgresql_copy:
@@ -536,52 +471,52 @@ plugin_routing:
redirect: community.postgresql.postgresql_table
postgresql_tablespace:
redirect: community.postgresql.postgresql_tablespace
postgresql_user:
redirect: community.postgresql.postgresql_user
postgresql_user_obj_stat_info:
redirect: community.postgresql.postgresql_user_obj_stat_info
postgresql_user:
redirect: community.postgresql.postgresql_user
purefa_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use purestorage.flasharray.purefa_info instead.
purefb_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use purestorage.flashblade.purefb_info instead.
python_requirements_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.python_requirements_info instead.
redfish_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.redfish_info instead.
scaleway_image_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_image_info instead.
scaleway_ip_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_ip_info instead.
scaleway_organization_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_organization_info instead.
scaleway_security_group_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_security_group_info instead.
scaleway_server_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_server_info instead.
scaleway_snapshot_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_snapshot_info instead.
scaleway_volume_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.scaleway_volume_info instead.
sf_account_manager:
@@ -605,15 +540,15 @@ plugin_routing:
removal_version: 2.0.0
warning_text: Use netapp.elementsw.na_elementsw_volume instead.
smartos_image_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.smartos_image_info instead.
vertica_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.vertica_info instead.
xenserver_guest_facts:
tombstone:
deprecation:
removal_version: 3.0.0
warning_text: Use community.general.xenserver_guest_info instead.
doc_fragments:
@@ -627,11 +562,6 @@ plugin_routing:
redirect: community.kubevirt.kubevirt_common_options
kubevirt_vm_options:
redirect: community.kubevirt.kubevirt_vm_options
nios:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.nios document fragment has been deprecated.
Please use infoblox.nios_modules.nios instead.
postgresql:
redirect: community.postgresql.postgresql
module_utils:
@@ -649,33 +579,21 @@ plugin_routing:
redirect: community.hrobot.robot
kubevirt:
redirect: community.kubevirt.kubevirt
net_tools.nios.api:
deprecation:
removal_version: 5.0.0
warning_text: The community.general.net_tools.nios.api module_utils has been
deprecated. Please use infoblox.nios_modules.api instead.
postgresql:
redirect: community.postgresql.postgresql
remote_management.dellemc.dellemc_idrac:
redirect: dellemc.openmanage.dellemc_idrac
remote_management.dellemc.ome:
redirect: dellemc.openmanage.ome
callback:
actionable:
tombstone:
removal_version: 2.0.0
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
= no' and 'display_ok_hosts = no' options.
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts = no' and 'display_ok_hosts = no' options.
full_skip:
tombstone:
removal_version: 2.0.0
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
= no' option.
warning_text: Use the 'default' callback plugin with 'display_skipped_hosts = no' option.
stderr:
tombstone:
removal_version: 2.0.0
warning_text: Use the 'default' callback plugin with 'display_failed_stderr
= yes' option.
warning_text: Use the 'default' callback plugin with 'display_failed_stderr = yes' option.
inventory:
docker_machine:
redirect: community.docker.docker_machine

View File

@@ -62,7 +62,7 @@ display = Display()
class Connection(ConnectionBase):
""" Local chroot based connections """
''' Local chroot based connections '''
transport = 'community.general.chroot'
has_pipelining = True
@@ -95,7 +95,7 @@ class Connection(ConnectionBase):
raise AnsibleError("%s does not look like a chrootable dir (/bin/sh missing)" % self.chroot)
def _connect(self):
""" connect to the chroot """
''' connect to the chroot '''
if os.path.isabs(self.get_option('chroot_exe')):
self.chroot_cmd = self.get_option('chroot_exe')
else:
@@ -110,17 +110,17 @@ class Connection(ConnectionBase):
self._connected = True
def _buffered_exec_command(self, cmd, stdin=subprocess.PIPE):
""" run a command on the chroot. This is only needed for implementing
''' run a command on the chroot. This is only needed for implementing
put_file() get_file() so that we don't have to read the whole file
into memory.
compared to exec_command() it looses some niceties like being able to
return the process's exit code immediately.
"""
'''
executable = self.get_option('executable')
local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
display.vvv("EXEC %s" % local_cmd, host=self.chroot)
display.vvv("EXEC %s" % (local_cmd), host=self.chroot)
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
p = subprocess.Popen(local_cmd, shell=False, stdin=stdin,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -128,17 +128,16 @@ class Connection(ConnectionBase):
return p
def exec_command(self, cmd, in_data=None, sudoable=False):
""" run a command on the chroot """
''' run a command on the chroot '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
p = self._buffered_exec_command(cmd)
stdout, stderr = p.communicate(in_data)
return p.returncode, stdout, stderr
return (p.returncode, stdout, stderr)
@staticmethod
def _prefix_login_path(remote_path):
""" Make sure that we put files into a standard path
def _prefix_login_path(self, remote_path):
''' Make sure that we put files into a standard path
If a path is relative, then we need to choose where to put it.
ssh chooses $HOME but we aren't guaranteed that a home dir will
@@ -146,13 +145,13 @@ class Connection(ConnectionBase):
This also happens to be the former default.
Can revisit using $HOME instead if it's a problem
"""
'''
if not remote_path.startswith(os.path.sep):
remote_path = os.path.join(os.path.sep, remote_path)
return os.path.normpath(remote_path)
def put_file(self, in_path, out_path):
""" transfer a file from local to chroot """
''' transfer a file from local to chroot '''
super(Connection, self).put_file(in_path, out_path)
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot)
@@ -178,7 +177,7 @@ class Connection(ConnectionBase):
raise AnsibleError("file or module does not exist at: %s" % in_path)
def fetch_file(self, in_path, out_path):
""" fetch a file from chroot to local """
''' fetch a file from chroot to local '''
super(Connection, self).fetch_file(in_path, out_path)
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot)
@@ -202,6 +201,6 @@ class Connection(ConnectionBase):
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
def close(self):
""" terminate the connection; nothing to do here """
''' terminate the connection; nothing to do here '''
super(Connection, self).close()
self._connected = False

View File

@@ -44,7 +44,7 @@ display = Display()
class Connection(ConnectionBase):
""" Func-based connections """
''' Func-based connections '''
has_pipelining = False
@@ -53,7 +53,6 @@ class Connection(ConnectionBase):
self.host = host
# port is unused, this go on func
self.port = port
self.client = None
def connect(self, port=None):
if not HAVE_FUNC:
@@ -63,32 +62,31 @@ class Connection(ConnectionBase):
return self
def exec_command(self, cmd, become_user=None, sudoable=False, executable='/bin/sh', in_data=None):
""" run a command on the remote minion """
''' run a command on the remote minion '''
if in_data:
raise AnsibleError("Internal Error: this module does not support optimized module pipelining")
# totally ignores privlege escalation
display.vvv("EXEC %s" % cmd, host=self.host)
display.vvv("EXEC %s" % (cmd), host=self.host)
p = self.client.command.run(cmd)[self.host]
return p[0], p[1], p[2]
return (p[0], p[1], p[2])
@staticmethod
def _normalize_path(path, prefix):
def _normalize_path(self, path, prefix):
if not path.startswith(os.path.sep):
path = os.path.join(os.path.sep, path)
normpath = os.path.normpath(path)
return os.path.join(prefix, normpath[1:])
def put_file(self, in_path, out_path):
""" transfer a file from local to remote """
''' transfer a file from local to remote '''
out_path = self._normalize_path(out_path, '/')
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
self.client.local.copyfile.send(in_path, out_path)
def fetch_file(self, in_path, out_path):
""" fetch a file from remote to local """
''' fetch a file from remote to local '''
in_path = self._normalize_path(in_path, '/')
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host)
@@ -101,5 +99,5 @@ class Connection(ConnectionBase):
shutil.rmtree(tmpdir)
def close(self):
""" terminate the connection; nothing to do here """
''' terminate the connection; nothing to do here '''
pass

View File

@@ -40,7 +40,7 @@ display = Display()
class Connection(Jail):
""" Local iocage based connections """
''' Local iocage based connections '''
transport = 'community.general.iocage'

View File

@@ -35,6 +35,7 @@ import os
import os.path
import subprocess
import traceback
import ansible.constants as C
from ansible.errors import AnsibleError
from ansible.module_utils.six.moves import shlex_quote
@@ -46,7 +47,7 @@ display = Display()
class Connection(ConnectionBase):
""" Local BSD Jail based connections """
''' Local BSD Jail based connections '''
modified_jailname_key = 'conn_jail_name'
@@ -89,20 +90,20 @@ class Connection(ConnectionBase):
return to_text(stdout, errors='surrogate_or_strict').split()
def _connect(self):
""" connect to the jail; nothing to do here """
''' connect to the jail; nothing to do here '''
super(Connection, self)._connect()
if not self._connected:
display.vvv(u"ESTABLISH JAIL CONNECTION FOR USER: {0}".format(self._play_context.remote_user), host=self.jail)
self._connected = True
def _buffered_exec_command(self, cmd, stdin=subprocess.PIPE):
""" run a command on the jail. This is only needed for implementing
''' run a command on the jail. This is only needed for implementing
put_file() get_file() so that we don't have to read the whole file
into memory.
compared to exec_command() it looses some niceties like being able to
return the process's exit code immediately.
"""
'''
local_cmd = [self.jexec_cmd]
set_env = ''
@@ -122,17 +123,16 @@ class Connection(ConnectionBase):
return p
def exec_command(self, cmd, in_data=None, sudoable=False):
""" run a command on the jail """
''' run a command on the jail '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
p = self._buffered_exec_command(cmd)
stdout, stderr = p.communicate(in_data)
return p.returncode, stdout, stderr
return (p.returncode, stdout, stderr)
@staticmethod
def _prefix_login_path(remote_path):
""" Make sure that we put files into a standard path
def _prefix_login_path(self, remote_path):
''' Make sure that we put files into a standard path
If a path is relative, then we need to choose where to put it.
ssh chooses $HOME but we aren't guaranteed that a home dir will
@@ -140,13 +140,13 @@ class Connection(ConnectionBase):
This also happens to be the former default.
Can revisit using $HOME instead if it's a problem
"""
'''
if not remote_path.startswith(os.path.sep):
remote_path = os.path.join(os.path.sep, remote_path)
return os.path.normpath(remote_path)
def put_file(self, in_path, out_path):
""" transfer a file from local to jail """
''' transfer a file from local to jail '''
super(Connection, self).put_file(in_path, out_path)
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.jail)
@@ -172,7 +172,7 @@ class Connection(ConnectionBase):
raise AnsibleError("file or module does not exist at: %s" % in_path)
def fetch_file(self, in_path, out_path):
""" fetch a file from jail to local """
''' fetch a file from jail to local '''
super(Connection, self).fetch_file(in_path, out_path)
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.jail)
@@ -196,6 +196,6 @@ class Connection(ConnectionBase):
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, to_native(stdout), to_native(stderr)))
def close(self):
""" terminate the connection; nothing to do here """
''' terminate the connection; nothing to do here '''
super(Connection, self).close()
self._connected = False

View File

@@ -42,13 +42,14 @@ try:
except ImportError:
pass
from ansible import constants as C
from ansible import errors
from ansible.module_utils._text import to_bytes, to_native
from ansible.plugins.connection import ConnectionBase
class Connection(ConnectionBase):
""" Local lxc based connections """
''' Local lxc based connections '''
transport = 'community.general.lxc'
has_pipelining = True
@@ -61,7 +62,7 @@ class Connection(ConnectionBase):
self.container = None
def _connect(self):
""" connect to the lxc; nothing to do here """
''' connect to the lxc; nothing to do here '''
super(Connection, self)._connect()
if not HAS_LIBLXC:
@@ -76,8 +77,7 @@ class Connection(ConnectionBase):
if self.container.state == "STOPPED":
raise errors.AnsibleError("%s is not running" % self.container_name)
@staticmethod
def _communicate(pid, in_data, stdin, stdout, stderr):
def _communicate(self, pid, in_data, stdin, stdout, stderr):
buf = {stdout: [], stderr: []}
read_fds = [stdout, stderr]
if in_data:
@@ -111,7 +111,7 @@ class Connection(ConnectionBase):
return fd
def exec_command(self, cmd, in_data=None, sudoable=False):
""" run a command on the chroot """
''' run a command on the chroot '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
# python2-lxc needs bytes. python3-lxc needs text.

View File

@@ -37,9 +37,15 @@ DOCUMENTATION = '''
# - name: hosts
'''
import shlex
import shutil
import os
import base64
import subprocess
from ansible.module_utils._text import to_bytes
import ansible.constants as C
from ansible.module_utils._text import to_bytes, to_native
from ansible.plugins.connection import ConnectionBase, ensure_connect
from ansible.errors import AnsibleConnectionFailure
from ansible.utils.display import Display

View File

@@ -16,11 +16,14 @@ DOCUMENTATION = '''
- This allows you to use existing Saltstack infrastructure to connect to targets.
'''
import re
import os
import base64
import pty
import codecs
import subprocess
from ansible import errors
from ansible.plugins.connection import ConnectionBase
from ansible.module_utils._text import to_bytes, to_text
from ansible.module_utils.six.moves import cPickle
HAVE_SALTSTACK = False
try:
@@ -29,9 +32,13 @@ try:
except ImportError:
pass
import os
from ansible import errors
from ansible.plugins.connection import ConnectionBase
class Connection(ConnectionBase):
""" Salt-based connections """
''' Salt-based connections '''
has_pipelining = False
# while the name of the product is salt, naming that module salt cause
@@ -51,30 +58,29 @@ class Connection(ConnectionBase):
return self
def exec_command(self, cmd, sudoable=False, in_data=None):
""" run a command on the remote minion """
''' run a command on the remote minion '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
if in_data:
raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")
self._display.vvv("EXEC %s" % cmd, host=self.host)
self._display.vvv("EXEC %s" % (cmd), host=self.host)
# need to add 'true;' to work around https://github.com/saltstack/salt/issues/28077
res = self.client.cmd(self.host, 'cmd.exec_code_all', ['bash', 'true;' + cmd])
if self.host not in res:
raise errors.AnsibleError("Minion %s didn't answer, check if salt-minion is running and the name is correct" % self.host)
p = res[self.host]
return p['retcode'], p['stdout'], p['stderr']
return (p['retcode'], p['stdout'], p['stderr'])
@staticmethod
def _normalize_path(path, prefix):
def _normalize_path(self, path, prefix):
if not path.startswith(os.path.sep):
path = os.path.join(os.path.sep, path)
normpath = os.path.normpath(path)
return os.path.join(prefix, normpath[1:])
def put_file(self, in_path, out_path):
""" transfer a file from local to remote """
''' transfer a file from local to remote '''
super(Connection, self).put_file(in_path, out_path)
@@ -82,11 +88,11 @@ class Connection(ConnectionBase):
self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.host)
with open(in_path, 'rb') as in_fh:
content = in_fh.read()
self.client.cmd(self.host, 'hashutil.base64_decodefile', [base64.b64encode(content), out_path])
self.client.cmd(self.host, 'hashutil.base64_decodefile', [codecs.encode(content, 'base64'), out_path])
# TODO test it
def fetch_file(self, in_path, out_path):
""" fetch a file from remote to local """
''' fetch a file from remote to local '''
super(Connection, self).fetch_file(in_path, out_path)
@@ -96,5 +102,5 @@ class Connection(ConnectionBase):
open(out_path, 'wb').write(content)
def close(self):
""" terminate the connection; nothing to do here """
''' terminate the connection; nothing to do here '''
pass

View File

@@ -31,6 +31,7 @@ import os.path
import subprocess
import traceback
from ansible import constants as C
from ansible.errors import AnsibleError
from ansible.module_utils.six.moves import shlex_quote
from ansible.module_utils._text import to_bytes
@@ -41,7 +42,7 @@ display = Display()
class Connection(ConnectionBase):
""" Local zone based connections """
''' Local zone based connections '''
transport = 'community.general.zone'
has_pipelining = True
@@ -74,9 +75,9 @@ class Connection(ConnectionBase):
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
zones = []
for line in process.stdout.readlines():
for l in process.stdout.readlines():
# 1:work:running:/zones/work:3126dc59-9a07-4829-cde9-a816e4c5040e:native:shared
s = line.split(':')
s = l.split(':')
if s[1] != 'global':
zones.append(s[1])
@@ -94,20 +95,20 @@ class Connection(ConnectionBase):
return path + '/root'
def _connect(self):
""" connect to the zone; nothing to do here """
''' connect to the zone; nothing to do here '''
super(Connection, self)._connect()
if not self._connected:
display.vvv("THIS IS A LOCAL ZONE DIR", host=self.zone)
self._connected = True
def _buffered_exec_command(self, cmd, stdin=subprocess.PIPE):
""" run a command on the zone. This is only needed for implementing
''' run a command on the zone. This is only needed for implementing
put_file() get_file() so that we don't have to read the whole file
into memory.
compared to exec_command() it looses some niceties like being able to
return the process's exit code immediately.
"""
'''
# NOTE: zlogin invokes a shell (just like ssh does) so we do not pass
# this through /bin/sh -c here. Instead it goes through the shell
# that zlogin selects.
@@ -121,16 +122,16 @@ class Connection(ConnectionBase):
return p
def exec_command(self, cmd, in_data=None, sudoable=False):
""" run a command on the zone """
''' run a command on the zone '''
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
p = self._buffered_exec_command(cmd)
stdout, stderr = p.communicate(in_data)
return p.returncode, stdout, stderr
return (p.returncode, stdout, stderr)
def _prefix_login_path(self, remote_path):
""" Make sure that we put files into a standard path
''' Make sure that we put files into a standard path
If a path is relative, then we need to choose where to put it.
ssh chooses $HOME but we aren't guaranteed that a home dir will
@@ -138,13 +139,13 @@ class Connection(ConnectionBase):
This also happens to be the former default.
Can revisit using $HOME instead if it's a problem
"""
'''
if not remote_path.startswith(os.path.sep):
remote_path = os.path.join(os.path.sep, remote_path)
return os.path.normpath(remote_path)
def put_file(self, in_path, out_path):
""" transfer a file from local to zone """
''' transfer a file from local to zone '''
super(Connection, self).put_file(in_path, out_path)
display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.zone)
@@ -170,7 +171,7 @@ class Connection(ConnectionBase):
raise AnsibleError("file or module does not exist at: %s" % in_path)
def fetch_file(self, in_path, out_path):
""" fetch a file from zone to local """
''' fetch a file from zone to local '''
super(Connection, self).fetch_file(in_path, out_path)
display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.zone)
@@ -194,6 +195,6 @@ class Connection(ConnectionBase):
raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
def close(self):
""" terminate the connection; nothing to do here """
''' terminate the connection; nothing to do here '''
super(Connection, self).close()
self._connected = False

View File

@@ -30,6 +30,7 @@ options:
description:
- Keycloak realm name to authenticate to for API access.
type: str
required: true
auth_client_secret:
description:
@@ -40,6 +41,7 @@ options:
description:
- Username to authenticate for API access with.
type: str
required: true
aliases:
- username
@@ -47,15 +49,10 @@ options:
description:
- Password to authenticate for API access with.
type: str
required: true
aliases:
- password
token:
description:
- Authentication token for Keycloak API.
type: str
version_added: 3.0.0
validate_certs:
description:
- Verify TLS certificates (do not disable this in production).

View File

@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2016, Red Hat, Inc.
# 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
class ModuleDocFragment(object):
# info standard oVirt documentation fragment
DOCUMENTATION = r'''
options:
fetch_nested:
description:
- If I(yes) the module will fetch additional data from the API.
- It will fetch only IDs of nested entity. It doesn't fetch multiple levels of nested attributes.
Only the attributes of the current entity. User can configure to fetch other
attributes of the nested entities by specifying C(nested_attributes).
type: bool
default: false
nested_attributes:
description:
- Specifies list of the attributes which should be fetched from the API.
- This parameter apply only when C(fetch_nested) is I(true).
type: list
auth:
description:
- "Dictionary with values needed to create HTTP/HTTPS connection to oVirt:"
- C(username)[I(required)] - The name of the user, something like I(admin@internal).
Default value is set by I(OVIRT_USERNAME) environment variable.
- "C(password)[I(required)] - The password of the user. Default value is set by I(OVIRT_PASSWORD) environment variable."
- "C(url)- A string containing the API URL of the server, usually
something like `I(https://server.example.com/ovirt-engine/api)`. Default value is set by I(OVIRT_URL) environment variable.
Either C(url) or C(hostname) is required."
- "C(hostname) - A string containing the hostname of the server, usually
something like `I(server.example.com)`. Default value is set by I(OVIRT_HOSTNAME) environment variable.
Either C(url) or C(hostname) is required."
- "C(token) - Token to be used instead of login with username/password. Default value is set by I(OVIRT_TOKEN) environment variable."
- "C(insecure) - A boolean flag that indicates if the server TLS
certificate and host name should be checked."
- "C(ca_file) - A PEM file containing the trusted CA certificates. The
certificate presented by the server will be verified using these CA
certificates. If `C(ca_file)` parameter is not set, system wide
CA certificate store is used. Default value is set by I(OVIRT_CAFILE) environment variable."
- "C(kerberos) - A boolean flag indicating if Kerberos authentication
should be used instead of the default basic authentication."
- "C(headers) - Dictionary of HTTP headers to be added to each API call."
type: dict
required: true
requirements:
- python >= 2.7
- ovirt-engine-sdk-python >= 4.3.0
notes:
- "In order to use this module you have to install oVirt Python SDK.
To ensure it's installed with correct version you can create the following task:
ansible.builtin.pip: name=ovirt-engine-sdk-python version=4.3.0"
'''

View File

@@ -1,42 +0,0 @@
# -*- 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)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleFilterError
from ansible.module_utils.common._collections_compat import Mapping, Sequence
def groupby_as_dict(sequence, attribute):
'''
Given a sequence of dictionaries and an attribute name, returns a dictionary mapping
the value of this attribute to the dictionary.
If multiple dictionaries in the sequence have the same value for this attribute,
the filter will fail.
'''
if not isinstance(sequence, Sequence):
raise AnsibleFilterError('Input is not a sequence')
result = dict()
for list_index, element in enumerate(sequence):
if not isinstance(element, Mapping):
raise AnsibleFilterError('Sequence element #{0} is not a mapping'.format(list_index))
if attribute not in element:
raise AnsibleFilterError('Attribute not contained in element #{0} of sequence'.format(list_index))
result_index = element[attribute]
if result_index in result:
raise AnsibleFilterError('Multiple sequence entries have attribute value {0!r}'.format(result_index))
result[result_index] = element
return result
class FilterModule(object):
''' Ansible list filters '''
def filters(self):
return {
'groupby_as_dict': groupby_as_dict,
}

View File

@@ -1,97 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@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,
AnsibleFilterTypeError,
)
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.common.collections import is_sequence
try:
from hashids import Hashids
HAS_HASHIDS = True
except ImportError:
HAS_HASHIDS = False
def initialize_hashids(**kwargs):
if not HAS_HASHIDS:
raise AnsibleError("The hashids library must be installed in order to use this plugin")
params = dict((k, v) for k, v in kwargs.items() if v)
try:
return Hashids(**params)
except TypeError as e:
raise AnsibleFilterError(
"The provided parameters %s are invalid: %s" % (
', '.join(["%s=%s" % (k, v) for k, v in params.items()]),
to_native(e)
)
)
def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
"""Generates a YouTube-like hash from a sequence of ints
:nums: Sequence of one or more ints to hash
: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
"""
hashids = initialize_hashids(
salt=salt,
alphabet=alphabet,
min_length=min_length
)
# Handles the case where a single int is not encapsulated in a list or tuple.
# User convenience seems preferable to strict typing in this case
# Also avoids obfuscated error messages related to single invalid inputs
if not is_sequence(nums):
nums = [nums]
try:
hashid = hashids.encode(*nums)
except TypeError as e:
raise AnsibleFilterTypeError(
"Data to encode must by a tuple or list of ints: %s" % to_native(e)
)
return hashid
def hashids_decode(hashid, salt=None, alphabet=None, min_length=None):
"""Decodes a YouTube-like hash to a sequence of ints
:hashid: Hash string to decode
: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
"""
hashids = initialize_hashids(
salt=salt,
alphabet=alphabet,
min_length=min_length
)
nums = hashids.decode(hashid)
return list(nums)
class FilterModule(object):
def filters(self):
return {
'hashids_encode': hashids_encode,
'hashids_decode': hashids_decode,
}

View File

@@ -1,950 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Frank Dornheim <dornheim@posteo.de>
# 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
DOCUMENTATION = r'''
name: lxd
short_description: Returns Ansible inventory from lxd host
description:
- Get inventory from the lxd.
- Uses a YAML configuration file that ends with 'lxd.(yml|yaml)'.
version_added: "3.0.0"
author: "Frank Dornheim (@conloos)"
options:
plugin:
description: Token that ensures this is a source file for the 'lxd' plugin.
required: true
choices: [ 'community.general.lxd' ]
url:
description:
- The unix domain socket path or the https URL for the lxd server.
- Sockets in filesystem have to start with C(unix:).
- Mostly C(unix:/var/lib/lxd/unix.socket) or C(unix:/var/snap/lxd/common/lxd/unix.socket).
default: unix:/var/snap/lxd/common/lxd/unix.socket
type: str
client_key:
description:
- The client certificate key file path.
aliases: [ key_file ]
default: $HOME/.config/lxc/client.key
type: path
client_cert:
description:
- The client certificate file path.
aliases: [ cert_file ]
default: $HOME/.config/lxc/client.crt
type: path
trust_password:
description:
- The client trusted password.
- You need to set this password on the lxd server before
running this module using the following command
C(lxc config set core.trust_password <some random password>)
See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/).
- If I(trust_password) is set, this module send a request for authentication before sending any requests.
type: str
state:
description: Filter the container according to the current status.
type: str
default: none
choices: [ 'STOPPED', 'STARTING', 'RUNNING', 'none' ]
prefered_container_network_interface:
description:
- If a container has multiple network interfaces, select which one is the prefered as pattern.
- Combined with the first number that can be found e.g. 'eth' + 0.
type: str
default: eth
prefered_container_network_family:
description:
- If a container has multiple network interfaces, which one is the prefered by family.
- Specify C(inet) for IPv4 and C(inet6) for IPv6.
type: str
default: inet
choices: [ 'inet', 'inet6' ]
groupby:
description:
- Create groups by the following keywords C(location), C(pattern), C(network_range), C(os), C(release), C(profile), C(vlanid).
- See example for syntax.
type: dict
'''
EXAMPLES = '''
# simple lxd.yml
plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket
# simple lxd.yml including filter
plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket
state: RUNNING
# grouping lxd.yml
groupby:
testpattern:
type: pattern
attribute: test
vlan666:
type: vlanid
attribute: 666
locationBerlin:
type: location
attribute: Berlin
osUbuntu:
type: os
attribute: ubuntu
releaseFocal:
type: release
attribute: focal
releaseBionic:
type: release
attribute: bionic
profileDefault:
type: profile
attribute: default
profileX11:
type: profile
attribute: x11
netRangeIPv4:
type: network_range
attribute: 10.98.143.0/24
netRangeIPv6:
type: network_range
attribute: fd42:bd00:7b11:2167:216:3eff::/24
'''
import binascii
import json
import re
import time
import os
import socket
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.module_utils._text import to_native, to_text
from ansible.module_utils.common.dict_transformations import dict_merge
from ansible.errors import AnsibleError, AnsibleParserError
from ansible_collections.community.general.plugins.module_utils.compat import ipaddress
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
class InventoryModule(BaseInventoryPlugin):
DEBUG = 4
NAME = 'community.general.lxd'
SNAP_SOCKET_URL = 'unix:/var/snap/lxd/common/lxd/unix.socket'
SOCKET_URL = 'unix:/var/lib/lxd/unix.socket'
@staticmethod
def load_json_data(path):
"""Load json data
Load json data from file
Args:
list(path): Path elements
str(file_name): Filename of data
Kwargs:
None
Raises:
None
Returns:
dict(json_data): json data"""
try:
with open(path, 'r') as json_file:
return json.load(json_file)
except (IOError, json.decoder.JSONDecodeError) as err:
raise AnsibleParserError('Could not load the test data from {0}: {1}'.format(to_native(path), to_native(err)))
def save_json_data(self, path, file_name=None):
"""save data as json
Save data as json file
Args:
list(path): Path elements
str(file_name): Filename of data
Kwargs:
None
Raises:
None
Returns:
None"""
if file_name:
path.append(file_name)
else:
prefix = 'lxd_data-'
time_stamp = time.strftime('%Y%m%d-%H%M%S')
suffix = '.atd'
path.append(prefix + time_stamp + suffix)
try:
cwd = os.path.abspath(os.path.dirname(__file__))
with open(os.path.abspath(os.path.join(cwd, *path)), 'w') as json_file:
json.dump(self.data, json_file)
except IOError as err:
raise AnsibleParserError('Could not save data: {0}'.format(to_native(err)))
def verify_file(self, path):
"""Check the config
Return true/false if the config-file is valid for this plugin
Args:
str(path): path to the config
Kwargs:
None
Raises:
None
Returns:
bool(valid): is valid"""
valid = False
if super(InventoryModule, self).verify_file(path):
if path.endswith(('lxd.yaml', 'lxd.yml')):
valid = True
else:
self.display.vvv('Inventory source not ending in "lxd.yaml" or "lxd.yml"')
return valid
@staticmethod
def validate_url(url):
"""validate url
check whether the url is correctly formatted
Args:
url
Kwargs:
None
Raises:
AnsibleError
Returns:
bool"""
if not isinstance(url, str):
return False
if not url.startswith(('unix:', 'https:')):
raise AnsibleError('URL is malformed: {0}'.format(to_native(url)))
return True
def _connect_to_socket(self):
"""connect to lxd socket
Connect to lxd socket by provided url or defaults
Args:
None
Kwargs:
None
Raises:
AnsibleError
Returns:
None"""
error_storage = {}
url_list = [self.get_option('url'), self.SNAP_SOCKET_URL, self.SOCKET_URL]
urls = (url for url in url_list if self.validate_url(url))
for url in urls:
try:
socket_connection = LXDClient(url, self.client_key, self.client_cert, self.debug)
return socket_connection
except LXDClientException as err:
error_storage[url] = err
raise AnsibleError('No connection to the socket: {0}'.format(to_native(error_storage)))
def _get_networks(self):
"""Get Networknames
Returns all network config names
Args:
None
Kwargs:
None
Raises:
None
Returns:
list(names): names of all network_configs"""
# e.g. {'type': 'sync',
# 'status': 'Success',
# 'status_code': 200,
# 'operation': '',
# 'error_code': 0,
# 'error': '',
# 'metadata': ['/1.0/networks/lxdbr0']}
network_configs = self.socket.do('GET', '/1.0/networks')
return [m.split('/')[3] for m in network_configs['metadata']]
def _get_containers(self):
"""Get Containernames
Returns all containernames
Args:
None
Kwargs:
None
Raises:
None
Returns:
list(names): names of all containers"""
# e.g. {'type': 'sync',
# 'status': 'Success',
# 'status_code': 200,
# 'operation': '',
# 'error_code': 0,
# 'error': '',
# 'metadata': ['/1.0/containers/udemy-ansible-ubuntu-2004']}
containers = self.socket.do('GET', '/1.0/containers')
return [m.split('/')[3] for m in containers['metadata']]
def _get_config(self, branch, name):
"""Get inventory of container
Get config of container
Args:
str(branch): Name oft the API-Branch
str(name): Name of Container
Kwargs:
None
Source:
https://github.com/lxc/lxd/blob/master/doc/rest-api.md
Raises:
None
Returns:
dict(config): Config of the container"""
config = {}
if isinstance(branch, (tuple, list)):
config[name] = {branch[1]: self.socket.do('GET', '/1.0/{0}/{1}/{2}'.format(to_native(branch[0]), to_native(name), to_native(branch[1])))}
else:
config[name] = {branch: self.socket.do('GET', '/1.0/{0}/{1}'.format(to_native(branch), to_native(name)))}
return config
def get_container_data(self, names):
"""Create Inventory of the container
Iterate through the different branches of the containers and collect Informations.
Args:
list(names): List of container names
Kwargs:
None
Raises:
None
Returns:
None"""
# tuple(('instances','metadata/templates')) to get section in branch
# e.g. /1.0/instances/<name>/metadata/templates
branches = ['containers', ('instances', 'state')]
container_config = {}
for branch in branches:
for name in names:
container_config['containers'] = self._get_config(branch, name)
self.data = dict_merge(container_config, self.data)
def get_network_data(self, names):
"""Create Inventory of the container
Iterate through the different branches of the containers and collect Informations.
Args:
list(names): List of container names
Kwargs:
None
Raises:
None
Returns:
None"""
# tuple(('instances','metadata/templates')) to get section in branch
# e.g. /1.0/instances/<name>/metadata/templates
branches = [('networks', 'state')]
network_config = {}
for branch in branches:
for name in names:
try:
network_config['networks'] = self._get_config(branch, name)
except LXDClientException:
network_config['networks'] = {name: None}
self.data = dict_merge(network_config, self.data)
def extract_network_information_from_container_config(self, container_name):
"""Returns the network interface configuration
Returns the network ipv4 and ipv6 config of the container without local-link
Args:
str(container_name): Name oft he container
Kwargs:
None
Raises:
None
Returns:
dict(network_configuration): network config"""
container_network_interfaces = self._get_data_entry('containers/{0}/state/metadata/network'.format(container_name))
network_configuration = None
if container_network_interfaces:
network_configuration = {}
gen_interface_names = [interface_name for interface_name in container_network_interfaces if interface_name != 'lo']
for interface_name in gen_interface_names:
gen_address = [address for address in container_network_interfaces[interface_name]['addresses'] if address.get('scope') != 'link']
network_configuration[interface_name] = []
for address in gen_address:
address_set = {}
address_set['family'] = address.get('family')
address_set['address'] = address.get('address')
address_set['netmask'] = address.get('netmask')
address_set['combined'] = address.get('address') + '/' + address.get('netmask')
network_configuration[interface_name].append(address_set)
return network_configuration
def get_prefered_container_network_interface(self, container_name):
"""Helper to get the prefered interface of thr container
Helper to get the prefered interface provide by neme pattern from 'prefered_container_network_interface'.
Args:
str(containe_name): name of container
Kwargs:
None
Raises:
None
Returns:
str(prefered_interface): None or interface name"""
container_network_interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
prefered_interface = None # init
if container_network_interfaces: # container have network interfaces
# generator if interfaces which start with the desired pattern
net_generator = [interface for interface in container_network_interfaces if interface.startswith(self.prefered_container_network_interface)]
selected_interfaces = [] # init
for interface in net_generator:
selected_interfaces.append(interface)
if len(selected_interfaces) > 0:
prefered_interface = sorted(selected_interfaces)[0]
return prefered_interface
def get_container_vlans(self, container_name):
"""Get VLAN(s) from container
Helper to get the VLAN_ID from the container
Args:
str(containe_name): name of container
Kwargs:
None
Raises:
None
Returns:
None"""
# get network device configuration and store {network: vlan_id}
network_vlans = {}
for network in self._get_data_entry('networks'):
if self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network)):
network_vlans[network] = self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network))
# get networkdevices of container and return
# e.g.
# "eth0":{ "name":"eth0",
# "network":"lxdbr0",
# "type":"nic"},
vlan_ids = {}
devices = self._get_data_entry('containers/{0}/containers/metadata/expanded_devices'.format(to_native(container_name)))
for device in devices:
if 'network' in devices[device]:
if devices[device]['network'] in network_vlans:
vlan_ids[devices[device].get('network')] = network_vlans[devices[device].get('network')]
return vlan_ids if vlan_ids else None
def _get_data_entry(self, path, data=None, delimiter='/'):
"""Helper to get data
Helper to get data from self.data by a path like 'path/to/target'
Attention: Escaping of the delimiter is not (yet) provided.
Args:
str(path): path to nested dict
Kwargs:
dict(data): datastore
str(delimiter): delimiter in Path.
Raises:
None
Returns:
*(value)"""
try:
if not data:
data = self.data
if delimiter in path:
path = path.split(delimiter)
if isinstance(path, list) and len(path) > 1:
data = data[path.pop(0)]
path = delimiter.join(path)
return self._get_data_entry(path, data, delimiter) # recursion
return data[path]
except KeyError:
return None
def _set_data_entry(self, container_name, key, value, path=None):
"""Helper to save data
Helper to save the data in self.data
Detect if data is allready in branch and use dict_merge() to prevent that branch is overwritten.
Args:
str(container_name): name of container
str(key): same as dict
*(value): same as dict
Kwargs:
str(path): path to branch-part
Raises:
AnsibleParserError
Returns:
None"""
if not path:
path = self.data['inventory']
if container_name not in path:
path[container_name] = {}
try:
if isinstance(value, dict) and key in path[container_name]:
path[container_name] = dict_merge(value, path[container_name][key])
else:
path[container_name][key] = value
except KeyError as err:
raise AnsibleParserError("Unable to store Informations: {0}".format(to_native(err)))
def extract_information_from_container_configs(self):
"""Process configuration information
Preparation of the data
Args:
dict(configs): Container configurations
Kwargs:
None
Raises:
None
Returns:
None"""
# create branch "inventory"
if 'inventory' not in self.data:
self.data['inventory'] = {}
for container_name in self.data['containers']:
self._set_data_entry(container_name, 'os', self._get_data_entry(
'containers/{0}/containers/metadata/config/image.os'.format(container_name)))
self._set_data_entry(container_name, 'release', self._get_data_entry(
'containers/{0}/containers/metadata/config/image.release'.format(container_name)))
self._set_data_entry(container_name, 'version', self._get_data_entry(
'containers/{0}/containers/metadata/config/image.version'.format(container_name)))
self._set_data_entry(container_name, 'profile', self._get_data_entry(
'containers/{0}/containers/metadata/profiles'.format(container_name)))
self._set_data_entry(container_name, 'location', self._get_data_entry(
'containers/{0}/containers/metadata/location'.format(container_name)))
self._set_data_entry(container_name, 'state', self._get_data_entry(
'containers/{0}/containers/metadata/config/volatile.last_state.power'.format(container_name)))
self._set_data_entry(container_name, 'network_interfaces', self.extract_network_information_from_container_config(container_name))
self._set_data_entry(container_name, 'preferred_interface', self.get_prefered_container_network_interface(container_name))
self._set_data_entry(container_name, 'vlan_ids', self.get_container_vlans(container_name))
def build_inventory_network(self, container_name):
"""Add the network interfaces of the container to the inventory
Logic:
- if the container have no interface -> 'ansible_connection: local'
- get preferred_interface & prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
- first Interface from: network_interfaces prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
Args:
str(container_name): name of container
Kwargs:
None
Raises:
None
Returns:
None"""
def interface_selection(container_name):
"""Select container Interface for inventory
Logic:
- get preferred_interface & prefered_container_network_family -> str(IP)
- first Interface from: network_interfaces prefered_container_network_family -> str(IP)
Args:
str(container_name): name of container
Kwargs:
None
Raises:
None
Returns:
dict(interface_name: ip)"""
prefered_interface = self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)) # name or None
prefered_container_network_family = self.prefered_container_network_family
ip_address = ''
if prefered_interface:
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(container_name, prefered_interface))
for config in interface:
if config['family'] == prefered_container_network_family:
ip_address = config['address']
break
else:
interface = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
for config in interface:
if config['family'] == prefered_container_network_family:
ip_address = config['address']
break
return ip_address
if self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name)): # container have network interfaces
if self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)): # container have a preferred interface
self.inventory.set_variable(container_name, 'ansible_connection', 'ssh')
self.inventory.set_variable(container_name, 'ansible_host', interface_selection(container_name))
else:
self.inventory.set_variable(container_name, 'ansible_connection', 'local')
def build_inventory_hosts(self):
"""Build host-part dynamic inventory
Build the host-part of the dynamic inventory.
Add Hosts and host_vars to the inventory.
Args:
None
Kwargs:
None
Raises:
None
Returns:
None"""
for container_name in self.data['inventory']:
# Only consider containers that match the "state" filter, if self.state is not None
if self.filter:
if self.filter.lower() != self._get_data_entry('inventory/{0}/state'.format(container_name)).lower():
continue
# add container
self.inventory.add_host(container_name)
# add network informations
self.build_inventory_network(container_name)
# add os
self.inventory.set_variable(container_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(container_name)).lower())
# add release
self.inventory.set_variable(container_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(container_name)).lower())
# add profile
self.inventory.set_variable(container_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(container_name)))
# add state
self.inventory.set_variable(container_name, 'ansible_lxd_state', self._get_data_entry('inventory/{0}/state'.format(container_name)).lower())
# add location information
if self._get_data_entry('inventory/{0}/location'.format(container_name)) != "none": # wrong type by lxd 'none' != 'None'
self.inventory.set_variable(container_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(container_name)))
# add VLAN_ID information
if self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)):
self.inventory.set_variable(container_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)))
def build_inventory_groups_location(self, group_name):
"""create group by attribute: location
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
for container_name in self.inventory.hosts:
if 'ansible_lxd_location' in self.inventory.get_host(container_name).get_vars():
self.inventory.add_child(group_name, container_name)
def build_inventory_groups_pattern(self, group_name):
"""create group by name pattern
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
regex_pattern = self.groupby[group_name].get('attribute')
for container_name in self.inventory.hosts:
result = re.search(regex_pattern, container_name)
if result:
self.inventory.add_child(group_name, container_name)
def build_inventory_groups_network_range(self, group_name):
"""check if IP is in network-class
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
try:
network = ipaddress.ip_network(to_text(self.groupby[group_name].get('attribute')))
except ValueError as err:
raise AnsibleParserError(
'Error while parsing network range {0}: {1}'.format(self.groupby[group_name].get('attribute'), to_native(err)))
for container_name in self.inventory.hosts:
if self.data['inventory'][container_name].get('network_interfaces') is not None:
for interface in self.data['inventory'][container_name].get('network_interfaces'):
for interface_family in self.data['inventory'][container_name].get('network_interfaces')[interface]:
try:
address = ipaddress.ip_address(to_text(interface_family['address']))
if address.version == network.version and address in network:
self.inventory.add_child(group_name, container_name)
except ValueError:
# Ignore invalid IP addresses returned by lxd
pass
def build_inventory_groups_os(self, group_name):
"""create group by attribute: os
Args:
str(group_name): Group name
Kwargs:
Noneself.data['inventory'][container_name][interface]
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
gen_containers = [
container_name for container_name in self.inventory.hosts
if 'ansible_lxd_os' in self.inventory.get_host(container_name).get_vars()]
for container_name in gen_containers:
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_os'):
self.inventory.add_child(group_name, container_name)
def build_inventory_groups_release(self, group_name):
"""create group by attribute: release
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
gen_containers = [
container_name for container_name in self.inventory.hosts
if 'ansible_lxd_release' in self.inventory.get_host(container_name).get_vars()]
for container_name in gen_containers:
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_release'):
self.inventory.add_child(group_name, container_name)
def build_inventory_groups_profile(self, group_name):
"""create group by attribute: profile
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
gen_containers = [
container_name for container_name in self.inventory.hosts.keys()
if 'ansible_lxd_profile' in self.inventory.get_host(container_name).get_vars().keys()]
for container_name in gen_containers:
if self.groupby[group_name].get('attribute').lower() in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_profile'):
self.inventory.add_child(group_name, container_name)
def build_inventory_groups_vlanid(self, group_name):
"""create group by attribute: vlanid
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# maybe we just want to expand one group
if group_name not in self.inventory.groups:
self.inventory.add_group(group_name)
gen_containers = [
container_name for container_name in self.inventory.hosts.keys()
if 'ansible_lxd_vlan_ids' in self.inventory.get_host(container_name).get_vars().keys()]
for container_name in gen_containers:
if self.groupby[group_name].get('attribute') in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_vlan_ids').values():
self.inventory.add_child(group_name, container_name)
def build_inventory_groups(self):
"""Build group-part dynamic inventory
Build the group-part of the dynamic inventory.
Add groups to the inventory.
Args:
None
Kwargs:
None
Raises:
None
Returns:
None"""
def group_type(group_name):
"""create groups defined by lxd.yml or defaultvalues
create groups defined by lxd.yml or defaultvalues
supportetd:
* 'location'
* 'pattern'
* 'network_range'
* 'os'
* 'release'
* 'profile'
* 'vlanid'
Args:
str(group_name): Group name
Kwargs:
None
Raises:
None
Returns:
None"""
# Due to the compatibility with python 2 no use of map
if self.groupby[group_name].get('type') == 'location':
self.build_inventory_groups_location(group_name)
elif self.groupby[group_name].get('type') == 'pattern':
self.build_inventory_groups_pattern(group_name)
elif self.groupby[group_name].get('type') == 'network_range':
self.build_inventory_groups_network_range(group_name)
elif self.groupby[group_name].get('type') == 'os':
self.build_inventory_groups_os(group_name)
elif self.groupby[group_name].get('type') == 'release':
self.build_inventory_groups_release(group_name)
elif self.groupby[group_name].get('type') == 'profile':
self.build_inventory_groups_profile(group_name)
elif self.groupby[group_name].get('type') == 'vlanid':
self.build_inventory_groups_vlanid(group_name)
else:
raise AnsibleParserError('Unknown group type: {0}'.format(to_native(group_name)))
if self.groupby:
for group_name in self.groupby:
if not group_name.isalnum():
raise AnsibleParserError('Invalid character(s) in groupname: {0}'.format(to_native(group_name)))
group_type(group_name)
def build_inventory(self):
"""Build dynamic inventory
Build the dynamic inventory.
Args:
None
Kwargs:
None
Raises:
None
Returns:
None"""
self.build_inventory_hosts()
self.build_inventory_groups()
def _populate(self):
"""Return the hosts and groups
Returns the processed container configurations from the lxd import
Args:
None
Kwargs:
None
Raises:
None
Returns:
None"""
if len(self.data) == 0: # If no data is injected by unittests open socket
self.socket = self._connect_to_socket()
self.get_container_data(self._get_containers())
self.get_network_data(self._get_networks())
self.extract_information_from_container_configs()
# self.display.vvv(self.save_json_data([os.path.abspath(__file__)]))
self.build_inventory()
def parse(self, inventory, loader, path, cache):
"""Return dynamic inventory from source
Returns the processed inventory from the lxd import
Args:
str(inventory): inventory object with existing data and
the methods to add hosts/groups/variables
to inventory
str(loader): Ansible's DataLoader
str(path): path to the config
bool(cache): use or avoid caches
Kwargs:
None
Raises:
AnsibleParserError
Returns:
None"""
super(InventoryModule, self).parse(inventory, loader, path, cache=False)
# Read the inventory YAML file
self._read_config_data(path)
try:
self.client_key = self.get_option('client_key')
self.client_cert = self.get_option('client_cert')
self.debug = self.DEBUG
self.data = {} # store for inventory-data
self.groupby = self.get_option('groupby')
self.plugin = self.get_option('plugin')
self.prefered_container_network_family = self.get_option('prefered_container_network_family')
self.prefered_container_network_interface = self.get_option('prefered_container_network_interface')
if self.get_option('state').lower() == 'none': # none in config is str()
self.filter = None
else:
self.filter = self.get_option('state').lower()
self.trust_password = self.get_option('trust_password')
self.url = self.get_option('url')
except Exception as err:
raise AnsibleParserError(
'All correct options required: {0}'.format(to_native(err)))
# Call our internal helper to populate the dynamic inventory
self._populate()

View File

@@ -70,13 +70,6 @@ DOCUMENTATION = '''
description: Gather LXC/QEMU configuration facts.
default: no
type: bool
want_proxmox_nodes_ansible_host:
version_added: 3.0.0
description:
- Whether to set C(ansbile_host) for proxmox nodes.
- When set to C(true) (default), will use the first available interface. This can be different from what you expect.
default: true
type: bool
strict:
version_added: 2.5.0
compose:
@@ -241,22 +234,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
)
)['result']
if "error" in ifaces:
if "class" in ifaces["error"]:
# This happens on Windows, even though qemu agent is running, the IP address
# cannot be fetched, as it's unsupported, also a command disabled can happen.
errorClass = ifaces["error"]["class"]
if errorClass in ["Unsupported"]:
self.display.v("Retrieving network interfaces from guest agents on windows with older qemu-guest-agents is not supported")
elif errorClass in ["CommandDisabled"]:
self.display.v("Retrieving network interfaces from guest agents has been disabled")
return result
for iface in ifaces:
result.append({
'name': iface['name'],
'mac-address': iface['hardware-address'] if 'hardware-address' in iface else '',
'ip-addresses': ["%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']] if 'ip-addresses' in iface else []
'mac-address': iface['hardware-address'],
'ip-addresses': [
"%s/%s" % (ip['ip-address'], ip['prefix']) for ip in iface['ip-addresses']
]
})
except requests.HTTPError:
pass
@@ -370,9 +354,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
self.inventory.add_child(nodes_group, node['node'])
# 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)
ip = self._get_node_ip(node['node'])
self.inventory.set_variable(node['node'], 'ansible_host', ip)
# get LXC containers for this node
node_lxc_group = self.to_safe('%s%s' % (self.get_option('group_prefix'), ('%s_lxc' % node['node']).lower()))

View File

@@ -1,24 +1,24 @@
# Copyright (c) 2017 Ansible Project
# Copyright: (c) 2017 Ansible Project
# 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
DOCUMENTATION = '''
DOCUMENTATION = r'''
name: scaleway
author:
- Remy Leone (@sieben)
short_description: Scaleway inventory source
description:
- Get inventory hosts from Scaleway
- Get inventory hosts from Scaleway.
options:
plugin:
description: token that ensures this is a source file for the 'scaleway' plugin.
description: Token that ensures this is a source file for the 'scaleway' plugin.
required: True
choices: ['scaleway', 'community.general.scaleway']
regions:
description: Filter results on a specific Scaleway region
description: Filter results on a specific Scaleway region.
type: list
default:
- ams1
@@ -26,11 +26,13 @@ DOCUMENTATION = '''
- par2
- waw1
tags:
description: Filter results on a specific tag
description: Filter results on a specific tag.
type: list
oauth_token:
required: True
description: Scaleway OAuth token.
description:
- Scaleway OAuth token.
- More details on L(how to generate token, https://www.scaleway.com/en/docs/generate-api-keys/).
env:
# in order of precedence
- name: SCW_TOKEN
@@ -48,14 +50,14 @@ DOCUMENTATION = '''
- hostname
- id
variables:
description: 'set individual variables: keys are variable names and
description: 'Set individual variables: keys are variable names and
values are templates. Any value returned by the
L(Scaleway API, https://developer.scaleway.com/#servers-server-get)
can be used.'
type: dict
'''
EXAMPLES = '''
EXAMPLES = r'''
# scaleway_inventory.yml file in YAML format
# Example command line: ansible-inventory --list -i scaleway_inventory.yml
@@ -81,6 +83,15 @@ regions:
- par1
variables:
ansible_host: public_ip.address
# Using static strings as variables
plugin: community.general.scaleway
hostnames:
- hostname
variables:
ansible_host: public_ip.address
ansible_connection: "'ssh'"
ansible_user: "'admin'"
'''
import json
@@ -89,7 +100,7 @@ from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, parse_pagination_link
from ansible.module_utils.urls import open_url
from ansible.module_utils._text import to_native
from ansible.module_utils._text import to_native, to_text
import ansible.module_utils.six.moves.urllib.parse as urllib_parse
@@ -105,7 +116,7 @@ def _fetch_information(token, url):
except Exception as e:
raise AnsibleError("Error while fetching %s: %s" % (url, to_native(e)))
try:
raw_json = json.loads(response.read())
raw_json = json.loads(to_text(response.read()))
except ValueError:
raise AnsibleError("Incorrect JSON payload")
@@ -230,8 +241,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if not matching_tags:
return set()
else:
return matching_tags.union((server_zone,))
return matching_tags.union((server_zone,))
def _filter_host(self, host_infos, hostname_preferences):

View File

@@ -1,208 +0,0 @@
# (c) 2015-2021, Felix Fontein <felix@fontein.de>
# (c) 2018 Ansible Project
# 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
DOCUMENTATION = """
name: dependent
short_description: Composes a list with nested elements of other lists or dicts which can depend on previous loop variables
version_added: 3.1.0
description:
- "Takes the input lists and returns a list with elements that are lists, dictionaries,
or template expressions which evaluate to lists or dicts, composed of the elements of
the input evaluated lists and dictionaries."
options:
_raw:
description:
- A list where the elements are one-element dictionaries, mapping a name to a string, list, or dictionary.
The name is the index that is used in the result object. The value is iterated over as described below.
- If the value is a list, it is simply iterated over.
- If the value is a dictionary, it is iterated over and returned as if they would be processed by the
R(ansible.builtin.dict2items filter,ansible_collections.ansible.builtin.dict2items_filter).
- If the value is a string, it is evaluated as Jinja2 expressions which can access the previously chosen
elements with C(item.<index_name>). The result must be a list or a dictionary.
type: list
elements: dict
required: true
"""
EXAMPLES = """
- name: Install/remove public keys for active admin users
ansible.posix.authorized_key:
user: "{{ item.admin.key }}"
key: "{{ lookup('file', item.key.public_key) }}"
state: "{{ 'present' if item.key.active else 'absent' }}"
when: item.admin.value.active
with_community.general.dependent:
- admin: admin_user_data
- key: admin_ssh_keys[item.admin.key]
loop_control:
# Makes the output readable, so that it doesn't contain the whole subdictionaries and lists
label: "{{ [item.admin.key, 'active' if item.key.active else 'inactive', item.key.public_key] }}"
vars:
admin_user_data:
admin1:
name: Alice
active: true
admin2:
name: Bob
active: true
admin_ssh_keys:
admin1:
- private_key: keys/private_key_admin1.pem
public_key: keys/private_key_admin1.pub
active: true
admin2:
- private_key: keys/private_key_admin2.pem
public_key: keys/private_key_admin2.pub
active: true
- private_key: keys/private_key_admin2-old.pem
public_key: keys/private_key_admin2-old.pub
active: false
- name: Update DNS records
community.aws.route53:
zone: "{{ item.zone.key }}"
record: "{{ item.prefix.key ~ '.' if item.prefix.key else '' }}{{ item.zone.key }}"
type: "{{ item.entry.key }}"
ttl: "{{ item.entry.value.ttl | default(3600) }}"
value: "{{ item.entry.value.value }}"
state: "{{ 'absent' if (item.entry.value.absent | default(False)) else 'present' }}"
overwrite: true
loop_control:
# Makes the output readable, so that it doesn't contain the whole subdictionaries and lists
label: |-
{{ [item.zone.key, item.prefix.key, item.entry.key,
item.entry.value.ttl | default(3600),
item.entry.value.absent | default(False), item.entry.value.value] }}
with_community.general.dependent:
- zone: dns_setup
- prefix: item.zone.value
- entry: item.prefix.value
vars:
dns_setup:
example.com:
'':
A:
value:
- 1.2.3.4
AAAA:
value:
- "2a01:1:2:3::1"
'test._domainkey':
TXT:
ttl: 300
value:
- '"k=rsa; t=s; p=MIGfMA..."'
example.org:
'www':
A:
value:
- 1.2.3.4
- 5.6.7.8
"""
RETURN = """
_list:
description:
- A list composed of dictionaries whose keys are the variable names from the input list.
type: list
elements: dict
sample:
- key1: a
key2: test
- key1: a
key2: foo
- key1: b
key2: bar
"""
from ansible.errors import AnsibleLookupError
from ansible.module_utils.common._collections_compat import Mapping, Sequence
from ansible.module_utils.six import string_types
from ansible.plugins.lookup import LookupBase
from ansible.template import Templar
class LookupModule(LookupBase):
def __evaluate(self, expression, templar, variables):
"""Evaluate expression with templar.
``expression`` is the expression to evaluate.
``variables`` are the variables to use.
"""
templar.available_variables = variables or {}
return templar.template("{0}{1}{2}".format("{{", expression, "}}"), cache=False)
def __process(self, result, terms, index, current, templar, variables):
"""Fills ``result`` list with evaluated items.
``result`` is a list where the resulting items are placed.
``terms`` is the parsed list of terms
``index`` is the current index to be processed in the list.
``current`` is a dictionary where the first ``index`` values are filled in.
``variables`` are the variables currently available.
"""
# If we are done, add to result list:
if index == len(terms):
result.append(current.copy())
return
key, expression, values = terms[index]
if expression is not None:
# Evaluate expression in current context
vars = variables.copy()
vars['item'] = current.copy()
try:
values = self.__evaluate(expression, templar, variables=vars)
except Exception as e:
raise AnsibleLookupError(
'Caught "{error}" while evaluating {key!r} with item == {item!r}'.format(
error=e, key=key, item=current))
if isinstance(values, Mapping):
for idx, val in sorted(values.items()):
current[key] = dict([('key', idx), ('value', val)])
self.__process(result, terms, index + 1, current, templar, variables)
elif isinstance(values, Sequence):
for elt in values:
current[key] = elt
self.__process(result, terms, index + 1, current, templar, variables)
else:
raise AnsibleLookupError(
'Did not obtain dictionary or list while evaluating {key!r} with item == {item!r}, but {type}'.format(
key=key, item=current, type=type(values)))
def run(self, terms, variables=None, **kwargs):
"""Generate list."""
result = []
if len(terms) > 0:
templar = Templar(loader=self._templar._loader)
data = []
vars_so_far = set()
for index, term in enumerate(terms):
if not isinstance(term, Mapping):
raise AnsibleLookupError(
'Parameter {index} must be a dictionary, got {type}'.format(
index=index, type=type(term)))
if len(term) != 1:
raise AnsibleLookupError(
'Parameter {index} must be a one-element dictionary, got {count} elements'.format(
index=index, count=len(term)))
k, v = list(term.items())[0]
if k in vars_so_far:
raise AnsibleLookupError(
'The variable {key!r} appears more than once'.format(key=k))
vars_so_far.add(k)
if isinstance(v, string_types):
data.append((k, v, None))
elif isinstance(v, (Sequence, Mapping)):
data.append((k, None, v))
else:
raise AnsibleLookupError(
'Parameter {key!r} (index {index}) must have a value of type string, dictionary or list, got type {type}'.format(
index=index, key=k, type=type(v)))
self.__process(result, data, 0, {}, templar, variables)
return result

View File

@@ -25,10 +25,6 @@ DOCUMENTATION = '''
author: Unknown (!UNKNOWN)
name: nios
short_description: Query Infoblox NIOS objects
deprecated:
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
alternative: infoblox.nios_modules.nios_lookup
removed_in: 5.0.0
description:
- Uses the Infoblox WAPI API to fetch NIOS specified objects. This lookup
supports adding additional keywords to filter the return data and specify

View File

@@ -25,10 +25,6 @@ DOCUMENTATION = '''
author: Unknown (!UNKNOWN)
name: nios_next_ip
short_description: Return the next available IP address for a network
deprecated:
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
alternative: infoblox.nios_modules.nios_next_ip
removed_in: 5.0.0
description:
- Uses the Infoblox WAPI API to return the next available IP addresses
for a given network CIDR

View File

@@ -25,10 +25,6 @@ DOCUMENTATION = '''
author: Unknown (!UNKNOWN)
name: nios_next_network
short_description: Return the next available network range for a network-container
deprecated:
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
alternative: infoblox.nios_modules.nios_next_network
removed_in: 5.0.0
description:
- Uses the Infoblox WAPI API to return the next available network addresses for
a given network CIDR

View File

@@ -30,11 +30,6 @@ DOCUMENTATION = '''
aliases: ['vault_password']
section:
description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
domain:
description: Domain of 1Password. Default is U(1password.com).
version_added: 3.2.0
default: '1password.com'
type: str
subdomain:
description: The 1Password subdomain to authenticate against.
username:
@@ -114,7 +109,6 @@ class OnePass(object):
self.logged_in = False
self.token = None
self.subdomain = None
self.domain = None
self.username = None
self.secret_key = None
self.master_password = None
@@ -174,7 +168,7 @@ class OnePass(object):
args = [
'signin',
'{0}.{1}'.format(self.subdomain, self.domain),
'{0}.1password.com'.format(self.subdomain),
to_bytes(self.username),
to_bytes(self.secret_key),
'--output=raw',
@@ -271,7 +265,6 @@ class LookupModule(LookupBase):
section = kwargs.get('section')
vault = kwargs.get('vault')
op.subdomain = kwargs.get('subdomain')
op.domain = kwargs.get('domain', '1password.com')
op.username = kwargs.get('username')
op.secret_key = kwargs.get('secret_key')
op.master_password = kwargs.get('master_password', kwargs.get('vault_password'))

View File

@@ -25,9 +25,9 @@ DOCUMENTATION = '''
env:
- name: PASSWORD_STORE_DIR
create:
description: Create the password if it does not already exist. Takes precedence over C(missing).
description: Create the password if it does not already exist.
type: bool
default: false
default: 'no'
overwrite:
description: Overwrite the password if it does already exist.
type: bool
@@ -60,22 +60,6 @@ DOCUMENTATION = '''
description: use alphanumeric characters.
type: bool
default: 'no'
missing:
description:
- List of preference about what to do if the password file is missing.
- If I(create=true), the value for this option is ignored and assumed to be C(create).
- If set to C(error), the lookup will error out if the passname does not exist.
- If set to C(create), the passname will be created with the provided length I(length) if it does not exist.
- If set to C(empty) or C(warn), will return a C(none) in case the passname does not exist.
When using C(lookup) and not C(query), this will be translated to an empty string.
version_added: 3.1.0
type: str
default: error
choices:
- error
- warn
- empty
- create
'''
EXAMPLES = """
# Debug is used for examples, BAD IDEA to show passwords on screen
@@ -83,28 +67,12 @@ EXAMPLES = """
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test')}}"
- 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: 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: 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: 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: Different size password
ansible.builtin.debug:
msg: "{{ lookup('community.general.passwordstore', 'example/test create=true length=42')}}"
@@ -143,13 +111,10 @@ import yaml
from distutils import util
from ansible.errors import AnsibleError, AnsibleAssertionError
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.utils.display import Display
from ansible.utils.encrypt import random_password
from ansible.plugins.lookup import LookupBase
from ansible import constants as C
display = Display()
# backhacked check_output with input for python 2.7
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
@@ -213,17 +178,12 @@ class LookupModule(LookupBase):
self.paramvals[key] = util.strtobool(self.paramvals[key])
except (ValueError, AssertionError) as e:
raise AnsibleError(e)
if self.paramvals['missing'] not in ['error', 'warn', 'create', 'empty']:
raise AnsibleError("{0} is not a valid option for missing".format(self.paramvals['missing']))
if not isinstance(self.paramvals['length'], int):
if self.paramvals['length'].isdigit():
self.paramvals['length'] = int(self.paramvals['length'])
else:
raise AnsibleError("{0} is not a correct value for length".format(self.paramvals['length']))
if self.paramvals['create']:
self.paramvals['missing'] = 'create'
# Collect pass environment variables from the plugin's parameters.
self.env = os.environ.copy()
@@ -264,11 +224,9 @@ class LookupModule(LookupBase):
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))
if not self.paramvals['create']:
raise AnsibleError('passname: {0} not found, use create=True'.format(self.passname))
else:
if self.paramvals['missing'] == 'warn':
display.warning('passwordstore: passname {0} not found'.format(self.passname))
return False
else:
raise AnsibleError(e)
@@ -336,7 +294,6 @@ class LookupModule(LookupBase):
'userpass': '',
'length': 16,
'backup': False,
'missing': 'error',
}
for term in terms:
@@ -347,9 +304,6 @@ class LookupModule(LookupBase):
else:
result.append(self.get_passresult())
else: # password does not exist
if self.paramvals['missing'] == 'create':
if self.paramvals['create']:
result.append(self.generate_password())
else:
result.append(None)
return result

View File

@@ -1,99 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Abhijeet Kasurde <akasurde@redhat.com>
# Copyright: (c) 2018, Ansible Project
# 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
DOCUMENTATION = r'''
name: random_pet
author:
- Abhijeet Kasurde (@Akasurde)
short_description: Generates random pet names
version_added: '3.1.0'
requirements:
- petname U(https://github.com/dustinkirkland/python-petname)
description:
- Generates random pet names that can be used as unique identifiers for the resources.
options:
words:
description:
- The number of words in the pet name.
default: 2
type: int
length:
description:
- The maximal length of every component of the pet name.
- Values below 3 will be set to 3 by petname.
default: 6
type: int
prefix:
description: A string to prefix with the name.
type: str
separator:
description: The character to separate words in the pet name.
default: "-"
type: str
'''
EXAMPLES = r'''
- name: Generate pet name
ansible.builtin.debug:
var: lookup('community.general.random_pet')
# Example result: 'loving-raptor'
- name: Generate pet name with 3 words
ansible.builtin.debug:
var: lookup('community.general.random_pet', words=3)
# Example result: 'fully-fresh-macaw'
- name: Generate pet name with separator
ansible.builtin.debug:
var: lookup('community.general.random_pet', separator="_")
# Example result: 'causal_snipe'
- name: Generate pet name with length
ansible.builtin.debug:
var: lookup('community.general.random_pet', length=7)
# Example result: 'natural-peacock'
'''
RETURN = r'''
_raw:
description: A one-element list containing a random pet name
type: list
elements: str
'''
try:
import petname
HAS_PETNAME = True
except ImportError:
HAS_PETNAME = False
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_PETNAME:
raise AnsibleError('Python petname library is required. '
'Please install using "pip install petname"')
self.set_options(var_options=variables, direct=kwargs)
words = self.get_option('words')
length = self.get_option('length')
prefix = self.get_option('prefix')
separator = self.get_option('separator')
values = petname.Generate(words=words, separator=separator, letters=length)
if prefix:
values = "%s%s%s" % (prefix, separator, values)
return [values]

View File

@@ -1,220 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Abhijeet Kasurde <akasurde@redhat.com>
# Copyright: (c) 2018, Ansible Project
# 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
DOCUMENTATION = r"""
name: random_string
author:
- Abhijeet Kasurde (@Akasurde)
short_description: Generates random string
version_added: '3.2.0'
description:
- Generates random string based upon the given constraints.
options:
length:
description: The length of the string.
default: 8
type: int
upper:
description:
- Include uppercase letters in the string.
default: true
type: bool
lower:
description:
- Include lowercase letters in the string.
default: true
type: bool
numbers:
description:
- Include numbers in the string.
default: true
type: bool
special:
description:
- Include special characters in the string.
- Special characters are taken from Python standard library C(string).
See L(the documentation of string.punctuation,https://docs.python.org/3/library/string.html#string.punctuation)
for which characters will be used.
- The choice of special characters can be changed to setting I(override_special).
default: true
type: bool
min_numeric:
description:
- Minimum number of numeric characters in the string.
- If set, overrides I(numbers=false).
default: 0
type: int
min_upper:
description:
- Minimum number of uppercase alphabets in the string.
- If set, overrides I(upper=false).
default: 0
type: int
min_lower:
description:
- Minimum number of lowercase alphabets in the string.
- If set, overrides I(lower=false).
default: 0
type: int
min_special:
description:
- Minimum number of special character in the string.
default: 0
type: int
override_special:
description:
- Overide a list of special characters to use in the string.
- If set I(min_special) should be set to a non-default value.
type: str
override_all:
description:
- Override all values of I(numbers), I(upper), I(lower), and I(special) with
the given list of characters.
type: str
base64:
description:
- Returns base64 encoded string.
type: bool
default: false
"""
EXAMPLES = r"""
- name: Generate random string
ansible.builtin.debug:
var: lookup('community.general.random_string')
# Example result: ['DeadBeeF']
- name: Generate random string with length 12
ansible.builtin.debug:
var: lookup('community.general.random_string', length=12)
# Example result: ['Uan0hUiX5kVG']
- name: Generate base64 encoded random string
ansible.builtin.debug:
var: lookup('community.general.random_string', base64=True)
# Example result: ['NHZ6eWN5Qk0=']
- name: Generate a random string with 1 lower, 1 upper, 1 number and 1 special char (atleast)
ansible.builtin.debug:
var: lookup('community.general.random_string', min_lower=1, min_upper=1, min_special=1, min_numeric=1)
# Example result: ['&Qw2|E[-']
- name: Generate a random string with all lower case characters
debug:
var: query('community.general.random_string', upper=false, numbers=false, special=false)
# Example result: ['exolxzyz']
- name: Generate random hexadecimal string
debug:
var: query('community.general.random_string', upper=false, lower=false, override_special=hex_chars, numbers=false)
vars:
hex_chars: '0123456789ABCDEF'
# Example result: ['D2A40737']
- name: Generate random hexadecimal string with override_all
debug:
var: query('community.general.random_string', override_all=hex_chars)
vars:
hex_chars: '0123456789ABCDEF'
# Example result: ['D2A40737']
"""
RETURN = r"""
_raw:
description: A one-element list containing a random string
type: list
elements: str
"""
import base64
import random
import string
from ansible.errors import AnsibleLookupError
from ansible.plugins.lookup import LookupBase
from ansible.module_utils._text import to_bytes, to_text
class LookupModule(LookupBase):
@staticmethod
def get_random(random_generator, chars, length):
if not chars:
raise AnsibleLookupError(
"Available characters cannot be None, please change constraints"
)
return "".join(random_generator.choice(chars) for dummy in range(length))
@staticmethod
def b64encode(string_value, encoding="utf-8"):
return to_text(
base64.b64encode(
to_bytes(string_value, encoding=encoding, errors="surrogate_or_strict")
)
)
def run(self, terms, variables=None, **kwargs):
number_chars = string.digits
lower_chars = string.ascii_lowercase
upper_chars = string.ascii_uppercase
special_chars = string.punctuation
random_generator = random.SystemRandom()
self.set_options(var_options=variables, direct=kwargs)
length = self.get_option("length")
base64_flag = self.get_option("base64")
override_all = self.get_option("override_all")
values = ""
available_chars_set = ""
if override_all:
# Override all the values
available_chars_set = override_all
else:
upper = self.get_option("upper")
lower = self.get_option("lower")
numbers = self.get_option("numbers")
special = self.get_option("special")
override_special = self.get_option("override_special")
if override_special:
special_chars = override_special
if upper:
available_chars_set += upper_chars
if lower:
available_chars_set += lower_chars
if numbers:
available_chars_set += number_chars
if special:
available_chars_set += special_chars
mapping = {
"min_numeric": number_chars,
"min_lower": lower_chars,
"min_upper": upper_chars,
"min_special": special_chars,
}
for m in mapping:
if self.get_option(m):
values += self.get_random(random_generator, mapping[m], self.get_option(m))
remaining_pass_len = length - len(values)
values += self.get_random(random_generator, available_chars_set, remaining_pass_len)
# Get pseudo randomization
shuffled_values = list(values)
# Randomize the order
random.shuffle(shuffled_values)
if base64_flag:
return [self.b64encode("".join(shuffled_values))]
return ["".join(shuffled_values)]

View File

@@ -48,6 +48,10 @@
# agrees to be bound by the terms and conditions of this License
# Agreement.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import os

View File

@@ -0,0 +1,871 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import inspect
import os
import time
from abc import ABCMeta, abstractmethod
from datetime import datetime
from distutils.version import LooseVersion
from ansible_collections.community.general.plugins.module_utils.cloud import CloudRetry
from ansible.module_utils.common._collections_compat import Mapping
try:
from enum import Enum # enum is a ovirtsdk4 requirement
import ovirtsdk4 as sdk
import ovirtsdk4.version as sdk_version
import ovirtsdk4.types as otypes
HAS_SDK = LooseVersion(sdk_version.VERSION) >= LooseVersion('4.3.0')
except ImportError:
HAS_SDK = False
BYTES_MAP = {
'kib': 2**10,
'mib': 2**20,
'gib': 2**30,
'tib': 2**40,
'pib': 2**50,
}
def check_sdk(module):
if not HAS_SDK:
module.fail_json(
msg='ovirtsdk4 version 4.3.0 or higher is required for this module'
)
def get_dict_of_struct(struct, connection=None, fetch_nested=False, attributes=None):
"""
Convert SDK Struct type into dictionary.
"""
res = {}
def resolve_href(value):
# Fetch nested values of struct:
try:
value = connection.follow_link(value)
except sdk.Error:
value = None
nested_obj = dict(
(attr, convert_value(getattr(value, attr)))
for attr in attributes if getattr(value, attr, None) is not None
)
nested_obj['id'] = getattr(value, 'id', None)
nested_obj['href'] = getattr(value, 'href', None)
return nested_obj
def remove_underscore(val):
if val.startswith('_'):
val = val[1:]
remove_underscore(val)
return val
def convert_value(value):
nested = False
if isinstance(value, sdk.Struct):
if not fetch_nested or not value.href:
return get_dict_of_struct(value)
return resolve_href(value)
elif isinstance(value, Enum) or isinstance(value, datetime):
return str(value)
elif isinstance(value, list) or isinstance(value, sdk.List):
if isinstance(value, sdk.List) and fetch_nested and value.href:
try:
value = connection.follow_link(value)
nested = True
except sdk.Error:
value = []
ret = []
for i in value:
if isinstance(i, sdk.Struct):
if not nested and fetch_nested and i.href:
ret.append(resolve_href(i))
elif not nested:
ret.append(get_dict_of_struct(i))
else:
nested_obj = dict(
(attr, convert_value(getattr(i, attr)))
for attr in attributes if getattr(i, attr, None)
)
nested_obj['id'] = getattr(i, 'id', None)
ret.append(nested_obj)
elif isinstance(i, Enum):
ret.append(str(i))
else:
ret.append(i)
return ret
else:
return value
if struct is not None:
for key, value in struct.__dict__.items():
if value is None:
continue
key = remove_underscore(key)
res[key] = convert_value(value)
return res
def engine_version(connection):
"""
Return string representation of oVirt engine version.
"""
engine_api = connection.system_service().get()
engine_version = engine_api.product_info.version
return '%s.%s' % (engine_version.major, engine_version.minor)
def create_connection(auth):
"""
Create a connection to Python SDK, from task `auth` parameter.
If user doesnt't have SSO token the `auth` dictionary has following parameters mandatory:
url, username, password
If user has SSO token the `auth` dictionary has following parameters mandatory:
url, token
The `ca_file` parameter is mandatory in case user want to use secure connection,
in case user want to use insecure connection, it's mandatory to send insecure=True.
:param auth: dictionary which contains needed values for connection creation
:return: Python SDK connection
"""
url = auth.get('url')
if url is None and auth.get('hostname') is not None:
url = 'https://{0}/ovirt-engine/api'.format(auth.get('hostname'))
return sdk.Connection(
url=url,
username=auth.get('username'),
password=auth.get('password'),
ca_file=auth.get('ca_file', None),
insecure=auth.get('insecure', False),
token=auth.get('token', None),
kerberos=auth.get('kerberos', None),
headers=auth.get('headers', None),
)
def convert_to_bytes(param):
"""
This method convert units to bytes, which follow IEC standard.
:param param: value to be converted
"""
if param is None:
return None
# Get rid of whitespaces:
param = ''.join(param.split())
# Convert to bytes:
if len(param) > 3 and param[-3].lower() in ['k', 'm', 'g', 't', 'p']:
return int(param[:-3]) * BYTES_MAP.get(param[-3:].lower(), 1)
elif param.isdigit():
return int(param) * 2**10
else:
raise ValueError(
"Unsupported value(IEC supported): '{value}'".format(value=param)
)
def follow_link(connection, link):
"""
This method returns the entity of the element which link points to.
:param connection: connection to the Python SDK
:param link: link of the entity
:return: entity which link points to
"""
if link:
return connection.follow_link(link)
else:
return None
def get_link_name(connection, link):
"""
This method returns the name of the element which link points to.
:param connection: connection to the Python SDK
:param link: link of the entity
:return: name of the entity, which link points to
"""
if link:
return connection.follow_link(link).name
else:
return None
def equal(param1, param2, ignore_case=False):
"""
Compare two parameters and return if they are equal.
This parameter doesn't run equal operation if first parameter is None.
With this approach we don't run equal operation in case user don't
specify parameter in their task.
:param param1: user inputted parameter
:param param2: value of entity parameter
:return: True if parameters are equal or first parameter is None, otherwise False
"""
if param1 is not None:
if ignore_case:
return param1.lower() == param2.lower()
return param1 == param2
return True
def search_by_attributes(service, list_params=None, **kwargs):
"""
Search for the entity by attributes. Nested entities don't support search
via REST, so in case using search for nested entity we return all entities
and filter them by specified attributes.
"""
list_params = list_params or {}
# Check if 'list' method support search(look for search parameter):
if 'search' in inspect.getargspec(service.list)[0]:
res = service.list(
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
search=' and '.join('{0}="{1}"'.format(k, v) for k, v in kwargs.items()),
**list_params
)
else:
res = [
e for e in service.list(**list_params) if len([
k for k, v in kwargs.items() if getattr(e, k, None) == v
]) == len(kwargs)
]
res = res or [None]
return res[0]
def search_by_name(service, name, **kwargs):
"""
Search for the entity by its name. Nested entities don't support search
via REST, so in case using search for nested entity we return all entities
and filter them by name.
:param service: service of the entity
:param name: name of the entity
:return: Entity object returned by Python SDK
"""
# Check if 'list' method support search(look for search parameter):
if 'search' in inspect.getargspec(service.list)[0]:
res = service.list(
# There must be double quotes around name, because some oVirt resources it's possible to create then with space in name.
search='name="{name}"'.format(name=name)
)
else:
res = [e for e in service.list() if e.name == name]
if kwargs:
res = [
e for e in service.list() if len([
k for k, v in kwargs.items() if getattr(e, k, None) == v
]) == len(kwargs)
]
res = res or [None]
return res[0]
def get_entity(service, get_params=None):
"""
Ignore SDK Error in case of getting an entity from service.
"""
entity = None
try:
if get_params is not None:
entity = service.get(**get_params)
else:
entity = service.get()
except sdk.Error:
# We can get here 404, we should ignore it, in case
# of removing entity for example.
pass
return entity
def get_id_by_name(service, name, raise_error=True, ignore_case=False):
"""
Search an entity ID by it's name.
"""
entity = search_by_name(service, name)
if entity is not None:
return entity.id
if raise_error:
raise Exception("Entity '%s' was not found." % name)
def wait(
service,
condition,
fail_condition=lambda e: False,
timeout=180,
wait=True,
poll_interval=3,
):
"""
Wait until entity fulfill expected condition.
:param service: service of the entity
:param condition: condition to be fulfilled
:param fail_condition: if this condition is true, raise Exception
:param timeout: max time to wait in seconds
:param wait: if True wait for condition, if False don't wait
:param poll_interval: Number of seconds we should wait until next condition check
"""
# Wait until the desired state of the entity:
if wait:
start = time.time()
while time.time() < start + timeout:
# Exit if the condition of entity is valid:
entity = get_entity(service)
if condition(entity):
return
elif fail_condition(entity):
raise Exception("Error while waiting on result state of the entity.")
# Sleep for `poll_interval` seconds if none of the conditions apply:
time.sleep(float(poll_interval))
raise Exception("Timeout exceed while waiting on result state of the entity.")
def __get_auth_dict():
OVIRT_URL = os.environ.get('OVIRT_URL')
OVIRT_HOSTNAME = os.environ.get('OVIRT_HOSTNAME')
OVIRT_USERNAME = os.environ.get('OVIRT_USERNAME')
OVIRT_PASSWORD = os.environ.get('OVIRT_PASSWORD')
OVIRT_TOKEN = os.environ.get('OVIRT_TOKEN')
OVIRT_CAFILE = os.environ.get('OVIRT_CAFILE')
OVIRT_INSECURE = OVIRT_CAFILE is None
env_vars = None
if OVIRT_URL is None and OVIRT_HOSTNAME is not None:
OVIRT_URL = 'https://{0}/ovirt-engine/api'.format(OVIRT_HOSTNAME)
if OVIRT_URL and ((OVIRT_USERNAME and OVIRT_PASSWORD) or OVIRT_TOKEN):
env_vars = {
'url': OVIRT_URL,
'username': OVIRT_USERNAME,
'password': OVIRT_PASSWORD,
'insecure': OVIRT_INSECURE,
'token': OVIRT_TOKEN,
'ca_file': OVIRT_CAFILE,
}
if env_vars is not None:
auth = dict(default=env_vars, type='dict')
else:
auth = dict(required=True, type='dict')
return auth
def ovirt_info_full_argument_spec(**kwargs):
"""
Extend parameters of info module with parameters which are common to all
oVirt info modules.
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
spec = dict(
auth=__get_auth_dict(),
fetch_nested=dict(default=False, type='bool'),
nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
# Left for third-party module compatibility
def ovirt_facts_full_argument_spec(**kwargs):
"""
This is deprecated. Please use ovirt_info_full_argument_spec instead!
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
return ovirt_info_full_argument_spec(**kwargs)
def ovirt_full_argument_spec(**kwargs):
"""
Extend parameters of module with parameters which are common to all oVirt modules.
:param kwargs: kwargs to be extended
:return: extended dictionary with common parameters
"""
spec = dict(
auth=__get_auth_dict(),
timeout=dict(default=180, type='int'),
wait=dict(default=True, type='bool'),
poll_interval=dict(default=3, type='int'),
fetch_nested=dict(default=False, type='bool'),
nested_attributes=dict(type='list', default=list()),
)
spec.update(kwargs)
return spec
def check_params(module):
"""
Most modules must have either `name` or `id` specified.
"""
if module.params.get('name') is None and module.params.get('id') is None:
module.fail_json(msg='"name" or "id" is required')
def engine_supported(connection, version):
return LooseVersion(engine_version(connection)) >= LooseVersion(version)
def check_support(version, connection, module, params):
"""
Check if parameters used by user are supported by oVirt Python SDK
and oVirt engine.
"""
api_version = LooseVersion(engine_version(connection))
version = LooseVersion(version)
for param in params:
if module.params.get(param) is not None:
return LooseVersion(sdk_version.VERSION) >= version and api_version >= version
return True
class BaseModule(object):
"""
This is base class for oVirt modules. oVirt modules should inherit this
class and override method to customize specific needs of the module.
The only abstract method of this class is `build_entity`, which must
to be implemented in child class.
"""
__metaclass__ = ABCMeta
def __init__(self, connection, module, service, changed=False):
self._connection = connection
self._module = module
self._service = service
self._changed = changed
self._diff = {'after': dict(), 'before': dict()}
@property
def changed(self):
return self._changed
@changed.setter
def changed(self, changed):
if not self._changed:
self._changed = changed
@abstractmethod
def build_entity(self):
"""
This method should return oVirt Python SDK type, which we want to
create or update, initialized by values passed by Ansible module.
For example if we want to create VM, we will return following:
types.Vm(name=self._module.params['vm_name'])
:return: Specific instance of sdk.Struct.
"""
pass
def param(self, name, default=None):
"""
Return a module parameter specified by it's name.
"""
return self._module.params.get(name, default)
def update_check(self, entity):
"""
This method handle checks whether the entity values are same as values
passed to ansible module. By default we don't compare any values.
:param entity: Entity we want to compare with Ansible module values.
:return: True if values are same, so we don't need to update the entity.
"""
return True
def pre_create(self, entity):
"""
This method is called right before entity is created.
:param entity: Entity to be created or updated.
"""
pass
def post_create(self, entity):
"""
This method is called right after entity is created.
:param entity: Entity which was created.
"""
pass
def post_update(self, entity):
"""
This method is called right after entity is updated.
:param entity: Entity which was updated.
"""
pass
def diff_update(self, after, update):
for k, v in update.items():
if isinstance(v, Mapping):
after[k] = self.diff_update(after.get(k, dict()), v)
else:
after[k] = update[k]
return after
def create(
self,
entity=None,
result_state=None,
fail_condition=lambda e: False,
search_params=None,
update_params=None,
_wait=None,
force_create=False,
**kwargs
):
"""
Method which is called when state of the entity is 'present'. If user
don't provide `entity` parameter the entity is searched using
`search_params` parameter. If entity is found it's updated, whether
the entity should be updated is checked by `update_check` method.
The corresponding updated entity is build by `build_entity` method.
Function executed after entity is created can optionally be specified
in `post_create` parameter. Function executed after entity is updated
can optionally be specified in `post_update` parameter.
:param entity: Entity we want to update, if exists.
:param result_state: State which should entity has in order to finish task.
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
:param search_params: Dictionary of parameters to be used for search.
:param update_params: The params which should be passed to update method.
:param kwargs: Additional parameters passed when creating entity.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None and not force_create:
entity = self.search_entity(search_params)
self.pre_create(entity)
if entity:
# Entity exists, so update it:
entity_service = self._service.service(entity.id)
if not self.update_check(entity):
new_entity = self.build_entity()
if not self._module.check_mode:
update_params = update_params or {}
updated_entity = entity_service.update(
new_entity,
**update_params
)
self.post_update(entity)
# Update diffs only if user specified --diff parameter,
# so we don't useless overload API:
if self._module._diff:
before = get_dict_of_struct(
entity,
self._connection,
fetch_nested=True,
attributes=['name'],
)
after = before.copy()
self.diff_update(after, get_dict_of_struct(new_entity))
self._diff['before'] = before
self._diff['after'] = after
self.changed = True
else:
# Entity don't exists, so create it:
if not self._module.check_mode:
entity = self._service.add(
self.build_entity(),
**kwargs
)
self.post_create(entity)
self.changed = True
if not self._module.check_mode:
# Wait for the entity to be created and to be in the defined state:
entity_service = self._service.service(entity.id)
def state_condition(entity):
return entity
if result_state:
def state_condition(entity):
return entity and entity.status == result_state
wait(
service=entity_service,
condition=state_condition,
fail_condition=fail_condition,
wait=_wait if _wait is not None else self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
return {
'changed': self.changed,
'id': getattr(entity, 'id', None),
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
'diff': self._diff,
}
def pre_remove(self, entity):
"""
This method is called right before entity is removed.
:param entity: Entity which we want to remove.
"""
pass
def entity_name(self, entity):
return "{e_type} '{e_name}'".format(
e_type=type(entity).__name__.lower(),
e_name=getattr(entity, 'name', None),
)
def remove(self, entity=None, search_params=None, **kwargs):
"""
Method which is called when state of the entity is 'absent'. If user
don't provide `entity` parameter the entity is searched using
`search_params` parameter. If entity is found it's removed.
Function executed before remove is executed can optionally be specified
in `pre_remove` parameter.
:param entity: Entity we want to remove.
:param search_params: Dictionary of parameters to be used for search.
:param kwargs: Additional parameters passed when removing entity.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None:
entity = self.search_entity(search_params)
if entity is None:
return {
'changed': self.changed,
'msg': "Entity wasn't found."
}
self.pre_remove(entity)
entity_service = self._service.service(entity.id)
if not self._module.check_mode:
entity_service.remove(**kwargs)
wait(
service=entity_service,
condition=lambda entity: not entity,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
self.changed = True
return {
'changed': self.changed,
'id': entity.id,
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
}
def action(
self,
action,
entity=None,
action_condition=lambda e: e,
wait_condition=lambda e: e,
fail_condition=lambda e: False,
pre_action=lambda e: e,
post_action=lambda e: None,
search_params=None,
**kwargs
):
"""
This method is executed when we want to change the state of some oVirt
entity. The action to be executed on oVirt service is specified by
`action` parameter. Whether the action should be executed can be
specified by passing `action_condition` parameter. State which the
entity should be in after execution of the action can be specified
by `wait_condition` parameter.
Function executed before an action on entity can optionally be specified
in `pre_action` parameter. Function executed after an action on entity can
optionally be specified in `post_action` parameter.
:param action: Action which should be executed by service on entity.
:param entity: Entity we want to run action on.
:param action_condition: Function which is executed when checking if action should be executed.
:param fail_condition: Function which checks incorrect state of entity, if it returns `True` Exception is raised.
:param wait_condition: Function which is executed when waiting on result state.
:param pre_action: Function which is executed before running the action.
:param post_action: Function which is executed after running the action.
:param search_params: Dictionary of parameters to be used for search.
:param kwargs: Additional parameters passed to action.
:return: Dictionary with values returned by Ansible module.
"""
if entity is None:
entity = self.search_entity(search_params)
entity = pre_action(entity)
if entity is None:
self._module.fail_json(
msg="Entity not found, can't run action '{0}'.".format(
action
)
)
entity_service = self._service.service(entity.id)
entity = entity_service.get()
if action_condition(entity):
if not self._module.check_mode:
getattr(entity_service, action)(**kwargs)
self.changed = True
post_action(entity)
wait(
service=self._service.service(entity.id),
condition=wait_condition,
fail_condition=fail_condition,
wait=self._module.params['wait'],
timeout=self._module.params['timeout'],
poll_interval=self._module.params['poll_interval'],
)
return {
'changed': self.changed,
'id': entity.id,
type(entity).__name__.lower(): get_dict_of_struct(
struct=entity,
connection=self._connection,
fetch_nested=self._module.params.get('fetch_nested'),
attributes=self._module.params.get('nested_attributes'),
),
'diff': self._diff,
}
def wait_for_import(self, condition=lambda e: True):
if self._module.params['wait']:
start = time.time()
timeout = self._module.params['timeout']
poll_interval = self._module.params['poll_interval']
while time.time() < start + timeout:
entity = self.search_entity()
if entity and condition(entity):
return entity
time.sleep(poll_interval)
def search_entity(self, search_params=None, list_params=None):
"""
Always first try to search by `ID`, if ID isn't specified,
check if user constructed special search in `search_params`,
if not search by `name`.
"""
entity = None
if 'id' in self._module.params and self._module.params['id'] is not None:
entity = get_entity(self._service.service(self._module.params['id']), get_params=list_params)
elif search_params is not None:
entity = search_by_attributes(self._service, list_params=list_params, **search_params)
elif self._module.params.get('name') is not None:
entity = search_by_attributes(self._service, list_params=list_params, name=self._module.params['name'])
return entity
def _get_major(self, full_version):
if full_version is None or full_version == "":
return None
if isinstance(full_version, otypes.Version):
return int(full_version.major)
return int(full_version.split('.')[0])
def _get_minor(self, full_version):
if full_version is None or full_version == "":
return None
if isinstance(full_version, otypes.Version):
return int(full_version.minor)
return int(full_version.split('.')[1])
def _sdk4_error_maybe():
"""
Allow for ovirtsdk4 not being installed.
"""
if HAS_SDK:
return sdk.Error
return type(None)
class OvirtRetry(CloudRetry):
base_class = _sdk4_error_maybe()
@staticmethod
def status_code_from_exception(error):
return error.code
@staticmethod
def found(response_code, catch_extra_error_codes=None):
# This is a list of error codes to retry.
retry_on = [
# HTTP status: Conflict
409,
]
if catch_extra_error_codes:
retry_on.extend(catch_extra_error_codes)
return response_code in retry_on

View File

@@ -30,16 +30,12 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
import traceback
from ansible.module_utils.urls import open_url
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.six.moves.urllib.error import HTTPError
from ansible.module_utils._text import to_native
URL_REALMS = "{url}/admin/realms"
URL_REALM = "{url}/admin/realms/{realm}"
URL_TOKEN = "{url}/realms/{realm}/protocol/openid-connect/token"
URL_CLIENT = "{url}/admin/realms/{realm}/clients/{id}"
URL_CLIENTS = "{url}/admin/realms/{realm}/clients"
@@ -61,12 +57,11 @@ def keycloak_argument_spec():
return dict(
auth_keycloak_url=dict(type='str', aliases=['url'], required=True, no_log=False),
auth_client_id=dict(type='str', default='admin-cli'),
auth_realm=dict(type='str'),
auth_realm=dict(type='str', required=True),
auth_client_secret=dict(type='str', default=None, no_log=True),
auth_username=dict(type='str', aliases=['username']),
auth_password=dict(type='str', aliases=['password'], no_log=True),
validate_certs=dict(type='bool', default=True),
token=dict(type='str', no_log=True),
auth_username=dict(type='str', aliases=['username'], required=True),
auth_password=dict(type='str', aliases=['password'], required=True, no_log=True),
validate_certs=dict(type='bool', default=True)
)
@@ -78,58 +73,41 @@ class KeycloakError(Exception):
pass
def get_token(module_params):
""" Obtains connection header with token for the authentication,
token already given or obtained from credentials
:param module_params: parameters of the module
:return: connection header
"""
token = module_params.get('token')
base_url = module_params.get('auth_keycloak_url')
def get_token(base_url, validate_certs, auth_realm, client_id,
auth_username, auth_password, client_secret):
if not base_url.lower().startswith(('http', 'https')):
raise KeycloakError("auth_url '%s' should either start with 'http' or 'https'." % base_url)
if token is None:
base_url = module_params.get('auth_keycloak_url')
validate_certs = module_params.get('validate_certs')
auth_realm = module_params.get('auth_realm')
client_id = module_params.get('auth_client_id')
auth_username = module_params.get('auth_username')
auth_password = module_params.get('auth_password')
client_secret = module_params.get('auth_client_secret')
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
temp_payload = {
'grant_type': 'password',
'client_id': client_id,
'client_secret': client_secret,
'username': auth_username,
'password': auth_password,
}
# Remove empty items, for instance missing client_secret
payload = dict(
(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,
data=urlencode(payload)).read()))
except ValueError as e:
raise KeycloakError(
'API returned invalid JSON when trying to obtain access token from %s: %s'
% (auth_url, str(e)))
except Exception as e:
raise KeycloakError('Could not obtain access token from %s: %s'
% (auth_url, str(e)))
try:
token = r['access_token']
except KeyError:
raise KeycloakError(
'Could not obtain access token from %s' % auth_url)
return {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json'
auth_url = URL_TOKEN.format(url=base_url, realm=auth_realm)
temp_payload = {
'grant_type': 'password',
'client_id': client_id,
'client_secret': client_secret,
'username': auth_username,
'password': auth_password,
}
# Remove empty items, for instance missing client_secret
payload = dict(
(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,
data=urlencode(payload)).read()))
except ValueError as e:
raise KeycloakError(
'API returned invalid JSON when trying to obtain access token from %s: %s'
% (auth_url, str(e)))
except Exception as e:
raise KeycloakError('Could not obtain access token from %s: %s'
% (auth_url, str(e)))
try:
return {
'Authorization': 'Bearer ' + r['access_token'],
'Content-Type': 'application/json'
}
except KeyError:
raise KeycloakError(
'Could not obtain access token from %s' % auth_url)
class KeycloakAPI(object):
@@ -142,75 +120,6 @@ class KeycloakAPI(object):
self.validate_certs = self.module.params.get('validate_certs')
self.restheaders = connection_header
def get_realm_by_id(self, realm='master'):
""" Obtain realm representation by id
:param realm: realm id
:return: dict of real, representation or None if none matching exist
"""
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,
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 update_realm(self, realmrep, realm="master"):
""" Update an existing realm
:param realmrep: corresponding (partial/full) realm representation with updates
:param realm: realm to be updated in Keycloak
:return: HTTPResponse object on success
"""
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
try:
return open_url(realm_url, method='PUT', headers=self.restheaders,
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)),
exception=traceback.format_exc())
def create_realm(self, realmrep):
""" Create a realm in keycloak
:param realmrep: Realm representation of realm to be created.
:return: HTTPResponse object on success
"""
realm_url = URL_REALMS.format(url=self.baseurl)
try:
return open_url(realm_url, method='POST', headers=self.restheaders,
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)),
exception=traceback.format_exc())
def delete_realm(self, realm="master"):
""" Delete a realm from Keycloak
:param realm: realm to be deleted
:return: HTTPResponse object on success
"""
realm_url = URL_REALM.format(url=self.baseurl, realm=realm)
try:
return open_url(realm_url, method='DELETE', headers=self.restheaders,
validate_certs=self.validate_certs)
except Exception as e:
self.module.fail_json(msg='Could not delete realm %s: %s' % (realm, str(e)),
exception=traceback.format_exc())
def get_clients(self, realm='master', filter=None):
""" Obtains client representations for clients in a realm

View File

@@ -1,62 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException as _MHE
from ansible_collections.community.general.plugins.module_utils.mh.deco import module_fails_on_exception
class ModuleHelperBase(object):
module = None
ModuleHelperException = _MHE
def __init__(self, module=None):
self._changed = False
if module:
self.module = module
if not isinstance(self.module, AnsibleModule):
self.module = AnsibleModule(**self.module)
def __init_module__(self):
pass
def __run__(self):
raise NotImplementedError()
def __quit_module__(self):
pass
def __changed__(self):
raise NotImplementedError()
@property
def changed(self):
try:
return self.__changed__()
except NotImplementedError:
return self._changed
@changed.setter
def changed(self, value):
self._changed = value
def has_changed(self):
raise NotImplementedError()
@property
def output(self):
raise NotImplementedError()
@module_fails_on_exception
def run(self):
self.__init_module__()
self.__run__()
self.__quit_module__()
self.module.exit_json(changed=self.has_changed(), **self.output)

View File

@@ -1,54 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import traceback
from functools import wraps
from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException
def cause_changes(on_success=None, on_failure=None):
def deco(func):
if on_success is None and on_failure is None:
return func
@wraps(func)
def wrapper(*args, **kwargs):
try:
self = args[0]
func(*args, **kwargs)
if on_success is not None:
self.changed = on_success
except Exception:
if on_failure is not None:
self.changed = on_failure
raise
return wrapper
return deco
def module_fails_on_exception(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
try:
func(self, *args, **kwargs)
except SystemExit:
raise
except ModuleHelperException as e:
if e.update_output:
self.update_output(e.update_output)
self.module.fail_json(msg=e.msg, exception=traceback.format_exc(),
output=self.output, vars=self.vars.output(), **self.output)
except Exception as e:
msg = "Module failed with exception: {0}".format(str(e).strip())
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
output=self.output, vars=self.vars.output(), **self.output)
return wrapper

View File

@@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class ModuleHelperException(Exception):
@staticmethod
def _get_remove(key, kwargs):
if key in kwargs:
result = kwargs[key]
del kwargs[key]
return result
return None
def __init__(self, *args, **kwargs):
self.msg = self._get_remove('msg', kwargs) or "Module failed with exception: {0}".format(self)
self.update_output = self._get_remove('update_output', kwargs) or {}
super(ModuleHelperException, self).__init__(*args)

View File

@@ -1,175 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from functools import partial
class ArgFormat(object):
"""
Argument formatter for use as a command line parameter. Used in CmdMixin.
"""
BOOLEAN = 0
PRINTF = 1
FORMAT = 2
@staticmethod
def stars_deco(num):
if num == 1:
def deco(f):
return lambda v: f(*v)
return deco
elif num == 2:
def deco(f):
return lambda v: f(**v)
return deco
return lambda f: f
def __init__(self, name, fmt=None, style=FORMAT, stars=0):
"""
Creates a CLI-formatter for one specific argument. The argument may be a module parameter or just a named parameter for
the CLI command execution.
:param name: Name of the argument to be formatted
:param fmt: Either a str to be formatted (using or not printf-style) or a callable that does that
:param style: Whether arg_format (as str) should use printf-style formatting.
Ignored if arg_format is None or not a str (should be callable).
:param stars: A int with 0, 1 or 2 value, indicating to formatting the value as: value, *value or **value
"""
def printf_fmt(_fmt, v):
try:
return [_fmt % v]
except TypeError as e:
if e.args[0] != 'not all arguments converted during string formatting':
raise
return [_fmt]
_fmts = {
ArgFormat.BOOLEAN: lambda _fmt, v: ([_fmt] if bool(v) else []),
ArgFormat.PRINTF: printf_fmt,
ArgFormat.FORMAT: lambda _fmt, v: [_fmt.format(v)],
}
self.name = name
self.stars = stars
if fmt is None:
fmt = "{0}"
style = ArgFormat.FORMAT
if isinstance(fmt, str):
func = _fmts[style]
self.arg_format = partial(func, fmt)
elif isinstance(fmt, list) or isinstance(fmt, tuple):
self.arg_format = lambda v: [_fmts[style](f, v)[0] for f in fmt]
elif hasattr(fmt, '__call__'):
self.arg_format = fmt
else:
raise TypeError('Parameter fmt must be either: a string, a list/tuple of '
'strings or a function: type={0}, value={1}'.format(type(fmt), fmt))
if stars:
self.arg_format = (self.stars_deco(stars))(self.arg_format)
def to_text(self, value):
if value is None:
return []
func = self.arg_format
return [str(p) for p in func(value)]
class CmdMixin(object):
"""
Mixin for mapping module options to running a CLI command with its arguments.
"""
command = None
command_args_formats = {}
run_command_fixed_options = {}
check_rc = False
force_lang = "C"
@property
def module_formats(self):
result = {}
for param in self.module.params.keys():
result[param] = ArgFormat(param)
return result
@property
def custom_formats(self):
result = {}
for param, fmt_spec in self.command_args_formats.items():
result[param] = ArgFormat(param, **fmt_spec)
return result
def _calculate_args(self, extra_params=None, params=None):
def add_arg_formatted_param(_cmd_args, arg_format, _value):
args = list(arg_format.to_text(_value))
return _cmd_args + args
def find_format(_param):
return self.custom_formats.get(_param, self.module_formats.get(_param))
extra_params = extra_params or dict()
cmd_args = list([self.command]) if isinstance(self.command, str) else list(self.command)
try:
cmd_args[0] = self.module.get_bin_path(cmd_args[0], required=True)
except ValueError:
pass
param_list = params if params else self.vars.keys()
for param in param_list:
if isinstance(param, dict):
if len(param) != 1:
raise self.ModuleHelperException("run_command parameter as a dict must "
"contain only one key: {0}".format(param))
_param = list(param.keys())[0]
fmt = find_format(_param)
value = param[_param]
elif isinstance(param, str):
if param in self.vars.keys():
fmt = find_format(param)
value = self.vars[param]
elif param in extra_params:
fmt = find_format(param)
value = extra_params[param]
else:
self.module.deprecate("Cannot determine value for parameter: {0}. "
"From version 4.0.0 onwards this will generate an exception".format(param),
version="4.0.0", collection_name="community.general")
continue
else:
raise self.ModuleHelperException("run_command parameter must be either a str or a dict: {0}".format(param))
cmd_args = add_arg_formatted_param(cmd_args, fmt, value)
return cmd_args
def process_command_output(self, rc, out, err):
return rc, out, err
def run_command(self, extra_params=None, params=None, process_output=None, *args, **kwargs):
self.vars.cmd_args = self._calculate_args(extra_params, params)
options = dict(self.run_command_fixed_options)
options['check_rc'] = options.get('check_rc', self.check_rc)
options.update(kwargs)
env_update = dict(options.get('environ_update', {}))
if self.force_lang:
env_update.update({
'LANGUAGE': self.force_lang,
'LC_ALL': self.force_lang,
})
self.update_output(force_lang=self.force_lang)
options['environ_update'] = env_update
rc, out, err = self.module.run_command(self.vars.cmd_args, *args, **options)
self.update_output(rc=rc, stdout=out, stderr=err)
if process_output is None:
_process = self.process_command_output
else:
_process = process_output
return _process(rc, out, err)

View File

@@ -1,58 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import traceback
from ansible_collections.community.general.plugins.module_utils.mh.base import ModuleHelperBase
from ansible_collections.community.general.plugins.module_utils.mh.deco import module_fails_on_exception
class DependencyCtxMgr(object):
def __init__(self, name, msg=None):
self.name = name
self.msg = msg
self.has_it = False
self.exc_type = None
self.exc_val = None
self.exc_tb = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.has_it = exc_type is None
self.exc_type = exc_type
self.exc_val = exc_val
self.exc_tb = exc_tb
return not self.has_it
@property
def text(self):
return self.msg or str(self.exc_val)
class DependencyMixin(ModuleHelperBase):
_dependencies = []
@classmethod
def dependency(cls, name, msg):
cls._dependencies.append(DependencyCtxMgr(name, msg))
return cls._dependencies[-1]
def fail_on_missing_deps(self):
for d in self._dependencies:
if not d.has_it:
self.module.fail_json(changed=False,
exception="\n".join(traceback.format_exception(d.exc_type, d.exc_val, d.exc_tb)),
msg=d.text,
**self.output)
@module_fails_on_exception
def run(self):
self.fail_on_missing_deps()
super(DependencyMixin, self).run()

View File

@@ -1,39 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class StateMixin(object):
state_param = 'state'
default_state = None
def _state(self):
state = self.module.params.get(self.state_param)
return self.default_state if state is None else state
def _method(self, state):
return "{0}_{1}".format(self.state_param, state)
def __run__(self):
state = self._state()
self.vars.state = state
# resolve aliases
if state not in self.module.params:
aliased = [name for name, param in self.module.argument_spec.items() if state in param.get('aliases', [])]
if aliased:
state = aliased[0]
self.vars.effective_state = state
method = self._method(state)
if not hasattr(self, method):
return self.__state_fallback__()
func = getattr(self, method)
return func()
def __state_fallback__(self):
raise ValueError("Cannot find method: {0}".format(self._method(self._state())))

View File

@@ -1,132 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
class VarMeta(object):
NOTHING = object()
def __init__(self, diff=False, output=True, change=None, fact=False):
self.init = False
self.initial_value = None
self.value = None
self.diff = diff
self.change = diff if change is None else change
self.output = output
self.fact = fact
def set(self, diff=None, output=None, change=None, fact=None, initial_value=NOTHING):
if diff is not None:
self.diff = diff
if output is not None:
self.output = output
if change is not None:
self.change = change
if fact is not None:
self.fact = fact
if initial_value is not self.NOTHING:
self.initial_value = initial_value
def set_value(self, value):
if not self.init:
self.initial_value = value
self.init = True
self.value = value
return self
@property
def has_changed(self):
return self.change and (self.initial_value != self.value)
@property
def diff_result(self):
return None if not (self.diff and self.has_changed) else {
'before': self.initial_value,
'after': self.value,
}
def __str__(self):
return "<VarMeta: value={0}, initial={1}, diff={2}, output={3}, change={4}>".format(
self.value, self.initial_value, self.diff, self.output, self.change
)
class VarDict(object):
def __init__(self):
self._data = dict()
self._meta = dict()
def __getitem__(self, item):
return self._data[item]
def __setitem__(self, key, value):
self.set(key, value)
def __getattr__(self, item):
try:
return self._data[item]
except KeyError:
return getattr(self._data, item)
def __setattr__(self, key, value):
if key in ('_data', '_meta'):
super(VarDict, self).__setattr__(key, value)
else:
self.set(key, value)
def meta(self, name):
return self._meta[name]
def set_meta(self, name, **kwargs):
self.meta(name).set(**kwargs)
def set(self, name, value, **kwargs):
if name in ('_data', '_meta'):
raise ValueError("Names _data and _meta are reserved for use by ModuleHelper")
self._data[name] = value
if name in self._meta:
meta = self.meta(name)
else:
meta = VarMeta(**kwargs)
meta.set_value(value)
self._meta[name] = meta
def output(self):
return dict((k, v) for k, v in self._data.items() if self.meta(k).output)
def diff(self):
diff_results = [(k, self.meta(k).diff_result) for k in self._data]
diff_results = [dr for dr in diff_results if dr[1] is not None]
if diff_results:
before = dict((dr[0], dr[1]['before']) for dr in diff_results)
after = dict((dr[0], dr[1]['after']) for dr in diff_results)
return {'before': before, 'after': after}
return None
def facts(self):
facts_result = dict((k, v) for k, v in self._data.items() if self._meta[k].fact)
return facts_result if facts_result else None
def change_vars(self):
return [v for v in self._data if self.meta(v).change]
def has_changed(self, v):
return self._meta[v].has_changed
class VarsMixin(object):
def __init__(self, module=None):
self.vars = VarDict()
super(VarsMixin, self).__init__(module)
def update_vars(self, meta=None, **kwargs):
if meta is None:
meta = {}
for k, v in kwargs.items():
self.vars.set(k, v, **meta)

View File

@@ -1,79 +0,0 @@
# -*- coding: utf-8 -*-
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
# Copyright: (c) 2020, Ansible Project
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.common.dict_transformations import dict_merge
from ansible_collections.community.general.plugins.module_utils.mh.base import ModuleHelperBase, AnsibleModule
from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd import CmdMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarsMixin, VarDict as _VD
class ModuleHelper(VarsMixin, DependencyMixin, ModuleHelperBase):
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
facts_name = None
output_params = ()
diff_params = ()
change_params = ()
facts_params = ()
VarDict = _VD # for backward compatibility, will be deprecated at some point
def __init__(self, module=None):
super(ModuleHelper, self).__init__(module)
for name, value in self.module.params.items():
self.vars.set(
name, value,
diff=name in self.diff_params,
output=name in self.output_params,
change=None if not self.change_params else name in self.change_params,
fact=name in self.facts_params,
)
def update_output(self, **kwargs):
self.update_vars(meta={"output": True}, **kwargs)
def update_facts(self, **kwargs):
self.update_vars(meta={"fact": True}, **kwargs)
def _vars_changed(self):
return any(self.vars.has_changed(v) for v in self.vars.change_vars())
def has_changed(self):
return self.changed or self._vars_changed()
@property
def output(self):
result = dict(self.vars.output())
if self.facts_name:
facts = self.vars.facts()
if facts is not None:
result['ansible_facts'] = {self.facts_name: facts}
if self.module._diff:
diff = result.get('diff', {})
vars_diff = self.vars.diff() or {}
result['diff'] = dict_merge(dict(diff), vars_diff)
for varname in result:
if varname in self._output_conflict_list:
result["_" + varname] = result[varname]
del result[varname]
return result
class StateModuleHelper(StateMixin, ModuleHelper):
pass
class CmdModuleHelper(CmdMixin, ModuleHelper):
pass
class CmdStateModuleHelper(CmdMixin, StateMixin, ModuleHelper):
pass

View File

@@ -6,13 +6,509 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from functools import partial, wraps
import traceback
from ansible_collections.community.general.plugins.module_utils.mh.module_helper import (
ModuleHelper, StateModuleHelper, CmdModuleHelper, CmdStateModuleHelper, AnsibleModule
)
from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd import CmdMixin, ArgFormat
from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyCtxMgr
from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException
from ansible_collections.community.general.plugins.module_utils.mh.deco import cause_changes, module_fails_on_exception
from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarMeta, VarDict
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.dict_transformations import dict_merge
class ModuleHelperException(Exception):
@staticmethod
def _get_remove(key, kwargs):
if key in kwargs:
result = kwargs[key]
del kwargs[key]
return result
return None
def __init__(self, *args, **kwargs):
self.msg = self._get_remove('msg', kwargs) or "Module failed with exception: {0}".format(self)
self.update_output = self._get_remove('update_output', kwargs) or {}
super(ModuleHelperException, self).__init__(*args)
class ArgFormat(object):
"""
Argument formatter for use as a command line parameter. Used in CmdMixin.
"""
BOOLEAN = 0
PRINTF = 1
FORMAT = 2
@staticmethod
def stars_deco(num):
if num == 1:
def deco(f):
return lambda v: f(*v)
return deco
elif num == 2:
def deco(f):
return lambda v: f(**v)
return deco
return lambda f: f
def __init__(self, name, fmt=None, style=FORMAT, stars=0):
"""
Creates a CLI-formatter for one specific argument. The argument may be a module parameter or just a named parameter for
the CLI command execution.
:param name: Name of the argument to be formatted
:param fmt: Either a str to be formatted (using or not printf-style) or a callable that does that
:param style: Whether arg_format (as str) should use printf-style formatting.
Ignored if arg_format is None or not a str (should be callable).
:param stars: A int with 0, 1 or 2 value, indicating to formatting the value as: value, *value or **value
"""
def printf_fmt(_fmt, v):
try:
return [_fmt % v]
except TypeError as e:
if e.args[0] != 'not all arguments converted during string formatting':
raise
return [_fmt]
_fmts = {
ArgFormat.BOOLEAN: lambda _fmt, v: ([_fmt] if bool(v) else []),
ArgFormat.PRINTF: printf_fmt,
ArgFormat.FORMAT: lambda _fmt, v: [_fmt.format(v)],
}
self.name = name
self.stars = stars
if fmt is None:
fmt = "{0}"
style = ArgFormat.FORMAT
if isinstance(fmt, str):
func = _fmts[style]
self.arg_format = partial(func, fmt)
elif isinstance(fmt, list) or isinstance(fmt, tuple):
self.arg_format = lambda v: [_fmts[style](f, v)[0] for f in fmt]
elif hasattr(fmt, '__call__'):
self.arg_format = fmt
else:
raise TypeError('Parameter fmt must be either: a string, a list/tuple of '
'strings or a function: type={0}, value={1}'.format(type(fmt), fmt))
if stars:
self.arg_format = (self.stars_deco(stars))(self.arg_format)
def to_text(self, value):
if value is None:
return []
func = self.arg_format
return [str(p) for p in func(value)]
def cause_changes(on_success=None, on_failure=None):
def deco(func):
if on_success is None and on_failure is None:
return func
@wraps(func)
def wrapper(*args, **kwargs):
try:
self = args[0]
func(*args, **kwargs)
if on_success is not None:
self.changed = on_success
except Exception:
if on_failure is not None:
self.changed = on_failure
raise
return wrapper
return deco
def module_fails_on_exception(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
try:
func(self, *args, **kwargs)
except SystemExit:
raise
except ModuleHelperException as e:
if e.update_output:
self.update_output(e.update_output)
self.module.fail_json(msg=e.msg, exception=traceback.format_exc(),
output=self.output, vars=self.vars.output(), **self.output)
except Exception as e:
msg = "Module failed with exception: {0}".format(str(e).strip())
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
output=self.output, vars=self.vars.output(), **self.output)
return wrapper
class DependencyCtxMgr(object):
def __init__(self, name, msg=None):
self.name = name
self.msg = msg
self.has_it = False
self.exc_type = None
self.exc_val = None
self.exc_tb = None
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.has_it = exc_type is None
self.exc_type = exc_type
self.exc_val = exc_val
self.exc_tb = exc_tb
return not self.has_it
@property
def text(self):
return self.msg or str(self.exc_val)
class VarMeta(object):
NOTHING = object()
def __init__(self, diff=False, output=True, change=None, fact=False):
self.init = False
self.initial_value = None
self.value = None
self.diff = diff
self.change = diff if change is None else change
self.output = output
self.fact = fact
def set(self, diff=None, output=None, change=None, fact=None, initial_value=NOTHING):
if diff is not None:
self.diff = diff
if output is not None:
self.output = output
if change is not None:
self.change = change
if fact is not None:
self.fact = fact
if initial_value is not self.NOTHING:
self.initial_value = initial_value
def set_value(self, value):
if not self.init:
self.initial_value = value
self.init = True
self.value = value
return self
@property
def has_changed(self):
return self.change and (self.initial_value != self.value)
@property
def diff_result(self):
return None if not (self.diff and self.has_changed) else {
'before': self.initial_value,
'after': self.value,
}
def __str__(self):
return "<VarMeta: value={0}, initial={1}, diff={2}, output={3}, change={4}>".format(
self.value, self.initial_value, self.diff, self.output, self.change
)
class ModuleHelper(object):
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
_dependencies = []
module = None
facts_name = None
output_params = ()
diff_params = ()
change_params = ()
facts_params = ()
class VarDict(object):
def __init__(self):
self._data = dict()
self._meta = dict()
def __getitem__(self, item):
return self._data[item]
def __setitem__(self, key, value):
self.set(key, value)
def __getattr__(self, item):
try:
return self._data[item]
except KeyError:
return getattr(self._data, item)
def __setattr__(self, key, value):
if key in ('_data', '_meta'):
super(ModuleHelper.VarDict, self).__setattr__(key, value)
else:
self.set(key, value)
def meta(self, name):
return self._meta[name]
def set_meta(self, name, **kwargs):
self.meta(name).set(**kwargs)
def set(self, name, value, **kwargs):
if name in ('_data', '_meta'):
raise ValueError("Names _data and _meta are reserved for use by ModuleHelper")
self._data[name] = value
if name in self._meta:
meta = self.meta(name)
else:
meta = VarMeta(**kwargs)
meta.set_value(value)
self._meta[name] = meta
def output(self):
return dict((k, v) for k, v in self._data.items() if self.meta(k).output)
def diff(self):
diff_results = [(k, self.meta(k).diff_result) for k in self._data]
diff_results = [dr for dr in diff_results if dr[1] is not None]
if diff_results:
before = dict((dr[0], dr[1]['before']) for dr in diff_results)
after = dict((dr[0], dr[1]['after']) for dr in diff_results)
return {'before': before, 'after': after}
return None
def facts(self):
facts_result = dict((k, v) for k, v in self._data.items() if self._meta[k].fact)
return facts_result if facts_result else None
def change_vars(self):
return [v for v in self._data if self.meta(v).change]
def has_changed(self, v):
return self._meta[v].has_changed
def __init__(self, module=None):
self.vars = ModuleHelper.VarDict()
self._changed = False
if module:
self.module = module
if not isinstance(self.module, AnsibleModule):
self.module = AnsibleModule(**self.module)
for name, value in self.module.params.items():
self.vars.set(
name, value,
diff=name in self.diff_params,
output=name in self.output_params,
change=None if not self.change_params else name in self.change_params,
fact=name in self.facts_params,
)
def update_vars(self, meta=None, **kwargs):
if meta is None:
meta = {}
for k, v in kwargs.items():
self.vars.set(k, v, **meta)
def update_output(self, **kwargs):
self.update_vars(meta={"output": True}, **kwargs)
def update_facts(self, **kwargs):
self.update_vars(meta={"fact": True}, **kwargs)
def __init_module__(self):
pass
def __run__(self):
raise NotImplementedError()
def __quit_module__(self):
pass
def _vars_changed(self):
return any(self.vars.has_changed(v) for v in self.vars.change_vars())
@property
def changed(self):
return self._changed
@changed.setter
def changed(self, value):
self._changed = value
def has_changed(self):
return self.changed or self._vars_changed()
@property
def output(self):
result = dict(self.vars.output())
if self.facts_name:
facts = self.vars.facts()
if facts is not None:
result['ansible_facts'] = {self.facts_name: facts}
if self.module._diff:
diff = result.get('diff', {})
vars_diff = self.vars.diff() or {}
result['diff'] = dict_merge(dict(diff), vars_diff)
for varname in result:
if varname in self._output_conflict_list:
result["_" + varname] = result[varname]
del result[varname]
return result
@module_fails_on_exception
def run(self):
self.fail_on_missing_deps()
self.__init_module__()
self.__run__()
self.__quit_module__()
self.module.exit_json(changed=self.has_changed(), **self.output)
@classmethod
def dependency(cls, name, msg):
cls._dependencies.append(DependencyCtxMgr(name, msg))
return cls._dependencies[-1]
def fail_on_missing_deps(self):
for d in self._dependencies:
if not d.has_it:
self.module.fail_json(changed=False,
exception="\n".join(traceback.format_exception(d.exc_type, d.exc_val, d.exc_tb)),
msg=d.text,
**self.output)
class StateMixin(object):
state_param = 'state'
default_state = None
def _state(self):
state = self.module.params.get(self.state_param)
return self.default_state if state is None else state
def _method(self, state):
return "{0}_{1}".format(self.state_param, state)
def __run__(self):
state = self._state()
self.vars.state = state
# resolve aliases
if state not in self.module.params:
aliased = [name for name, param in self.module.argument_spec.items() if state in param.get('aliases', [])]
if aliased:
state = aliased[0]
self.vars.effective_state = state
method = self._method(state)
if not hasattr(self, method):
return self.__state_fallback__()
func = getattr(self, method)
return func()
def __state_fallback__(self):
raise ValueError("Cannot find method: {0}".format(self._method(self._state())))
class CmdMixin(object):
"""
Mixin for mapping module options to running a CLI command with its arguments.
"""
command = None
command_args_formats = {}
run_command_fixed_options = {}
check_rc = False
force_lang = "C"
@property
def module_formats(self):
result = {}
for param in self.module.params.keys():
result[param] = ArgFormat(param)
return result
@property
def custom_formats(self):
result = {}
for param, fmt_spec in self.command_args_formats.items():
result[param] = ArgFormat(param, **fmt_spec)
return result
def _calculate_args(self, extra_params=None, params=None):
def add_arg_formatted_param(_cmd_args, arg_format, _value):
args = list(arg_format.to_text(_value))
return _cmd_args + args
def find_format(_param):
return self.custom_formats.get(_param, self.module_formats.get(_param))
extra_params = extra_params or dict()
cmd_args = list([self.command]) if isinstance(self.command, str) else list(self.command)
try:
cmd_args[0] = self.module.get_bin_path(cmd_args[0], required=True)
except ValueError:
pass
param_list = params if params else self.module.params.keys()
for param in param_list:
if isinstance(param, dict):
if len(param) != 1:
raise ModuleHelperException("run_command parameter as a dict must "
"contain only one key: {0}".format(param))
_param = list(param.keys())[0]
fmt = find_format(_param)
value = param[_param]
elif isinstance(param, str):
if param in self.module.argument_spec:
fmt = find_format(param)
value = self.module.params[param]
elif param in extra_params:
fmt = find_format(param)
value = extra_params[param]
else:
self.module.deprecate("Cannot determine value for parameter: {0}. "
"From version 4.0.0 onwards this will generate an exception".format(param),
version="4.0.0", collection_name="community.general")
continue
else:
raise ModuleHelperException("run_command parameter must be either a str or a dict: {0}".format(param))
cmd_args = add_arg_formatted_param(cmd_args, fmt, value)
return cmd_args
def process_command_output(self, rc, out, err):
return rc, out, err
def run_command(self, extra_params=None, params=None, *args, **kwargs):
self.vars.cmd_args = self._calculate_args(extra_params, params)
options = dict(self.run_command_fixed_options)
options['check_rc'] = options.get('check_rc', self.check_rc)
options.update(kwargs)
env_update = dict(options.get('environ_update', {}))
if self.force_lang:
env_update.update({
'LANGUAGE': self.force_lang,
'LC_ALL': self.force_lang,
})
self.update_output(force_lang=self.force_lang)
options['environ_update'] = env_update
rc, out, err = self.module.run_command(self.vars.cmd_args, *args, **options)
self.update_output(rc=rc, stdout=out, stderr=err)
return self.process_command_output(rc, out, err)
class StateModuleHelper(StateMixin, ModuleHelper):
pass
class CmdModuleHelper(CmdMixin, ModuleHelper):
pass
class CmdStateModuleHelper(CmdMixin, StateMixin, ModuleHelper):
pass

View File

@@ -19,10 +19,11 @@ PATCH_HEADERS = {'content-type': 'application/json', 'accept': 'application/json
'OData-Version': '4.0'}
DELETE_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
FAIL_MSG = 'Issuing a data modification command without specifying the '\
'ID of the target %(resource)s resource when there is more '\
'than one %(resource)s is no longer allowed. Use the `resource_id` '\
'option to specify the target %(resource)s ID.'
DEPRECATE_MSG = 'Issuing a data modification command without specifying the '\
'ID of the target %(resource)s resource when there is more '\
'than one %(resource)s will use the first one in the '\
'collection. Use the `resource_id` option to specify the '\
'target %(resource)s ID'
class RedfishUtils(object):
@@ -266,7 +267,8 @@ class RedfishUtils(object):
'ret': False,
'msg': "System resource %s not found" % self.resource_id}
elif len(self.systems_uris) > 1:
self.module.fail_json(msg=FAIL_MSG % {'resource': 'System'})
self.module.deprecate(DEPRECATE_MSG % {'resource': 'System'},
version='3.0.0', collection_name='community.general') # was Ansible 2.14
return {'ret': True}
def _find_updateservice_resource(self):
@@ -316,7 +318,8 @@ class RedfishUtils(object):
'ret': False,
'msg': "Chassis resource %s not found" % self.resource_id}
elif len(self.chassis_uris) > 1:
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Chassis'})
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Chassis'},
version='3.0.0', collection_name='community.general') # was Ansible 2.14
return {'ret': True}
def _find_managers_resource(self):
@@ -345,7 +348,8 @@ class RedfishUtils(object):
'ret': False,
'msg': "Manager resource %s not found" % self.resource_id}
elif len(self.manager_uris) > 1:
self.module.fail_json(msg=FAIL_MSG % {'resource': 'Manager'})
self.module.deprecate(DEPRECATE_MSG % {'resource': 'Manager'},
version='3.0.0', collection_name='community.general') # was Ansible 2.14
return {'ret': True}
def _get_all_action_info_values(self, action):
@@ -1671,31 +1675,19 @@ class RedfishUtils(object):
# Make a copy of the attributes dict
attrs_to_patch = dict(attributes)
# List to hold attributes not found
attrs_bad = {}
# Check the attributes
for attr_name, attr_value in attributes.items():
# Check if attribute exists
if attr_name not in data[u'Attributes']:
# Remove and proceed to next attribute if this isn't valid
attrs_bad.update({attr_name: attr_value})
del attrs_to_patch[attr_name]
continue
for attr in attributes:
if attr not in data[u'Attributes']:
return {'ret': False, 'msg': "BIOS attribute %s not found" % attr}
# If already set to requested value, remove it from PATCH payload
if data[u'Attributes'][attr_name] == attributes[attr_name]:
del attrs_to_patch[attr_name]
warning = ""
if attrs_bad:
warning = "Incorrect attributes %s" % (attrs_bad)
if data[u'Attributes'][attr] == attributes[attr]:
del attrs_to_patch[attr]
# Return success w/ changed=False if no attrs need to be changed
if not attrs_to_patch:
return {'ret': True, 'changed': False,
'msg': "BIOS attributes already set",
'warning': warning}
'msg': "BIOS attributes already set"}
# Get the SettingsObject URI
set_bios_attr_uri = data["@Redfish.Settings"]["SettingsObject"]["@odata.id"]
@@ -1705,9 +1697,7 @@ class RedfishUtils(object):
response = self.patch_request(self.root_uri + set_bios_attr_uri, payload)
if response['ret'] is False:
return response
return {'ret': True, 'changed': True,
'msg': "Modified BIOS attributes %s" % (attrs_to_patch),
'warning': warning}
return {'ret': True, 'changed': True, 'msg': "Modified BIOS attribute"}
def set_boot_order(self, boot_list):
if not boot_list:

View File

@@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
#
# Dell EMC OpenManage Ansible Modules
# Version 1.0
# Copyright (C) 2018 Dell Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# All rights reserved. Dell, EMC, and other trademarks are trademarks of Dell Inc. or its subsidiaries.
# Other trademarks may be trademarks of their respective owners.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
try:
from omsdk.sdkinfra import sdkinfra
from omsdk.sdkcreds import UserCredentials
from omsdk.sdkfile import FileOnShare, file_share_manager
from omsdk.sdkprotopref import ProtoPreference, ProtocolEnum
from omsdk.http.sdkwsmanbase import WsManOptions
HAS_OMSDK = True
except ImportError:
HAS_OMSDK = False
class iDRACConnection:
def __init__(self, module_params):
if not HAS_OMSDK:
raise ImportError("Dell EMC OMSDK library is required for this module")
self.idrac_ip = module_params['idrac_ip']
self.idrac_user = module_params['idrac_user']
self.idrac_pwd = module_params['idrac_password']
self.idrac_port = module_params['idrac_port']
if not all((self.idrac_ip, self.idrac_user, self.idrac_pwd)):
raise ValueError("hostname, username and password required")
self.handle = None
self.creds = UserCredentials(self.idrac_user, self.idrac_pwd)
self.pOp = WsManOptions(port=self.idrac_port)
self.sdk = sdkinfra()
if self.sdk is None:
msg = "Could not initialize iDRAC drivers."
raise RuntimeError(msg)
def __enter__(self):
self.sdk.importPath()
self.handle = self.sdk.get_driver(self.sdk.driver_enum.iDRAC, self.idrac_ip, self.creds, pOptions=self.pOp)
if self.handle is None:
msg = "Could not find device driver for iDRAC with IP Address: {0}".format(self.idrac_ip)
raise RuntimeError(msg)
return self.handle
def __exit__(self, exc_type, exc_val, exc_tb):
self.handle.disconnect()
return False

View File

@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
# Dell EMC OpenManage Ansible Modules
# Version 1.3
# Copyright (C) 2019 Dell Inc. or its subsidiaries. All Rights Reserved.
#
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.module_utils.urls import open_url, ConnectionError, SSLValidationError
from ansible.module_utils.six.moves.urllib.error import URLError, HTTPError
from ansible.module_utils.six.moves.urllib.parse import urlencode
SESSION_RESOURCE_COLLECTION = {
"SESSION": "SessionService/Sessions",
"SESSION_ID": "SessionService/Sessions('{Id}')",
}
class OpenURLResponse(object):
"""Handles HTTPResponse"""
def __init__(self, resp):
self.body = None
self.resp = resp
if self.resp:
self.body = self.resp.read()
@property
def json_data(self):
try:
return json.loads(self.body)
except ValueError:
raise ValueError("Unable to parse json")
@property
def status_code(self):
return self.resp.getcode()
@property
def success(self):
return self.status_code in (200, 201, 202, 204)
@property
def token_header(self):
return self.resp.headers.get('X-Auth-Token')
class RestOME(object):
"""Handles OME API requests"""
def __init__(self, module_params=None, req_session=False):
self.module_params = module_params
self.hostname = self.module_params["hostname"]
self.username = self.module_params["username"]
self.password = self.module_params["password"]
self.port = self.module_params["port"]
self.req_session = req_session
self.session_id = None
self.protocol = 'https'
self._headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
def _get_base_url(self):
"""builds base url"""
return '{0}://{1}:{2}/api'.format(self.protocol, self.hostname, self.port)
def _build_url(self, path, query_param=None):
"""builds complete url"""
url = path
base_uri = self._get_base_url()
if path:
url = '{0}/{1}'.format(base_uri, path)
if query_param:
url += "?{0}".format(urlencode(query_param))
return url
def _url_common_args_spec(self, method, api_timeout, headers=None):
"""Creates an argument common spec"""
req_header = self._headers
if headers:
req_header.update(headers)
url_kwargs = {
"method": method,
"validate_certs": False,
"use_proxy": True,
"headers": req_header,
"timeout": api_timeout,
"follow_redirects": 'all',
}
return url_kwargs
def _args_without_session(self, method, api_timeout=30, headers=None):
"""Creates an argument spec in case of basic authentication"""
req_header = self._headers
if headers:
req_header.update(headers)
url_kwargs = self._url_common_args_spec(method, api_timeout, headers=headers)
url_kwargs["url_username"] = self.username
url_kwargs["url_password"] = self.password
url_kwargs["force_basic_auth"] = True
return url_kwargs
def _args_with_session(self, method, api_timeout=30, headers=None):
"""Creates an argument spec, in case of authentication with session"""
url_kwargs = self._url_common_args_spec(method, api_timeout, headers=headers)
url_kwargs["force_basic_auth"] = False
return url_kwargs
def invoke_request(self, method, path, data=None, query_param=None, headers=None,
api_timeout=30, dump=True):
"""
Sends a request via open_url
Returns :class:`OpenURLResponse` object.
:arg method: HTTP verb to use for the request
:arg path: path to request without query parameter
:arg data: (optional) Payload to send with the request
:arg query_param: (optional) Dictionary of query parameter to send with request
:arg headers: (optional) Dictionary of HTTP Headers to send with the
request
:arg api_timeout: (optional) How long to wait for the server to send
data before giving up
:arg dump: (Optional) boolean value for dumping payload data.
:returns: OpenURLResponse
"""
try:
if 'X-Auth-Token' in self._headers:
url_kwargs = self._args_with_session(method, api_timeout, headers=headers)
else:
url_kwargs = self._args_without_session(method, api_timeout, headers=headers)
if data and dump:
data = json.dumps(data)
url = self._build_url(path, query_param=query_param)
resp = open_url(url, data=data, **url_kwargs)
resp_data = OpenURLResponse(resp)
except (HTTPError, URLError, SSLValidationError, ConnectionError) as err:
raise err
return resp_data
def __enter__(self):
"""Creates sessions by passing it to header"""
if self.req_session:
payload = {'UserName': self.username,
'Password': self.password,
'SessionType': 'API', }
path = SESSION_RESOURCE_COLLECTION["SESSION"]
resp = self.invoke_request('POST', path, data=payload)
if resp and resp.success:
self.session_id = resp.json_data.get("Id")
self._headers["X-Auth-Token"] = resp.token_header
else:
msg = "Could not create the session"
raise ConnectionError(msg)
return self
def __exit__(self, exc_type, exc_value, traceback):
"""Deletes a session id, which is in use for request"""
if self.session_id:
path = SESSION_RESOURCE_COLLECTION["SESSION_ID"].format(Id=self.session_id)
self.invoke_request('DELETE', path)
return False

View File

@@ -0,0 +1 @@
cloud/alicloud/ali_instance_facts.py

View File

@@ -0,0 +1 @@
ali_instance_info.py

View File

@@ -383,6 +383,9 @@ def main():
)
)
module = AnsibleModule(argument_spec=argument_spec)
if module._name in ('ali_instance_facts', 'community.general.ali_instance_facts'):
module.deprecate("The 'ali_instance_facts' module has been renamed to 'ali_instance_info'",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
if HAS_FOOTMARK is False:
module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR)

View File

@@ -30,6 +30,10 @@ options:
required: False
default: present
choices: ['present','absent']
wait:
description:
- This option does nothing and will be removed in community.general 3.0.0.
type: bool
requirements:
- python = 2.7
- requests >= 2.5.0
@@ -181,6 +185,7 @@ class ClcAntiAffinityPolicy:
argument_spec = dict(
name=dict(required=True),
location=dict(required=True),
wait=dict(type='bool', removed_in_version='3.0.0', removed_from_collection='community.general'), # was Ansible 2.14
state=dict(default='present', choices=['present', 'absent']),
)
return argument_spec

View File

@@ -21,10 +21,8 @@ options:
type: str
api_key:
description:
- Linode API key.
- C(LINODE_API_KEY) env variable can be used instead.
- Linode API key
type: str
required: yes
name:
description:
- Name to give the instance (alphanumeric, dashes, underscore).
@@ -48,7 +46,6 @@ options:
- List of dictionaries for creating additional disks that are added to the Linode configuration settings.
- Dictionary takes Size, Label, Type. Size is in MB.
type: list
elements: dict
alert_bwin_enabled:
description:
- Set status of bandwidth in alerts.
@@ -89,18 +86,9 @@ options:
description:
- Set threshold for average IO ops/sec over 2 hour period.
type: int
backupsenabled:
description:
- Deprecated parameter, it will be removed in community.general C(5.0.0).
- To enable backups pass values to either I(backupweeklyday) or I(backupwindow).
type: int
backupweeklyday:
description:
- Day of the week to take backups.
type: int
backupwindow:
description:
- The time window in which backups will be taken.
- Integer value for what day of the week to store weekly backups.
type: int
plan:
description:
@@ -165,6 +153,7 @@ author:
notes:
- Please note, linode-python does not have python 3 support.
- This module uses the now deprecated v3 of the Linode API.
- C(LINODE_API_KEY) env variable can be used instead.
- Please review U(https://www.linode.com/api/linode) for determining the required parameters.
'''
@@ -273,6 +262,7 @@ EXAMPLES = '''
delegate_to: localhost
'''
import os
import time
import traceback
@@ -284,7 +274,7 @@ except ImportError:
LINODE_IMP_ERR = traceback.format_exc()
HAS_LINODE = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib, env_fallback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
def randompass():
@@ -368,7 +358,7 @@ def linodeServers(module, api, state, name,
if not servers:
for arg in (name, plan, distribution, datacenter):
if not arg:
module.fail_json(msg='%s is required for %s state' % (arg, state))
module.fail_json(msg='%s is required for %s state' % (arg, state)) # @TODO use required_if instead
# Create linode entity
new_server = True
@@ -393,7 +383,7 @@ def linodeServers(module, api, state, name,
try:
res = api.linode_ip_addprivate(LinodeID=linode_id)
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
if not disks:
for arg in (name, linode_id, distribution):
@@ -438,7 +428,7 @@ def linodeServers(module, api, state, name,
jobs.append(res['JobID'])
except Exception as e:
# TODO: destroy linode ?
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
if not configs:
for arg in (name, linode_id, distribution):
@@ -481,7 +471,7 @@ def linodeServers(module, api, state, name,
Disklist=disks_list, Label='%s config' % name)
configs = api.linode_config_list(LinodeId=linode_id)
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
# Start / Ensure servers are running
for server in servers:
@@ -527,7 +517,10 @@ def linodeServers(module, api, state, name,
instance['password'] = password
instances.append(instance)
elif state in ('stopped',):
elif state in ('stopped'):
if not linode_id:
module.fail_json(msg='linode_id is required for stopped state')
if not servers:
module.fail_json(msg='Server (lid: %s) not found' % (linode_id))
@@ -537,14 +530,17 @@ def linodeServers(module, api, state, name,
try:
res = api.linode_shutdown(LinodeId=linode_id)
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
instance['status'] = 'Stopping'
changed = True
else:
instance['status'] = 'Stopped'
instances.append(instance)
elif state in ('restarted',):
elif state in ('restarted'):
if not linode_id:
module.fail_json(msg='linode_id is required for restarted state')
if not servers:
module.fail_json(msg='Server (lid: %s) not found' % (linode_id))
@@ -553,7 +549,7 @@ def linodeServers(module, api, state, name,
try:
res = api.linode_reboot(LinodeId=server['LINODEID'])
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
instance['status'] = 'Restarting'
changed = True
instances.append(instance)
@@ -564,7 +560,7 @@ def linodeServers(module, api, state, name,
try:
api.linode_delete(LinodeId=server['LINODEID'], skipChecks=True)
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
instance['status'] = 'Deleting'
changed = True
instances.append(instance)
@@ -581,7 +577,7 @@ def main():
argument_spec=dict(
state=dict(type='str', default='present',
choices=['absent', 'active', 'deleted', 'present', 'restarted', 'started', 'stopped']),
api_key=dict(type='str', no_log=True, required=True, fallback=(env_fallback, ['LINODE_API_KEY'])),
api_key=dict(type='str', no_log=True),
name=dict(type='str', required=True),
alert_bwin_enabled=dict(type='bool'),
alert_bwin_threshold=dict(type='int'),
@@ -593,12 +589,12 @@ def main():
alert_cpu_threshold=dict(type='int'),
alert_diskio_enabled=dict(type='bool'),
alert_diskio_threshold=dict(type='int'),
backupsenabled=dict(type='int', removed_in_version='5.0.0', removed_from_collection='community.general'),
backupsenabled=dict(type='int'),
backupweeklyday=dict(type='int'),
backupwindow=dict(type='int'),
displaygroup=dict(type='str', default=''),
plan=dict(type='int'),
additional_disks=dict(type='list', elements='dict'),
additional_disks=dict(type='list'),
distribution=dict(type='int'),
datacenter=dict(type='int'),
kernel_id=dict(type='int'),
@@ -612,10 +608,6 @@ def main():
wait_timeout=dict(type='int', default=300),
watchdog=dict(type='bool', default=True),
),
required_if=[
('state', 'restarted', ['linode_id']),
('state', 'stopped', ['linode_id']),
]
)
if not HAS_LINODE:
@@ -634,6 +626,7 @@ def main():
alert_cpu_threshold = module.params.get('alert_cpu_threshold')
alert_diskio_enabled = module.params.get('alert_diskio_enabled')
alert_diskio_threshold = module.params.get('alert_diskio_threshold')
backupsenabled = module.params.get('backupsenabled')
backupweeklyday = module.params.get('backupweeklyday')
backupwindow = module.params.get('backupwindow')
displaygroup = module.params.get('displaygroup')
@@ -649,9 +642,10 @@ def main():
ssh_pub_key = module.params.get('ssh_pub_key')
swap = module.params.get('swap')
wait = module.params.get('wait')
wait_timeout = module.params.get('wait_timeout')
wait_timeout = int(module.params.get('wait_timeout'))
watchdog = int(module.params.get('watchdog'))
kwargs = dict()
check_items = dict(
alert_bwin_enabled=alert_bwin_enabled,
alert_bwin_threshold=alert_bwin_threshold,
@@ -667,14 +661,23 @@ def main():
backupwindow=backupwindow,
)
kwargs = dict((k, v) for k, v in check_items.items() if v is not None)
for key, value in check_items.items():
if value is not None:
kwargs[key] = value
# Setup the api_key
if not api_key:
try:
api_key = os.environ['LINODE_API_KEY']
except KeyError as e:
module.fail_json(msg='Unable to load %s' % e.message)
# setup the auth
try:
api = linode_api.Api(api_key)
api.test_echo()
except Exception as e:
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'], exception=traceback.format_exc())
module.fail_json(msg='%s' % e.value[0]['ERRORMESSAGE'])
linodeServers(module, api, state, name,
displaygroup, plan,

View File

@@ -53,13 +53,6 @@ options:
group labelling is deprecated but still supported. The encouraged
method for marking instances is to use tags.
type: str
private_ip:
description:
- If C(true), the created Linode will have private networking enabled and
assigned a private IPv4 address.
type: bool
default: false
version_added: 3.0.0
tags:
description:
- The tags that the instance should be marked under. See
@@ -244,7 +237,6 @@ def initialise_module():
authorized_keys=dict(type='list', elements='str', no_log=False),
group=dict(type='str'),
image=dict(type='str'),
private_ip=dict(type='bool', default=False),
region=dict(type='str'),
root_pass=dict(type='str', no_log=True),
tags=dict(type='list', elements='str'),
@@ -290,7 +282,6 @@ def main():
group=module.params['group'],
image=module.params['image'],
label=module.params['label'],
private_ip=module.params['private_ip'],
region=module.params['region'],
root_pass=module.params['root_pass'],
tags=module.params['tags'],

View File

@@ -0,0 +1 @@
memset_memstore_info.py

View File

@@ -151,6 +151,9 @@ def main():
),
supports_check_mode=False
)
if module._name in ('memset_memstore_facts', 'community.general.memset_memstore_facts'):
module.deprecate("The 'memset_memstore_facts' module has been renamed to 'memset_memstore_info'",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
# populate the dict with the user-provided vars.
args = dict()

View File

@@ -0,0 +1 @@
memset_server_info.py

View File

@@ -276,6 +276,9 @@ def main():
),
supports_check_mode=False
)
if module._name in ('memset_server_facts', 'community.general.memset_server_facts'):
module.deprecate("The 'memset_server_facts' module has been renamed to 'memset_server_info'",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
# populate the dict with the user-provided vars.
args = dict()

View File

@@ -88,7 +88,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
CLOUD_INIT_PATH = "/var/lib/cloud/data"
CLOUD_INIT_PATH = "/var/lib/cloud/data/"
def gather_cloud_init_data_facts(module):
@@ -100,7 +100,7 @@ def gather_cloud_init_data_facts(module):
filter = module.params.get('filter')
if filter is None or filter == i:
res['cloud_init_data_facts'][i] = dict()
json_file = os.path.join(CLOUD_INIT_PATH, i + '.json')
json_file = CLOUD_INIT_PATH + i + '.json'
if os.path.exists(json_file):
f = open(json_file, 'rb')

View File

@@ -0,0 +1,216 @@
#!/usr/bin/python
# (c) 2016, Flavio Percoco <flavio@redhat.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
DOCUMENTATION = '''
---
deprecated:
removed_in: 3.0.0 # was Ansible 2.14
why: For more details https://github.com/ansible/ansible/issues/61546.
alternative: Use M(community.kubernetes.helm) instead.
module: helm
short_description: Manages Kubernetes packages with the Helm package manager
author: "Flavio Percoco (@flaper87)"
description:
- Install, upgrade, delete and list packages with the Helm package manager.
requirements:
- "pyhelm"
- "grpcio"
options:
host:
description:
- Tiller's server host.
type: str
default: "localhost"
port:
description:
- Tiller's server port.
type: int
default: 44134
namespace:
description:
- Kubernetes namespace where the chart should be installed.
type: str
default: "default"
name:
description:
- Release name to manage.
type: str
state:
description:
- Whether to install C(present), remove C(absent), or purge C(purged) a package.
choices: ['absent', 'purged', 'present']
type: str
default: "present"
chart:
description:
- A map describing the chart to install. See examples for available options.
type: dict
default: {}
values:
description:
- A map of value options for the chart.
type: dict
default: {}
disable_hooks:
description:
- Whether to disable hooks during the uninstall process.
type: bool
default: 'no'
'''
RETURN = ''' # '''
EXAMPLES = '''
- name: Install helm chart
community.general.helm:
host: localhost
chart:
name: memcached
version: 0.4.0
source:
type: repo
location: https://kubernetes-charts.storage.googleapis.com
state: present
name: my-memcached
namespace: default
- name: Uninstall helm chart
community.general.helm:
host: localhost
state: absent
name: my-memcached
- name: Install helm chart from a git repo
community.general.helm:
host: localhost
chart:
source:
type: git
location: https://github.com/user/helm-chart.git
state: present
name: my-example
namespace: default
values:
foo: "bar"
- name: Install helm chart from a git repo specifying path
community.general.helm:
host: localhost
chart:
source:
type: git
location: https://github.com/helm/charts.git
path: stable/memcached
state: present
name: my-memcached
namespace: default
values: "{{ lookup('file', '/path/to/file/values.yaml') | from_yaml }}"
'''
import traceback
HELM_IMPORT_ERR = None
try:
import grpc
from pyhelm import tiller
from pyhelm import chartbuilder
except ImportError:
HELM_IMPORT_ERR = traceback.format_exc()
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
def install(module, tserver):
changed = False
params = module.params
name = params['name']
values = params['values']
chart = module.params['chart']
namespace = module.params['namespace']
chartb = chartbuilder.ChartBuilder(chart)
r_matches = (x for x in tserver.list_releases()
if x.name == name and x.namespace == namespace)
installed_release = next(r_matches, None)
if installed_release:
if installed_release.chart.metadata.version != chart['version']:
tserver.update_release(chartb.get_helm_chart(), False,
namespace, name=name, values=values)
changed = True
else:
tserver.install_release(chartb.get_helm_chart(), namespace,
dry_run=False, name=name,
values=values)
changed = True
return dict(changed=changed)
def delete(module, tserver, purge=False):
changed = False
params = module.params
if not module.params['name']:
module.fail_json(msg='Missing required field name')
name = module.params['name']
disable_hooks = params['disable_hooks']
try:
tserver.uninstall_release(name, disable_hooks, purge)
changed = True
except grpc._channel._Rendezvous as exc:
if 'not found' not in str(exc):
raise exc
return dict(changed=changed)
def main():
"""The main function."""
module = AnsibleModule(
argument_spec=dict(
host=dict(type='str', default='localhost'),
port=dict(type='int', default=44134),
name=dict(type='str', default=''),
chart=dict(type='dict'),
state=dict(
choices=['absent', 'purged', 'present'],
default='present'
),
# Install options
values=dict(type='dict'),
namespace=dict(type='str', default='default'),
# Uninstall options
disable_hooks=dict(type='bool', default=False),
),
supports_check_mode=True)
if HELM_IMPORT_ERR:
module.fail_json(msg=missing_required_lib('pyhelm'), exception=HELM_IMPORT_ERR)
host = module.params['host']
port = module.params['port']
state = module.params['state']
tserver = tiller.Tiller(host, port)
if state == 'present':
rst = install(module, tserver)
if state in 'absent':
rst = delete(module, tserver)
if state in 'purged':
rst = delete(module, tserver, True)
module.exit_json(**rst)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,502 @@
#!/usr/bin/python
# Copyright: (c) 2013, Vincent Van der Kussen <vincent at vanderkussen.org>
# 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
DOCUMENTATION = '''
---
module: ovirt
author:
- Vincent Van der Kussen (@vincentvdk)
short_description: oVirt/RHEV platform management
deprecated:
removed_in: 3.0.0 # was Ansible 2.14
why: This module is for deprecated version of ovirt.
alternative: Use C(ovirt_vm) from the C(ovirt.ovirt) collection instead
description:
- This module only supports oVirt/RHEV version 3. A newer module M(ovirt.ovirt.ovirt_vm) supports oVirt/RHV version 4.
- Allows you to create new instances, either from scratch or an image, in addition to deleting or stopping instances on the oVirt/RHEV platform.
options:
user:
description:
- The user to authenticate with.
type: str
required: true
url:
description:
- The url of the oVirt instance.
type: str
required: true
instance_name:
description:
- The name of the instance to use.
type: str
required: true
aliases: [ vmname ]
password:
description:
- Password of the user to authenticate with.
type: str
required: true
image:
description:
- The template to use for the instance.
type: str
resource_type:
description:
- Whether you want to deploy an image or create an instance from scratch.
type: str
choices: [ new, template ]
zone:
description:
- Deploy the image to this oVirt cluster.
type: str
instance_disksize:
description:
- Size of the instance's disk in GB.
type: str
aliases: [ vm_disksize]
instance_cpus:
description:
- The instance's number of CPUs.
type: str
default: 1
aliases: [ vmcpus ]
instance_nic:
description:
- The name of the network interface in oVirt/RHEV.
type: str
aliases: [ vmnic ]
instance_network:
description:
- The logical network the machine should belong to.
type: str
default: rhevm
aliases: [ vmnetwork ]
instance_mem:
description:
- The instance's amount of memory in MB.
type: str
aliases: [ vmmem ]
instance_type:
description:
- Define whether the instance is a server, desktop or high_performance.
- I(high_performance) is supported since Ansible 2.5 and oVirt/RHV 4.2.
type: str
choices: [ desktop, server, high_performance ]
default: server
aliases: [ vmtype ]
disk_alloc:
description:
- Define whether disk is thin or preallocated.
type: str
choices: [ preallocated, thin ]
default: thin
disk_int:
description:
- Interface type of the disk.
type: str
choices: [ ide, virtio ]
default: virtio
instance_os:
description:
- Type of Operating System.
type: str
aliases: [ vmos ]
instance_cores:
description:
- Define the instance's number of cores.
type: str
default: 1
aliases: [ vmcores ]
sdomain:
description:
- The Storage Domain where you want to create the instance's disk on.
type: str
region:
description:
- The oVirt/RHEV datacenter where you want to deploy to.
type: str
instance_dns:
description:
- Define the instance's Primary DNS server.
type: str
aliases: [ dns ]
instance_domain:
description:
- Define the instance's Domain.
type: str
aliases: [ domain ]
instance_hostname:
description:
- Define the instance's Hostname.
type: str
aliases: [ hostname ]
instance_ip:
description:
- Define the instance's IP.
type: str
aliases: [ ip ]
instance_netmask:
description:
- Define the instance's Netmask.
type: str
aliases: [ netmask ]
instance_gateway:
description:
- Define the instance's Gateway.
type: str
aliases: [ gateway ]
instance_rootpw:
description:
- Define the instance's Root password.
type: str
aliases: [ rootpw ]
instance_key:
description:
- Define the instance's Authorized key.
type: str
aliases: [ key ]
state:
description:
- Create, terminate or remove instances.
type: str
choices: [ absent, present, restart, shutdown, started ]
default: present
requirements:
- ovirt-engine-sdk-python
'''
EXAMPLES = '''
- name: Basic example to provision from image
community.general.ovirt:
user: admin@internal
url: https://ovirt.example.com
instance_name: ansiblevm04
password: secret
image: centos_64
zone: cluster01
resource_type: template
- name: Full example to create new instance from scratch
community.general.ovirt:
instance_name: testansible
resource_type: new
instance_type: server
user: admin@internal
password: secret
url: https://ovirt.example.com
instance_disksize: 10
zone: cluster01
region: datacenter1
instance_cpus: 1
instance_nic: nic1
instance_network: rhevm
instance_mem: 1000
disk_alloc: thin
sdomain: FIBER01
instance_cores: 1
instance_os: rhel_6x64
disk_int: virtio
- name: Stopping an existing instance
community.general.ovirt:
instance_name: testansible
state: stopped
user: admin@internal
password: secret
url: https://ovirt.example.com
- name: Start an existing instance
community.general.ovirt:
instance_name: testansible
state: started
user: admin@internal
password: secret
url: https://ovirt.example.com
- name: Start an instance with cloud init information
community.general.ovirt:
instance_name: testansible
state: started
user: admin@internal
password: secret
url: https://ovirt.example.com
hostname: testansible
domain: ansible.local
ip: 192.0.2.100
netmask: 255.255.255.0
gateway: 192.0.2.1
rootpw: bigsecret
'''
import time
try:
from ovirtsdk.api import API
from ovirtsdk.xml import params
HAS_OVIRTSDK = True
except ImportError:
HAS_OVIRTSDK = False
from ansible.module_utils.basic import AnsibleModule
# ------------------------------------------------------------------- #
# create connection with API
#
def conn(url, user, password):
api = API(url=url, username=user, password=password, insecure=True)
try:
value = api.test()
except Exception:
raise Exception("error connecting to the oVirt API")
return api
# ------------------------------------------------------------------- #
# Create VM from scratch
def create_vm(conn, vmtype, vmname, zone, vmdisk_size, vmcpus, vmnic, vmnetwork, vmmem, vmdisk_alloc, sdomain, vmcores, vmos, vmdisk_int):
if vmdisk_alloc == 'thin':
# define VM params
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), os=params.OperatingSystem(type_=vmos),
template=conn.templates.get(name="Blank"), memory=1024 * 1024 * int(vmmem),
cpu=params.CPU(topology=params.CpuTopology(cores=int(vmcores), sockets=vmcpus)), type_=vmtype)
# define disk params
vmdisk = params.Disk(size=1024 * 1024 * 1024 * int(vmdisk_size), wipe_after_delete=True, sparse=True, interface=vmdisk_int, type_="System",
format='cow',
storage_domains=params.StorageDomains(storage_domain=[conn.storagedomains.get(name=sdomain)]))
# define network parameters
network_net = params.Network(name=vmnetwork)
nic_net1 = params.NIC(name='nic1', network=network_net, interface='virtio')
elif vmdisk_alloc == 'preallocated':
# define VM params
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), os=params.OperatingSystem(type_=vmos),
template=conn.templates.get(name="Blank"), memory=1024 * 1024 * int(vmmem),
cpu=params.CPU(topology=params.CpuTopology(cores=int(vmcores), sockets=vmcpus)), type_=vmtype)
# define disk params
vmdisk = params.Disk(size=1024 * 1024 * 1024 * int(vmdisk_size), wipe_after_delete=True, sparse=False, interface=vmdisk_int, type_="System",
format='raw', storage_domains=params.StorageDomains(storage_domain=[conn.storagedomains.get(name=sdomain)]))
# define network parameters
network_net = params.Network(name=vmnetwork)
nic_net1 = params.NIC(name=vmnic, network=network_net, interface='virtio')
try:
conn.vms.add(vmparams)
except Exception:
raise Exception("Error creating VM with specified parameters")
vm = conn.vms.get(name=vmname)
try:
vm.disks.add(vmdisk)
except Exception:
raise Exception("Error attaching disk")
try:
vm.nics.add(nic_net1)
except Exception:
raise Exception("Error adding nic")
# create an instance from a template
def create_vm_template(conn, vmname, image, zone):
vmparams = params.VM(name=vmname, cluster=conn.clusters.get(name=zone), template=conn.templates.get(name=image), disks=params.Disks(clone=True))
try:
conn.vms.add(vmparams)
except Exception:
raise Exception('error adding template %s' % image)
# start instance
def vm_start(conn, vmname, hostname=None, ip=None, netmask=None, gateway=None,
domain=None, dns=None, rootpw=None, key=None):
vm = conn.vms.get(name=vmname)
use_cloud_init = False
nics = None
nic = None
if hostname or ip or netmask or gateway or domain or dns or rootpw or key:
use_cloud_init = True
if ip and netmask and gateway:
ipinfo = params.IP(address=ip, netmask=netmask, gateway=gateway)
nic = params.GuestNicConfiguration(name='eth0', boot_protocol='STATIC', ip=ipinfo, on_boot=True)
nics = params.Nics()
nics = params.GuestNicsConfiguration(nic_configuration=[nic])
initialization = params.Initialization(regenerate_ssh_keys=True, host_name=hostname, domain=domain, user_name='root',
root_password=rootpw, nic_configurations=nics, dns_servers=dns,
authorized_ssh_keys=key)
action = params.Action(use_cloud_init=use_cloud_init, vm=params.VM(initialization=initialization))
vm.start(action=action)
# Stop instance
def vm_stop(conn, vmname):
vm = conn.vms.get(name=vmname)
vm.stop()
# restart instance
def vm_restart(conn, vmname):
state = vm_status(conn, vmname)
vm = conn.vms.get(name=vmname)
vm.stop()
while conn.vms.get(vmname).get_status().get_state() != 'down':
time.sleep(5)
vm.start()
# remove an instance
def vm_remove(conn, vmname):
vm = conn.vms.get(name=vmname)
vm.delete()
# ------------------------------------------------------------------- #
# VM statuses
#
# Get the VMs status
def vm_status(conn, vmname):
status = conn.vms.get(name=vmname).status.state
return status
# Get VM object and return it's name if object exists
def get_vm(conn, vmname):
vm = conn.vms.get(name=vmname)
if vm is None:
name = "empty"
else:
name = vm.get_name()
return name
# ------------------------------------------------------------------- #
# Hypervisor operations
#
# not available yet
# ------------------------------------------------------------------- #
# Main
def main():
module = AnsibleModule(
argument_spec=dict(
state=dict(type='str', default='present', choices=['absent', 'present', 'restart', 'shutdown', 'started']),
user=dict(type='str', required=True),
url=dict(type='str', required=True),
instance_name=dict(type='str', required=True, aliases=['vmname']),
password=dict(type='str', required=True, no_log=True),
image=dict(type='str'),
resource_type=dict(type='str', choices=['new', 'template']),
zone=dict(type='str'),
instance_disksize=dict(type='str', aliases=['vm_disksize']),
instance_cpus=dict(type='str', default=1, aliases=['vmcpus']),
instance_nic=dict(type='str', aliases=['vmnic']),
instance_network=dict(type='str', default='rhevm', aliases=['vmnetwork']),
instance_mem=dict(type='str', aliases=['vmmem']),
instance_type=dict(type='str', default='server', aliases=['vmtype'], choices=['desktop', 'server', 'high_performance']),
disk_alloc=dict(type='str', default='thin', choices=['preallocated', 'thin']),
disk_int=dict(type='str', default='virtio', choices=['ide', 'virtio']),
instance_os=dict(type='str', aliases=['vmos']),
instance_cores=dict(type='str', default=1, aliases=['vmcores']),
instance_hostname=dict(type='str', aliases=['hostname']),
instance_ip=dict(type='str', aliases=['ip']),
instance_netmask=dict(type='str', aliases=['netmask']),
instance_gateway=dict(type='str', aliases=['gateway']),
instance_domain=dict(type='str', aliases=['domain']),
instance_dns=dict(type='str', aliases=['dns']),
instance_rootpw=dict(type='str', aliases=['rootpw'], no_log=True),
instance_key=dict(type='str', aliases=['key'], no_log=True),
sdomain=dict(type='str'),
region=dict(type='str'),
),
)
if not HAS_OVIRTSDK:
module.fail_json(msg='ovirtsdk required for this module')
state = module.params['state']
user = module.params['user']
url = module.params['url']
vmname = module.params['instance_name']
password = module.params['password']
image = module.params['image'] # name of the image to deploy
resource_type = module.params['resource_type'] # template or from scratch
zone = module.params['zone'] # oVirt cluster
vmdisk_size = module.params['instance_disksize'] # disksize
vmcpus = module.params['instance_cpus'] # number of cpu
vmnic = module.params['instance_nic'] # network interface
vmnetwork = module.params['instance_network'] # logical network
vmmem = module.params['instance_mem'] # mem size
vmdisk_alloc = module.params['disk_alloc'] # thin, preallocated
vmdisk_int = module.params['disk_int'] # disk interface virtio or ide
vmos = module.params['instance_os'] # Operating System
vmtype = module.params['instance_type'] # server, desktop or high_performance
vmcores = module.params['instance_cores'] # number of cores
sdomain = module.params['sdomain'] # storage domain to store disk on
region = module.params['region'] # oVirt Datacenter
hostname = module.params['instance_hostname']
ip = module.params['instance_ip']
netmask = module.params['instance_netmask']
gateway = module.params['instance_gateway']
domain = module.params['instance_domain']
dns = module.params['instance_dns']
rootpw = module.params['instance_rootpw']
key = module.params['instance_key']
# initialize connection
try:
c = conn(url + "/api", user, password)
except Exception as e:
module.fail_json(msg='%s' % e)
if state == 'present':
if get_vm(c, vmname) == "empty":
if resource_type == 'template':
try:
create_vm_template(c, vmname, image, zone)
except Exception as e:
module.fail_json(msg='%s' % e)
module.exit_json(changed=True, msg="deployed VM %s from template %s" % (vmname, image))
elif resource_type == 'new':
# FIXME: refactor, use keyword args.
try:
create_vm(c, vmtype, vmname, zone, vmdisk_size, vmcpus, vmnic, vmnetwork, vmmem, vmdisk_alloc, sdomain, vmcores, vmos, vmdisk_int)
except Exception as e:
module.fail_json(msg='%s' % e)
module.exit_json(changed=True, msg="deployed VM %s from scratch" % vmname)
else:
module.exit_json(changed=False, msg="You did not specify a resource type")
else:
module.exit_json(changed=False, msg="VM %s already exists" % vmname)
if state == 'started':
if vm_status(c, vmname) == 'up':
module.exit_json(changed=False, msg="VM %s is already running" % vmname)
else:
# vm_start(c, vmname)
vm_start(c, vmname, hostname, ip, netmask, gateway, domain, dns, rootpw, key)
module.exit_json(changed=True, msg="VM %s started" % vmname)
if state == 'shutdown':
if vm_status(c, vmname) == 'down':
module.exit_json(changed=False, msg="VM %s is already shutdown" % vmname)
else:
vm_stop(c, vmname)
module.exit_json(changed=True, msg="VM %s is shutting down" % vmname)
if state == 'restart':
if vm_status(c, vmname) == 'up':
vm_restart(c, vmname)
module.exit_json(changed=True, msg="VM %s is restarted" % vmname)
else:
module.exit_json(changed=False, msg="VM %s is not running" % vmname)
if state == 'absent':
if get_vm(c, vmname) == "empty":
module.exit_json(changed=False, msg="VM %s does not exist" % vmname)
else:
vm_remove(c, vmname)
module.exit_json(changed=True, msg="VM %s removed" % vmname)
if __name__ == '__main__':
main()

View File

@@ -95,7 +95,7 @@ class ProxmoxGroup:
self.group = dict()
# Data representation is not the same depending on API calls
for k, v in group.items():
if k == 'users' and isinstance(v, str):
if k == 'users' and type(v) == str:
self.group['users'] = v.split(',')
elif k == 'members':
self.group['users'] = group['members']

View File

@@ -808,8 +808,7 @@ def get_vminfo(module, proxmox, node, vmid, **kwargs):
# Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
# Convert all dict in kwargs to elements.
# For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
# Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n]
for k in list(kwargs.keys()):
if isinstance(kwargs[k], dict):
kwargs.update(kwargs[k])
@@ -818,30 +817,35 @@ def get_vminfo(module, proxmox, node, vmid, **kwargs):
# Split information by type
re_net = re.compile(r'net[0-9]')
re_dev = re.compile(r'(virtio|ide|scsi|sata)[0-9]')
for k, v in kwargs.items():
for k in kwargs.keys():
if re_net.match(k):
interface = k
k = vm[k]
k = re.search('=(.*?),', k).group(1)
mac[interface] = k
mac[k] = parse_mac(vm[k])
elif re_dev.match(k):
device = k
k = vm[k]
k = re.search('(.*?),', k).group(1)
devices[device] = k
devices[k] = parse_dev(vm[k])
results['mac'] = mac
results['devices'] = devices
results['vmid'] = int(vmid)
def settings(proxmox, vmid, node, **kwargs):
def parse_mac(netstr):
return re.search('=(.*?),', netstr).group(1)
def parse_dev(devstr):
return re.search('(.*?)(,|$)', devstr).group(1)
def settings(module, proxmox, vmid, node, name, **kwargs):
proxmox_node = proxmox.nodes(node)
# Sanitize kwargs. Remove not defined args and ensure True and False converted to int.
kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
return proxmox_node.qemu(vmid).config.set(**kwargs) is None
if proxmox_node.qemu(vmid).config.set(**kwargs) is None:
return True
else:
return False
def wait_for_task(module, proxmox, node, taskid):
@@ -912,8 +916,7 @@ def create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sock
if 'pool' in kwargs:
del kwargs['pool']
# Convert all dict in kwargs to elements.
# For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n], ipconfig[n]
# Convert all dict in kwargs to elements. For hostpci[n], ide[n], net[n], numa[n], parallel[n], sata[n], scsi[n], serial[n], virtio[n], ipconfig[n]
for k in list(kwargs.keys()):
if isinstance(kwargs[k], dict):
kwargs.update(kwargs[k])
@@ -936,9 +939,8 @@ def create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sock
# VM tags are expected to be valid and presented as a comma/semi-colon delimited string
if 'tags' in kwargs:
re_tag = re.compile(r'^[a-z0-9_][a-z0-9_\-\+\.]*$')
for tag in kwargs['tags']:
if not re_tag.match(tag):
if not re.match(r'^[a-z0-9_][a-z0-9_\-\+\.]*$', tag):
module.fail_json(msg='%s is not a valid tag' % tag)
kwargs['tags'] = ",".join(kwargs['tags'])
@@ -970,7 +972,7 @@ def create_vm(module, proxmox, vmid, newid, node, name, memory, cpu, cores, sock
if not wait_for_task(module, proxmox, node, taskid):
module.fail_json(msg='Reached timeout while waiting for creating VM. Last line in task before timeout: %s' %
proxmox_node.tasks(taskid).log.get()[:1])
proxmox_node.tasks(taskid).log.get()[:1])
return False
return True
@@ -1208,14 +1210,14 @@ def main():
if delete is not None:
try:
settings(proxmox, vmid, node, delete=delete)
settings(module, proxmox, vmid, node, name, delete=delete)
module.exit_json(changed=True, vmid=vmid, msg="Settings has deleted on VM {0} with vmid {1}".format(name, vmid))
except Exception as e:
module.fail_json(vmid=vmid, msg='Unable to delete settings on VM {0} with vmid {1}: '.format(name, vmid) + str(e))
if revert is not None:
try:
settings(proxmox, vmid, node, revert=revert)
settings(module, proxmox, vmid, node, name, revert=revert)
module.exit_json(changed=True, vmid=vmid, msg="Settings has reverted on VM {0} with vmid {1}".format(name, vmid))
except Exception as e:
module.fail_json(vmid=vmid, msg='Unable to revert settings on VM {0} with vmid {1}: Maybe is not a pending task... '.format(name, vmid) + str(e))

View File

@@ -1,348 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Lammert Hellinga (@Kogelvis) <lammert@hellinga.it>
# 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
DOCUMENTATION = r'''
---
module: proxmox_nic
short_description: Management of a NIC of a Qemu(KVM) VM in a Proxmox VE cluster.
version_added: 3.1.0
description:
- Allows you to create/update/delete a NIC on Qemu(KVM) Virtual Machines in a Proxmox VE cluster.
author: "Lammert Hellinga (@Kogelvis) <lammert@hellinga.it>"
options:
bridge:
description:
- Add this interface to the specified bridge device. The Proxmox VE default bridge is called C(vmbr0).
type: str
firewall:
description:
- Whether this interface should be protected by the firewall.
type: bool
default: false
interface:
description:
- Name of the interface, should be C(net[n]) where C(1 ≤ n ≤ 31).
type: str
required: true
link_down:
description:
- Whether this interface should be disconnected (like pulling the plug).
type: bool
default: false
mac:
description:
- C(XX:XX:XX:XX:XX:XX) should be a unique MAC address. This is automatically generated if not specified.
- When not specified this module will keep the MAC address the same when changing an existing interface.
type: str
model:
description:
- The NIC emulator model.
type: str
choices: ['e1000', 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em', 'i82551', 'i82557b', 'i82559er', 'ne2k_isa', 'ne2k_pci', 'pcnet',
'rtl8139', 'virtio', 'vmxnet3']
default: virtio
mtu:
description:
- Force MTU, for C(virtio) model only, setting will be ignored otherwise.
- Set to C(1) to use the bridge MTU.
- Value should be C(1 ≤ n ≤ 65520).
type: int
name:
description:
- Specifies the VM name. Only used on the configuration web interface.
- Required only for I(state=present).
type: str
queues:
description:
- Number of packet queues to be used on the device.
- Value should be C(0 ≤ n ≤ 16).
type: int
rate:
description:
- Rate limit in MBps (MegaBytes per second) as floating point number.
type: float
state:
description:
- Indicates desired state of the NIC.
type: str
choices: ['present', 'absent']
default: present
tag:
description:
- VLAN tag to apply to packets on this interface.
- Value should be C(1 ≤ n ≤ 4094).
type: int
trunks:
description:
- List of VLAN trunks to pass through this interface.
type: list
elements: int
vmid:
description:
- Specifies the instance ID.
type: int
extends_documentation_fragment:
- community.general.proxmox.documentation
'''
EXAMPLES = '''
- name: Create NIC net0 targeting the vm by name
community.general.proxmox_nic:
api_user: root@pam
api_password: secret
api_host: proxmoxhost
name: my_vm
interface: net0
bridge: vmbr0
tag: 3
- name: Create NIC net0 targeting the vm by id
community.general.proxmox_nic:
api_user: root@pam
api_password: secret
api_host: proxmoxhost
vmid: 103
interface: net0
bridge: vmbr0
mac: "12:34:56:C0:FF:EE"
firewall: true
- name: Delete NIC net0 targeting the vm by name
community.general.proxmox_nic:
api_user: root@pam
api_password: secret
api_host: proxmoxhost
name: my_vm
interface: net0
state: absent
'''
RETURN = '''
vmid:
description: The VM vmid.
returned: success
type: int
sample: 115
msg:
description: A short message
returned: always
type: str
sample: "Nic net0 unchanged on VM with vmid 103"
'''
try:
from proxmoxer import ProxmoxAPI
HAS_PROXMOXER = True
except ImportError:
HAS_PROXMOXER = False
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible_collections.community.general.plugins.module_utils.proxmox import proxmox_auth_argument_spec
def get_vmid(module, proxmox, name):
try:
vms = [vm['vmid'] for vm in proxmox.cluster.resources.get(type='vm') if vm.get('name') == name]
except Exception as e:
module.fail_json(msg='Error: %s occurred while retrieving VM with name = %s' % (e, name))
if not vms:
module.fail_json(msg='No VM found with name: %s' % name)
elif len(vms) > 1:
module.fail_json(msg='Multiple VMs found with name: %s, provide vmid instead' % name)
return vms[0]
def get_vm(proxmox, vmid):
return [vm for vm in proxmox.cluster.resources.get(type='vm') if vm['vmid'] == int(vmid)]
def update_nic(module, proxmox, vmid, interface, model, **kwargs):
vm = get_vm(proxmox, vmid)
try:
vminfo = proxmox.nodes(vm[0]['node']).qemu(vmid).config.get()
except Exception as e:
module.fail_json(msg='Getting information for VM with vmid = %s failed with exception: %s' % (vmid, e))
if interface in vminfo:
# Convert the current config to a dictionary
config = vminfo[interface].split(',')
config.sort()
config_current = {}
for i in config:
kv = i.split('=')
try:
config_current[kv[0]] = kv[1]
except IndexError:
config_current[kv[0]] = ''
# determine the current model nic and mac-address
models = ['e1000', 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em', 'i82551', 'i82557b',
'i82559er', 'ne2k_isa', 'ne2k_pci', 'pcnet', 'rtl8139', 'virtio', 'vmxnet3']
current_model = set(models) & set(config_current.keys())
current_model = current_model.pop()
current_mac = config_current[current_model]
# build nic config string
config_provided = "{0}={1}".format(model, current_mac)
else:
config_provided = model
if kwargs['mac']:
config_provided = "{0}={1}".format(model, kwargs['mac'])
if kwargs['bridge']:
config_provided += ",bridge={0}".format(kwargs['bridge'])
if kwargs['firewall']:
config_provided += ",firewall=1"
if kwargs['link_down']:
config_provided += ',link_down=1'
if kwargs['mtu']:
config_provided += ",mtu={0}".format(kwargs['mtu'])
if model != 'virtio':
module.warn(
'Ignoring MTU for nic {0} on VM with vmid {1}, '
'model should be set to \'virtio\': '.format(interface, vmid))
if kwargs['queues']:
config_provided += ",queues={0}".format(kwargs['queues'])
if kwargs['rate']:
config_provided += ",rate={0}".format(kwargs['rate'])
if kwargs['tag']:
config_provided += ",tag={0}".format(kwargs['tag'])
if kwargs['trunks']:
config_provided += ",trunks={0}".format(';'.join(str(x) for x in kwargs['trunks']))
net = {interface: config_provided}
vm = get_vm(proxmox, vmid)
if ((interface not in vminfo) or (vminfo[interface] != config_provided)):
if not module.check_mode:
proxmox.nodes(vm[0]['node']).qemu(vmid).config.set(**net)
return True
return False
def delete_nic(module, proxmox, vmid, interface):
vm = get_vm(proxmox, vmid)
vminfo = proxmox.nodes(vm[0]['node']).qemu(vmid).config.get()
if interface in vminfo:
if not module.check_mode:
proxmox.nodes(vm[0]['node']).qemu(vmid).config.set(vmid=vmid, delete=interface)
return True
return False
def main():
module_args = proxmox_auth_argument_spec()
nic_args = dict(
bridge=dict(type='str'),
firewall=dict(type='bool', default=False),
interface=dict(type='str', required=True),
link_down=dict(type='bool', default=False),
mac=dict(type='str'),
model=dict(choices=['e1000', 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em',
'i82551', 'i82557b', 'i82559er', 'ne2k_isa', 'ne2k_pci', 'pcnet',
'rtl8139', 'virtio', 'vmxnet3'], default='virtio'),
mtu=dict(type='int'),
name=dict(type='str'),
queues=dict(type='int'),
rate=dict(type='float'),
state=dict(default='present', choices=['present', 'absent']),
tag=dict(type='int'),
trunks=dict(type='list', elements='int'),
vmid=dict(type='int'),
)
module_args.update(nic_args)
module = AnsibleModule(
argument_spec=module_args,
required_together=[('api_token_id', 'api_token_secret')],
required_one_of=[('name', 'vmid'), ('api_password', 'api_token_id')],
supports_check_mode=True,
)
if not HAS_PROXMOXER:
module.fail_json(msg='proxmoxer required for this module')
api_host = module.params['api_host']
api_password = module.params['api_password']
api_token_id = module.params['api_token_id']
api_token_secret = module.params['api_token_secret']
api_user = module.params['api_user']
interface = module.params['interface']
model = module.params['model']
name = module.params['name']
state = module.params['state']
validate_certs = module.params['validate_certs']
vmid = module.params['vmid']
auth_args = {'user': api_user}
if not (api_token_id and api_token_secret):
auth_args['password'] = api_password
else:
auth_args['token_name'] = api_token_id
auth_args['token_value'] = api_token_secret
try:
proxmox = ProxmoxAPI(api_host, verify_ssl=validate_certs, **auth_args)
except Exception as e:
module.fail_json(msg='authorization on proxmox cluster failed with exception: %s' % e)
# If vmid is not defined then retrieve its value from the vm name,
if not vmid:
vmid = get_vmid(module, proxmox, name)
# Ensure VM id exists
if not get_vm(proxmox, vmid):
module.fail_json(vmid=vmid, msg='VM with vmid = %s does not exist in cluster' % vmid)
if state == 'present':
try:
if update_nic(module, proxmox, vmid, interface, model,
bridge=module.params['bridge'],
firewall=module.params['firewall'],
link_down=module.params['link_down'],
mac=module.params['mac'],
mtu=module.params['mtu'],
queues=module.params['queues'],
rate=module.params['rate'],
tag=module.params['tag'],
trunks=module.params['trunks']):
module.exit_json(changed=True, vmid=vmid, msg="Nic {0} updated on VM with vmid {1}".format(interface, vmid))
else:
module.exit_json(vmid=vmid, msg="Nic {0} unchanged on VM with vmid {1}".format(interface, vmid))
except Exception as e:
module.fail_json(vmid=vmid, msg='Unable to change nic {0} on VM with vmid {1}: '.format(interface, vmid) + str(e))
elif state == 'absent':
try:
if delete_nic(module, proxmox, vmid, interface):
module.exit_json(changed=True, vmid=vmid, msg="Nic {0} deleted on VM with vmid {1}".format(interface, vmid))
else:
module.exit_json(vmid=vmid, msg="Nic {0} does not exist on VM with vmid {1}".format(interface, vmid))
except Exception as e:
module.fail_json(vmid=vmid, msg='Unable to delete nic {0} on VM with vmid {1}: '.format(interface, vmid) + str(e))
if __name__ == '__main__':
main()

View File

@@ -547,7 +547,7 @@ class RHEVConn(object):
def set_Memory_Policy(self, name, memory_policy):
VM = self.get_VM(name)
VM.memory_policy.guaranteed = int(memory_policy) * 1024 * 1024 * 1024
VM.memory_policy.guaranteed = int(int(memory_policy) * 1024 * 1024 * 1024)
try:
VM.update()
setMsg("The memory policy has been updated.")
@@ -1260,7 +1260,7 @@ def core(module):
r = RHEV(module)
state = module.params.get('state')
state = module.params.get('state', 'present')
if state == 'ping':
r.test()

View File

@@ -139,14 +139,16 @@ from ansible.module_utils.basic import AnsibleModule
def read_serverless_config(module):
path = module.params.get('service_path')
full_path = os.path.join(path, 'serverless.yml')
try:
with open(full_path) as sls_config:
with open(os.path.join(path, 'serverless.yml')) as sls_config:
config = yaml.safe_load(sls_config.read())
return config
except IOError as e:
module.fail_json(msg="Could not open serverless.yml in {0}. err: {1}".format(full_path, str(e)))
module.fail_json(msg="Could not open serverless.yml in {0}. err: {1}".format(path, str(e)))
module.fail_json(msg="Failed to open serverless config at {0}".format(
os.path.join(path, 'serverless.yml')))
def get_service_name(module, stage):
@@ -180,6 +182,7 @@ def main():
service_path = module.params.get('service_path')
state = module.params.get('state')
functions = module.params.get('functions')
region = module.params.get('region')
stage = module.params.get('stage')
deploy = module.params.get('deploy', True)
@@ -190,7 +193,7 @@ def main():
if serverless_bin_path is not None:
command = serverless_bin_path + " "
else:
command = module.get_bin_path("serverless") + " "
command = "serverless "
if state == 'present':
command += 'deploy '

View File

@@ -33,19 +33,6 @@ options:
vars.tf/main.tf/etc to use.
type: path
required: true
plugin_paths:
description:
- List of paths containing Terraform plugin executable files.
- Plugin executables can be downloaded from U(https://releases.hashicorp.com/).
- When set, the plugin discovery and auto-download behavior of Terraform is disabled.
- The directory structure in the plugin path can be tricky. The Terraform docs
U(https://learn.hashicorp.com/tutorials/terraform/automate-terraform#pre-installed-plugins)
show a simple directory of files, but actually, the directory structure
has to follow the same structure you would see if Terraform auto-downloaded the plugins.
See the examples below for a tree output of an example plugin directory.
type: list
elements: path
version_added: 3.0.0
workspace:
description:
- The terraform workspace to work with.
@@ -107,12 +94,6 @@ options:
you intend to provision an entirely new Terraform deployment.
default: false
type: bool
overwrite_init:
description:
- Run init even if C(.terraform/terraform.tfstate) already exists in I(project_path).
default: true
type: bool
version_added: '3.2.0'
backend_config:
description:
- A group of key-values to provide at init stage to the -backend-config parameter.
@@ -160,28 +141,6 @@ EXAMPLES = """
backend_config_files:
- /path/to/backend_config_file_1
- /path/to/backend_config_file_2
- name: Disable plugin discovery and auto-download by setting plugin_paths
community.general.terraform:
project_path: 'project/'
state: "{{ state }}"
force_init: true
plugin_paths:
- /path/to/plugins_dir_1
- /path/to/plugins_dir_2
### Example directory structure for plugin_paths example
# $ tree /path/to/plugins_dir_1
# /path/to/plugins_dir_1/
# └── registry.terraform.io
# └── hashicorp
# └── vsphere
# ├── 1.24.0
# │ └── linux_amd64
# │ └── terraform-provider-vsphere_v1.24.0_x4
# └── 1.26.0
# └── linux_amd64
# └── terraform-provider-vsphere_v1.26.0_x4
"""
RETURN = """
@@ -233,7 +192,7 @@ def get_version(bin_path):
def preflight_validation(bin_path, project_path, version, variables_args=None, plan_file=None):
if project_path is None or '/' not in project_path:
if project_path in [None, ''] or '/' not in project_path:
module.fail_json(msg="Path for Terraform project can not be None or ''.")
if not os.path.exists(bin_path):
module.fail_json(msg="Path for Terraform binary '{0}' doesn't exist on this host - check the path and try again please.".format(bin_path))
@@ -253,7 +212,7 @@ def _state_args(state_file):
return []
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths):
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure):
command = [bin_path, 'init', '-input=false']
if backend_config:
for key, val in backend_config.items():
@@ -266,9 +225,6 @@ def init_plugins(bin_path, project_path, backend_config, backend_config_files, i
command.extend(['-backend-config', f])
if init_reconfigure:
command.extend(['-reconfigure'])
if plugin_paths:
for plugin_path in plugin_paths:
command.extend(['-plugin-dir', plugin_path])
rc, out, err = module.run_command(command, check_rc=True, cwd=project_path)
@@ -339,7 +295,6 @@ def main():
argument_spec=dict(
project_path=dict(required=True, type='path'),
binary_path=dict(type='path'),
plugin_paths=dict(type='list', elements='path'),
workspace=dict(required=False, type='str', default='default'),
purge_workspace=dict(type='bool', default=False),
state=dict(default='present', choices=['present', 'absent', 'planned']),
@@ -354,7 +309,6 @@ def main():
backend_config=dict(type='dict', default=None),
backend_config_files=dict(type='list', elements='path', default=None),
init_reconfigure=dict(required=False, type='bool', default=False),
overwrite_init=dict(type='bool', default=True),
),
required_if=[('state', 'planned', ['plan_file'])],
supports_check_mode=True,
@@ -362,7 +316,6 @@ def main():
project_path = module.params.get('project_path')
bin_path = module.params.get('binary_path')
plugin_paths = module.params.get('plugin_paths')
workspace = module.params.get('workspace')
purge_workspace = module.params.get('purge_workspace')
state = module.params.get('state')
@@ -374,7 +327,6 @@ def main():
backend_config = module.params.get('backend_config')
backend_config_files = module.params.get('backend_config_files')
init_reconfigure = module.params.get('init_reconfigure')
overwrite_init = module.params.get('overwrite_init')
if bin_path is not None:
command = [bin_path]
@@ -391,8 +343,7 @@ def main():
APPLY_ARGS = ('apply', '-no-color', '-input=false', '-auto-approve')
if force_init:
if overwrite_init or not os.path.isfile(os.path.join(project_path, ".terraform", "terraform.tfstate")):
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths)
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure)
workspace_ctx = get_workspace_context(command[0], project_path)
if workspace_ctx["current"] != workspace:

View File

@@ -0,0 +1,175 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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
DOCUMENTATION = r'''
---
module: online_server_facts
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: Deprecated in favour of C(_info) module.
alternative: Use M(community.general.online_server_info) instead.
short_description: Gather facts about Online servers.
description:
- Gather facts about the servers.
- U(https://www.online.net/en/dedicated-server)
author:
- "Remy Leone (@sieben)"
extends_documentation_fragment:
- community.general.online
'''
EXAMPLES = r'''
- name: Gather Online server facts
community.general.online_server_facts:
api_token: '0d1627e8-bbf0-44c5-a46f-5c4d3aef033f'
'''
RETURN = r'''
---
online_server_facts:
description: Response from Online API
returned: success
type: complex
sample:
"online_server_facts": [
{
"abuse": "abuse@example.com",
"anti_ddos": false,
"bmc": {
"session_key": null
},
"boot_mode": "normal",
"contacts": {
"owner": "foobar",
"tech": "foobar"
},
"disks": [
{
"$ref": "/api/v1/server/hardware/disk/68452"
},
{
"$ref": "/api/v1/server/hardware/disk/68453"
}
],
"drive_arrays": [
{
"disks": [
{
"$ref": "/api/v1/server/hardware/disk/68452"
},
{
"$ref": "/api/v1/server/hardware/disk/68453"
}
],
"raid_controller": {
"$ref": "/api/v1/server/hardware/raidController/9910"
},
"raid_level": "RAID1"
}
],
"hardware_watch": true,
"hostname": "sd-42",
"id": 42,
"ip": [
{
"address": "195.154.172.149",
"mac": "28:92:4a:33:5e:c6",
"reverse": "195-154-172-149.rev.poneytelecom.eu.",
"switch_port_state": "up",
"type": "public"
},
{
"address": "10.90.53.212",
"mac": "28:92:4a:33:5e:c7",
"reverse": null,
"switch_port_state": "up",
"type": "private"
}
],
"last_reboot": "2018-08-23T08:32:03.000Z",
"location": {
"block": "A",
"datacenter": "DC3",
"position": 19,
"rack": "A23",
"room": "4 4-4"
},
"network": {
"ip": [
"195.154.172.149"
],
"ipfo": [],
"private": [
"10.90.53.212"
]
},
"offer": "Pro-1-S-SATA",
"os": {
"name": "FreeBSD",
"version": "11.1-RELEASE"
},
"power": "ON",
"proactive_monitoring": false,
"raid_controllers": [
{
"$ref": "/api/v1/server/hardware/raidController/9910"
}
],
"support": "Basic service level"
}
]
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.online import (
Online, OnlineException, online_argument_spec
)
class OnlineServerFacts(Online):
def __init__(self, module):
super(OnlineServerFacts, self).__init__(module)
self.name = 'api/v1/server'
def _get_server_detail(self, server_path):
try:
return self.get(path=server_path).json
except OnlineException as exc:
self.module.fail_json(msg="A problem occurred while fetching: %s (%s)" % (server_path, exc))
def all_detailed_servers(self):
servers_api_path = self.get_resources()
server_data = (
self._get_server_detail(server_api_path)
for server_api_path in servers_api_path
)
return [s for s in server_data if s is not None]
def main():
module = AnsibleModule(
argument_spec=online_argument_spec(),
supports_check_mode=True,
)
try:
servers_facts = OnlineServerFacts(module).all_detailed_servers()
module.exit_json(
ansible_facts={'online_server_facts': servers_facts}
)
except OnlineException as exc:
module.fail_json(msg=exc.message)
if __name__ == '__main__':
main()

View File

@@ -32,13 +32,11 @@ EXAMPLES = r'''
'''
RETURN = r'''
---
online_server_info:
description:
- Response from Online API.
- "For more details please refer to: U(https://console.online.net/en/api/)."
description: Response from Online API
returned: success
type: list
elements: dict
type: complex
sample:
"online_server_info": [
{

View File

@@ -0,0 +1,76 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 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
DOCUMENTATION = r'''
---
module: online_user_facts
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: Deprecated in favour of C(_info) module.
alternative: Use M(community.general.online_user_info) instead.
short_description: Gather facts about Online user.
description:
- Gather facts about the user.
author:
- "Remy Leone (@sieben)"
extends_documentation_fragment:
- community.general.online
'''
EXAMPLES = r'''
- name: Gather Online user facts
community.general.online_user_facts:
'''
RETURN = r'''
---
online_user_facts:
description: Response from Online API
returned: success
type: complex
sample:
"online_user_facts": {
"company": "foobar LLC",
"email": "foobar@example.com",
"first_name": "foo",
"id": 42,
"last_name": "bar",
"login": "foobar"
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.online import (
Online, OnlineException, online_argument_spec
)
class OnlineUserFacts(Online):
def __init__(self, module):
super(OnlineUserFacts, self).__init__(module)
self.name = 'api/v1/user'
def main():
module = AnsibleModule(
argument_spec=online_argument_spec(),
supports_check_mode=True,
)
try:
module.exit_json(
ansible_facts={'online_user_facts': OnlineUserFacts(module).get_resources()}
)
except OnlineException as exc:
module.fail_json(msg=exc.message)
if __name__ == '__main__':
main()

View File

@@ -7,6 +7,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = r'''
---
module: online_user_info
short_description: Gather information about Online user.
description:
@@ -15,6 +16,7 @@ author:
- "Remy Leone (@sieben)"
extends_documentation_fragment:
- community.general.online
'''
EXAMPLES = r'''
@@ -27,12 +29,11 @@ EXAMPLES = r'''
'''
RETURN = r'''
---
online_user_info:
description:
- Response from Online API.
- "For more details please refer to: U(https://console.online.net/en/api/)."
description: Response from Online API
returned: success
type: dict
type: complex
sample:
"online_user_info": {
"company": "foobar LLC",

View File

@@ -31,7 +31,7 @@ short_description: Manages OpenNebula images
description:
- Manages OpenNebula images
requirements:
- pyone
- python-oca
options:
api_url:
description:
@@ -88,7 +88,7 @@ EXAMPLES = '''
- name: Print the IMAGE properties
ansible.builtin.debug:
var: result
msg: result
- name: Rename existing IMAGE
community.general.one_image:
@@ -168,20 +168,21 @@ running_vms:
'''
try:
import pyone
HAS_PYONE = True
import oca
HAS_OCA = True
except ImportError:
HAS_PYONE = False
HAS_OCA = False
from ansible.module_utils.basic import AnsibleModule
import os
def get_image(module, client, predicate):
pool = oca.ImagePool(client)
# Filter -2 means fetch all images user can Use
pool = client.imagepool.info(-2, -1, -1, -1)
pool.info(filter=-2)
for image in pool.IMAGE:
for image in pool:
if predicate(image):
return image
@@ -189,11 +190,11 @@ def get_image(module, client, predicate):
def get_image_by_name(module, client, image_name):
return get_image(module, client, lambda image: (image.NAME == image_name))
return get_image(module, client, lambda image: (image.name == image_name))
def get_image_by_id(module, client, image_id):
return get_image(module, client, lambda image: (image.ID == image_id))
return get_image(module, client, lambda image: (image.id == image_id))
def get_image_instance(module, client, requested_id, requested_name):
@@ -207,28 +208,30 @@ IMAGE_STATES = ['INIT', 'READY', 'USED', 'DISABLED', 'LOCKED', 'ERROR', 'CLONE',
def get_image_info(image):
image.info()
info = {
'id': image.ID,
'name': image.NAME,
'state': IMAGE_STATES[image.STATE],
'running_vms': image.RUNNING_VMS,
'used': bool(image.RUNNING_VMS),
'user_name': image.UNAME,
'user_id': image.UID,
'group_name': image.GNAME,
'group_id': image.GID,
'id': image.id,
'name': image.name,
'state': IMAGE_STATES[image.state],
'running_vms': image.running_vms,
'used': bool(image.running_vms),
'user_name': image.uname,
'user_id': image.uid,
'group_name': image.gname,
'group_id': image.gid,
}
return info
def wait_for_state(module, client, image_id, wait_timeout, state_predicate):
def wait_for_state(module, image, wait_timeout, state_predicate):
import time
start_time = time.time()
while (time.time() - start_time) < wait_timeout:
image = client.image.info(image_id)
state = image.STATE
image.info()
state = image.state
if state_predicate(state):
return image
@@ -238,19 +241,19 @@ def wait_for_state(module, client, image_id, wait_timeout, state_predicate):
module.fail_json(msg="Wait timeout has expired!")
def wait_for_ready(module, client, image_id, wait_timeout=60):
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('READY')]))
def wait_for_ready(module, image, wait_timeout=60):
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('READY')]))
def wait_for_delete(module, client, image_id, wait_timeout=60):
return wait_for_state(module, client, image_id, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
def wait_for_delete(module, image, wait_timeout=60):
return wait_for_state(module, image, wait_timeout, lambda state: (state in [IMAGE_STATES.index('DELETE')]))
def enable_image(module, client, image, enable):
image = client.image.info(image.ID)
image.info()
changed = False
state = image.STATE
state = image.state
if state not in [IMAGE_STATES.index('READY'), IMAGE_STATES.index('DISABLED'), IMAGE_STATES.index('ERROR')]:
if enable:
@@ -263,7 +266,7 @@ def enable_image(module, client, image, enable):
changed = True
if changed and not module.check_mode:
client.image.enable(image.ID, enable)
client.call('image.enable', image.id, enable)
result = get_image_info(image)
result['changed'] = changed
@@ -273,7 +276,7 @@ def enable_image(module, client, image, enable):
def clone_image(module, client, image, new_name):
if new_name is None:
new_name = "Copy of " + image.NAME
new_name = "Copy of " + image.name
tmp_image = get_image_by_name(module, client, new_name)
if tmp_image:
@@ -281,13 +284,13 @@ def clone_image(module, client, image, new_name):
result['changed'] = False
return result
if image.STATE == IMAGE_STATES.index('DISABLED'):
if image.state == IMAGE_STATES.index('DISABLED'):
module.fail_json(msg="Cannot clone DISABLED image")
if not module.check_mode:
new_id = client.image.clone(image.ID, new_name)
wait_for_ready(module, client, new_id)
image = client.image.info(new_id)
new_id = client.call('image.clone', image.id, new_name)
image = get_image_by_id(module, client, new_id)
wait_for_ready(module, image)
result = get_image_info(image)
result['changed'] = True
@@ -299,7 +302,7 @@ def rename_image(module, client, image, new_name):
if new_name is None:
module.fail_json(msg="'new_name' option has to be specified when the state is 'renamed'")
if new_name == image.NAME:
if new_name == image.name:
result = get_image_info(image)
result['changed'] = False
return result
@@ -309,7 +312,7 @@ def rename_image(module, client, image, new_name):
module.fail_json(msg="Name '" + new_name + "' is already taken by IMAGE with id=" + str(tmp_image.id))
if not module.check_mode:
client.image.rename(image.ID, new_name)
client.call('image.rename', image.id, new_name)
result = get_image_info(image)
result['changed'] = True
@@ -321,12 +324,12 @@ def delete_image(module, client, image):
if not image:
return {'changed': False}
if image.RUNNING_VMS > 0:
module.fail_json(msg="Cannot delete image. There are " + str(image.RUNNING_VMS) + " VMs using it.")
if image.running_vms > 0:
module.fail_json(msg="Cannot delete image. There are " + str(image.running_vms) + " VMs using it.")
if not module.check_mode:
client.image.delete(image.ID)
wait_for_delete(module, client, image.ID)
client.call('image.delete', image.id)
wait_for_delete(module, image)
return {'changed': True}
@@ -375,8 +378,8 @@ def main():
mutually_exclusive=[['id', 'name']],
supports_check_mode=True)
if not HAS_PYONE:
module.fail_json(msg='This module requires pyone to work!')
if not HAS_OCA:
module.fail_json(msg='This module requires python-oca to work!')
auth = get_connection_info(module)
params = module.params
@@ -385,7 +388,7 @@ def main():
state = params.get('state')
enabled = params.get('enabled')
new_name = params.get('new_name')
client = pyone.OneServer(auth.url, session=auth.username + ':' + auth.password)
client = oca.Client(auth.username + ':' + auth.password, auth.url)
result = {}

View File

@@ -0,0 +1 @@
one_image_info.py

View File

@@ -261,6 +261,9 @@ def main():
module = AnsibleModule(argument_spec=fields,
mutually_exclusive=[['ids', 'name']],
supports_check_mode=True)
if module._name in ('one_image_facts', 'community.general.one_image_facts'):
module.deprecate("The 'one_image_facts' module has been renamed to 'one_image_info'",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
if not HAS_PYONE:
module.fail_json(msg='This module requires pyone to work!')

View File

@@ -0,0 +1,195 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_affinity_label_facts
short_description: Retrieve information about one or more oVirt/RHV affinity labels
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_affinity_label_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV affinity labels."
notes:
- "This module returns a variable C(ovirt_affinity_labels), which
contains a list of affinity labels. You need to register the result with
the I(register) keyword to use it."
options:
name:
description:
- "Name of the affinity labels which should be listed."
vm:
description:
- "Name of the VM, which affinity labels should be listed."
host:
description:
- "Name of the host, which affinity labels should be listed."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all affinity labels, which names start with label
ovirt_affinity_label_info:
name: label*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_affinity_labels }}"
- name: >
Gather information about all affinity labels, which are assigned to VMs
which names start with postgres
ovirt_affinity_label_info:
vm: postgres*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_affinity_labels }}"
- name: >
Gather information about all affinity labels, which are assigned to hosts
which names start with west
ovirt_affinity_label_info:
host: west*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_affinity_labels }}"
- name: >
Gather information about all affinity labels, which are assigned to hosts
which names start with west or VMs which names start with postgres
ovirt_affinity_label_info:
host: west*
vm: postgres*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_affinity_labels }}"
'''
RETURN = '''
ovirt_affinity_labels:
description: "List of dictionaries describing the affinity labels. Affinity labels attributes are mapped to dictionary keys,
all affinity labels attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/affinity_label."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
name=dict(default=None),
host=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_affinity_label_facts', 'community.general.ovirt_affinity_label_facts')
if is_old_facts:
module.deprecate("The 'ovirt_affinity_label_facts' module has been renamed to 'ovirt_affinity_label_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
affinity_labels_service = connection.system_service().affinity_labels_service()
labels = []
all_labels = affinity_labels_service.list()
if module.params['name']:
labels.extend([
l for l in all_labels
if fnmatch.fnmatch(l.name, module.params['name'])
])
if module.params['host']:
hosts_service = connection.system_service().hosts_service()
if search_by_name(hosts_service, module.params['host']) is None:
raise Exception("Host '%s' was not found." % module.params['host'])
labels.extend([
label
for label in all_labels
for host in connection.follow_link(label.hosts)
if fnmatch.fnmatch(hosts_service.service(host.id).get().name, module.params['host'])
])
if module.params['vm']:
vms_service = connection.system_service().vms_service()
if search_by_name(vms_service, module.params['vm']) is None:
raise Exception("Vm '%s' was not found." % module.params['vm'])
labels.extend([
label
for label in all_labels
for vm in connection.follow_link(label.vms)
if fnmatch.fnmatch(vms_service.service(vm.id).get().name, module.params['vm'])
])
if not (module.params['vm'] or module.params['host'] or module.params['name']):
labels = all_labels
result = dict(
ovirt_affinity_labels=[
get_dict_of_struct(
struct=l,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for l in labels
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,97 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Ansible Project
# 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
DOCUMENTATION = '''
---
module: ovirt_api_facts
short_description: Retrieve information about the oVirt/RHV API
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_api_info) instead.
description:
- "Retrieve information about the oVirt/RHV API."
notes:
- "This module returns a variable C(ovirt_api),
which contains a information about oVirt/RHV API. You need to register the result with
the I(register) keyword to use it."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information oVirt API
ovirt_api_info:
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_api }}"
'''
RETURN = '''
ovirt_api:
description: "Dictionary describing the oVirt API information.
Api attributes are mapped to dictionary keys,
all API attributes can be found at following
url: https://ovirt.example.com/ovirt-engine/api/model#types/api."
returned: On success.
type: dict
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec()
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_api_facts', 'community.general.ovirt_api_facts')
if is_old_facts:
module.deprecate("The 'ovirt_api_facts' module has been renamed to 'ovirt_api_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
api = connection.system_service().get()
result = dict(
ovirt_api=get_dict_of_struct(
struct=api,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
)
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,124 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_cluster_facts
short_description: Retrieve information about one or more oVirt/RHV clusters
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_cluster_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV clusters."
notes:
- "This module returns a variable C(ovirt_clusters), which
contains a list of clusters. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search cluster X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all clusters which names start with production
ovirt_cluster_info:
pattern:
name: 'production*'
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_clusters }}"
'''
RETURN = '''
ovirt_clusters:
description: "List of dictionaries describing the clusters. Cluster attributes are mapped to dictionary keys,
all clusters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/cluster."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_cluster_facts', 'community.general.ovirt_cluster_facts')
if is_old_facts:
module.deprecate("The 'ovirt_cluster_facts' module has been renamed to 'ovirt_cluster_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
clusters_service = connection.system_service().clusters_service()
clusters = clusters_service.list(search=module.params['pattern'])
result = dict(
ovirt_clusters=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in clusters
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,107 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# 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
DOCUMENTATION = '''
---
module: ovirt_datacenter_facts
short_description: Retrieve information about one or more oVirt/RHV datacenters
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_datacenter_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV datacenters."
notes:
- "This module returns a variable C(ovirt_datacenters), which
contains a list of datacenters. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search datacenter I(X) use following pattern: I(name=X)"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all data centers which names start with production
ovirt_datacenter_info:
pattern: name=production*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_datacenters }}"
'''
RETURN = '''
ovirt_datacenters:
description: "List of dictionaries describing the datacenters. Datacenter attributes are mapped to dictionary keys,
all datacenters attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/data_center."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_datacenter_facts', 'community.general.ovirt_datacenter_facts')
if is_old_facts:
module.deprecate("The 'ovirt_datacenter_facts' module has been renamed to 'ovirt_datacenter_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
datacenters_service = connection.system_service().data_centers_service()
datacenters = datacenters_service.list(search=module.params['pattern'])
result = dict(
ovirt_datacenters=[
get_dict_of_struct(
struct=d,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for d in datacenters
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,124 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_disk_facts
short_description: Retrieve information about one or more oVirt/RHV disks
author: "Katerina Koukiou (@KKoukiou)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_disk_info) instead
description:
- "Retrieve information about one or more oVirt/RHV disks."
notes:
- "This module returns a variable C(ovirt_disks), which
contains a list of disks. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search Disk X from storage Y use following pattern:
name=X and storage.name=Y"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all Disks which names start with centos
ovirt_disk_info:
pattern: name=centos*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_disks }}"
'''
RETURN = '''
ovirt_disks:
description: "List of dictionaries describing the Disks. Disk attributes are mapped to dictionary keys,
all Disks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/disk."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_disk_facts', 'community.general.ovirt_disk_facts')
if is_old_facts:
module.deprecate("The 'ovirt_disk_facts' module has been renamed to 'ovirt_disk_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
disks_service = connection.system_service().disks_service()
disks = disks_service.list(
search=module.params['pattern'],
)
result = dict(
ovirt_disks=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in disks
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,169 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright: (c) 2019, Ansible Project
# 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
DOCUMENTATION = '''
---
module: ovirt_event_facts
short_description: This module can be used to retrieve information about one or more oVirt/RHV events
author: "Chris Keller (@nasx)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_event_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV events."
options:
case_sensitive:
description:
- "Indicates if the search performed using the search parameter should be performed taking case
into account. The default value is true, which means that case is taken into account. If you
want to search ignoring case set it to false."
required: false
default: true
type: bool
from_:
description:
- "Indicates the event index after which events should be returned. The indexes of events are
strictly increasing, so when this parameter is used only the events with greater indexes
will be returned."
required: false
type: int
max:
description:
- "Sets the maximum number of events to return. If not specified all the events are returned."
required: false
type: int
search:
description:
- "Search term which is accepted by the oVirt/RHV API."
- "For example to search for events of severity alert use the following pattern: severity=alert"
required: false
type: str
headers:
description:
- "Additional HTTP headers."
required: false
type: str
query:
description:
- "Additional URL query parameters."
required: false
type: str
wait:
description:
- "If True wait for the response."
required: false
default: true
type: bool
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain the auth parameter for simplicity,
# look at the ovirt_auth module to see how to reuse authentication.
- name: Return all events
ovirt_event_info:
register: result
- name: Return the last 10 events
ovirt_event_info:
max: 10
register: result
- name: Return all events of type alert
ovirt_event_info:
search: "severity=alert"
register: result
- ansible.builtin.debug:
msg: "{{ result.ovirt_events }}"
'''
RETURN = '''
ovirt_events:
description: "List of dictionaries describing the events. Event attributes are mapped to dictionary keys.
All event attributes can be found at the following url:
http://ovirt.github.io/ovirt-engine-api-model/master/#types/event"
returned: On success."
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
case_sensitive=dict(default=True, type='bool', required=False),
from_=dict(default=None, type='int', required=False),
max=dict(default=None, type='int', required=False),
search=dict(default='', required=False),
headers=dict(default='', required=False),
query=dict(default='', required=False),
wait=dict(default=True, type='bool', required=False)
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_event_facts', 'community.general.ovirt_event_facts')
if is_old_facts:
module.deprecate("The 'ovirt_event_facts' module has been renamed to 'ovirt_event_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
events_service = connection.system_service().events_service()
events = events_service.list(
case_sensitive=module.params['case_sensitive'],
from_=module.params['from_'],
max=module.params['max'],
search=module.params['search'],
headers=module.params['headers'],
query=module.params['query'],
wait=module.params['wait']
)
result = dict(
ovirt_events=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in events
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,164 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_external_provider_facts
short_description: Retrieve information about one or more oVirt/RHV external providers
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_external_provider_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV external providers."
notes:
- "This module returns a variable C(ovirt_external_providers), which
contains a list of external_providers. You need to register the result with
the I(register) keyword to use it."
options:
type:
description:
- "Type of the external provider."
choices: ['os_image', 'os_network', 'os_volume', 'foreman']
required: true
type: str
name:
description:
- "Name of the external provider, can be used as glob expression."
type: str
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all image external providers named glance
ovirt_external_provider_info:
type: os_image
name: glance
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_external_providers }}"
'''
RETURN = '''
ovirt_external_providers:
description:
- "List of dictionaries. Content depends on I(type)."
- "For type C(foreman), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/external_host_provider."
- "For type C(os_image), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_image_provider."
- "For type C(os_volume), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_volume_provider."
- "For type C(os_network), attributes appearing in the dictionary can be found on your oVirt/RHV instance
at the following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/openstack_network_provider."
returned: On success
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def _external_provider_service(provider_type, system_service):
if provider_type == 'os_image':
return system_service.openstack_image_providers_service()
elif provider_type == 'os_network':
return system_service.openstack_network_providers_service()
elif provider_type == 'os_volume':
return system_service.openstack_volume_providers_service()
elif provider_type == 'foreman':
return system_service.external_host_providers_service()
def main():
argument_spec = ovirt_info_full_argument_spec(
name=dict(default=None, required=False),
type=dict(
required=True,
choices=['os_image', 'os_network', 'os_volume', 'foreman'],
aliases=['provider'],
),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_external_provider_facts', 'community.general.ovirt_external_provider_facts')
if is_old_facts:
module.deprecate("The 'ovirt_external_provider_facts' module has been renamed to 'ovirt_external_provider_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
external_providers_service = _external_provider_service(
provider_type=module.params.pop('type'),
system_service=connection.system_service(),
)
if module.params['name']:
external_providers = [
e for e in external_providers_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
external_providers = external_providers_service.list()
result = dict(
ovirt_external_providers=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in external_providers
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,122 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_group_facts
short_description: Retrieve information about one or more oVirt/RHV groups
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_group_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV groups."
notes:
- "This module returns a variable C(ovirt_groups), which
contains a list of groups. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search group X use following pattern: name=X"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all groups which names start with admin
ovirt_group_info:
pattern: name=admin*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_groups }}"
'''
RETURN = '''
ovirt_groups:
description: "List of dictionaries describing the groups. Group attributes are mapped to dictionary keys,
all groups attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/group."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_group_facts', 'community.general.ovirt_group_facts')
if is_old_facts:
module.deprecate("The 'ovirt_group_facts' module has been renamed to 'ovirt_group_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
groups_service = connection.system_service().groups_service()
groups = groups_service.list(search=module.params['pattern'])
result = dict(
ovirt_groups=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in groups
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,148 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# 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
DOCUMENTATION = '''
---
module: ovirt_host_facts
short_description: Retrieve information about one or more oVirt/RHV hosts
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_host_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV hosts."
notes:
- "This module returns a variable C(ovirt_hosts), which
contains a list of hosts. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search host X from datacenter Y use following pattern:
name=X and datacenter=Y"
all_content:
description:
- "If I(true) all the attributes of the hosts should be
included in the response."
default: False
type: bool
cluster_version:
description:
- "Filter the hosts based on the cluster version."
type: str
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all hosts which names start with host and belong to data center west
ovirt_host_info:
pattern: name=host* and datacenter=west
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_hosts }}"
- name: Gather information about all hosts with cluster version 4.2
ovirt_host_info:
pattern: name=host*
cluster_version: "4.2"
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_hosts }}"
'''
RETURN = '''
ovirt_hosts:
description: "List of dictionaries describing the hosts. Host attributes are mapped to dictionary keys,
all hosts attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def get_filtered_hosts(cluster_version, hosts, connection):
# Filtering by cluster version returns only those which have same cluster version as input
filtered_hosts = []
for host in hosts:
cluster = connection.follow_link(host.cluster)
cluster_version_host = str(cluster.version.major) + '.' + str(cluster.version.minor)
if cluster_version_host == cluster_version:
filtered_hosts.append(host)
return filtered_hosts
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
all_content=dict(default=False, type='bool'),
cluster_version=dict(default=None, type='str'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_host_facts', 'community.general.ovirt_host_facts')
if is_old_facts:
module.deprecate("The 'ovirt_host_facts' module has been renamed to 'ovirt_host_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
hosts_service = connection.system_service().hosts_service()
hosts = hosts_service.list(
search=module.params['pattern'],
all_content=module.params['all_content']
)
cluster_version = module.params.get('cluster_version')
if cluster_version is not None:
hosts = get_filtered_hosts(cluster_version, hosts, connection)
result = dict(
ovirt_hosts=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in hosts
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,186 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
# 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
DOCUMENTATION = '''
---
module: ovirt_host_storage_facts
short_description: Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)
author: "Daniel Erez (@derez)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_host_storage_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV HostStorages (applicable only for block storage)."
options:
host:
description:
- "Host to get device list from."
required: true
iscsi:
description:
- "Dictionary with values for iSCSI storage type:"
suboptions:
address:
description:
- "Address of the iSCSI storage server."
target:
description:
- "The target IQN for the storage device."
username:
description:
- "A CHAP user name for logging into a target."
password:
description:
- "A CHAP password for logging into a target."
portal:
description:
- "The portal being used to connect with iscsi."
fcp:
description:
- "Dictionary with values for fibre channel storage type:"
suboptions:
address:
description:
- "Address of the fibre channel storage server."
port:
description:
- "Port of the fibre channel storage server."
lun_id:
description:
- "LUN id."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about HostStorages with specified target and address
ovirt_host_storage_info:
host: myhost
iscsi:
target: iqn.2016-08-09.domain-01:nickname
address: 10.34.63.204
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_host_storages }}"
'''
RETURN = '''
ovirt_host_storages:
description: "List of dictionaries describing the HostStorage. HostStorage attributes are mapped to dictionary keys,
all HostStorage attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/host_storage."
returned: On success.
type: list
'''
import traceback
try:
import ovirtsdk4.types as otypes
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name,
)
def _login(host_service, iscsi):
host_service.iscsi_login(
iscsi=otypes.IscsiDetails(
username=iscsi.get('username'),
password=iscsi.get('password'),
address=iscsi.get('address'),
target=iscsi.get('target'),
portal=iscsi.get('portal')
),
)
def _get_storage_type(params):
for sd_type in ['iscsi', 'fcp']:
if params.get(sd_type) is not None:
return sd_type
def main():
argument_spec = ovirt_info_full_argument_spec(
host=dict(required=True),
iscsi=dict(default=None, type='dict'),
fcp=dict(default=None, type='dict'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_host_storage_facts', 'community.general.ovirt_host_storage_facts')
if is_old_facts:
module.deprecate("The 'ovirt_host_storage_facts' module has been renamed to 'ovirt_host_storage_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
# Get Host
hosts_service = connection.system_service().hosts_service()
host_id = get_id_by_name(hosts_service, module.params['host'])
storage_type = _get_storage_type(module.params)
host_service = hosts_service.host_service(host_id)
if storage_type == 'iscsi':
# Login
iscsi = module.params.get('iscsi')
_login(host_service, iscsi)
# Get LUNs exposed from the specified target
host_storages = host_service.storage_service().list()
if storage_type == 'iscsi':
filterred_host_storages = [host_storage for host_storage in host_storages
if host_storage.type == otypes.StorageType.ISCSI]
if 'target' in iscsi:
filterred_host_storages = [host_storage for host_storage in filterred_host_storages
if iscsi.get('target') == host_storage.logical_units[0].target]
elif storage_type == 'fcp':
filterred_host_storages = [host_storage for host_storage in host_storages
if host_storage.type == otypes.StorageType.FCP]
result = dict(
ovirt_host_storages=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in filterred_host_storages
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,124 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_network_facts
short_description: Retrieve information about one or more oVirt/RHV networks
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_network_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV networks."
notes:
- "This module returns a variable C(ovirt_networks), which
contains a list of networks. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search network starting with string vlan1 use: name=vlan1*"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all networks which names start with vlan1
ovirt_network_info:
pattern: name=vlan1*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_networks }}"
'''
RETURN = '''
ovirt_networks:
description: "List of dictionaries describing the networks. Network attributes are mapped to dictionary keys,
all networks attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/network."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_network_facts', 'community.general.ovirt_network_facts')
if is_old_facts:
module.deprecate("The 'ovirt_network_facts' module has been renamed to 'ovirt_network_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
networks_service = connection.system_service().networks_service()
networks = networks_service.list(search=module.params['pattern'])
result = dict(
ovirt_networks=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in networks
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,142 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_nic_facts
short_description: Retrieve information about one or more oVirt/RHV virtual machine network interfaces
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_nic_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV virtual machine network interfaces."
notes:
- "This module returns a variable C(ovirt_nics), which
contains a list of NICs. You need to register the result with
the I(register) keyword to use it."
options:
vm:
description:
- "Name of the VM where NIC is attached."
required: true
name:
description:
- "Name of the NIC, can be used as glob expression."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all NICs which names start with eth for VM named centos7
ovirt_nic_info:
vm: centos7
name: eth*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_nics }}"
'''
RETURN = '''
ovirt_nics:
description: "List of dictionaries describing the network interfaces. NIC attributes are mapped to dictionary keys,
all NICs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/nic."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
vm=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_nic_facts', 'community.general.ovirt_nic_facts')
if is_old_facts:
module.deprecate("The 'ovirt_nic_facts' module has been renamed to 'ovirt_nic_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vms_service = connection.system_service().vms_service()
vm_name = module.params['vm']
vm = search_by_name(vms_service, vm_name)
if vm is None:
raise Exception("VM '%s' was not found." % vm_name)
nics_service = vms_service.service(vm.id).nics_service()
if module.params['name']:
nics = [
e for e in nics_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
nics = nics_service.list()
result = dict(
ovirt_nics=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in nics
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,165 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_permission_facts
short_description: Retrieve information about one or more oVirt/RHV permissions
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_permission_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV permissions."
notes:
- "This module returns a variable C(ovirt_permissions), which
contains a list of permissions. You need to register the result with
the I(register) keyword to use it."
options:
user_name:
description:
- "Username of the user to manage. In most LDAPs it's I(uid) of the user, but in Active Directory you must specify I(UPN) of the user."
group_name:
description:
- "Name of the group to manage."
authz_name:
description:
- "Authorization provider of the user/group. In previous versions of oVirt/RHV known as domain."
required: true
aliases: ['domain']
namespace:
description:
- "Namespace of the authorization provider, where user/group resides."
required: false
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all permissions of user with username john
ovirt_permission_info:
user_name: john
authz_name: example.com-authz
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_permissions }}"
'''
RETURN = '''
ovirt_permissions:
description: "List of dictionaries describing the permissions. Permission attributes are mapped to dictionary keys,
all permissions attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/permission."
returned: On success.
type: list
'''
import traceback
try:
import ovirtsdk4 as sdk
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_link_name,
ovirt_info_full_argument_spec,
search_by_name,
)
def _permissions_service(connection, module):
if module.params['user_name']:
service = connection.system_service().users_service()
entity = next(
iter(
service.list(
search='usrname={0}'.format(
'{0}@{1}'.format(module.params['user_name'], module.params['authz_name'])
)
)
),
None
)
else:
service = connection.system_service().groups_service()
entity = search_by_name(service, module.params['group_name'])
if entity is None:
raise Exception("User/Group wasn't found.")
return service.service(entity.id).permissions_service()
def main():
argument_spec = ovirt_info_full_argument_spec(
authz_name=dict(required=True, aliases=['domain']),
user_name=dict(default=None),
group_name=dict(default=None),
namespace=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_permission_facts', 'community.general.ovirt_permission_facts')
if is_old_facts:
module.deprecate("The 'ovirt_permission_facts' module has been renamed to 'ovirt_permission_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
permissions_service = _permissions_service(connection, module)
permissions = []
for p in permissions_service.list():
newperm = dict()
for key, value in p.__dict__.items():
if value and isinstance(value, sdk.Struct):
newperm[key[1:]] = get_link_name(connection, value)
newperm['%s_id' % key[1:]] = value.id
permissions.append(newperm)
result = dict(ovirt_permissions=permissions)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,142 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_quota_facts
short_description: Retrieve information about one or more oVirt/RHV quotas
author: "Maor Lipchuk (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_quota_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV quotas."
notes:
- "This module returns a variable C(ovirt_quotas), which
contains a list of quotas. You need to register the result with
the I(register) keyword to use it."
options:
data_center:
description:
- "Name of the datacenter where quota resides."
required: true
name:
description:
- "Name of the quota, can be used as glob expression."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about quota named C<myquota> in Default datacenter
ovirt_quota_info:
data_center: Default
name: myquota
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_quotas }}"
'''
RETURN = '''
ovirt_quotas:
description: "List of dictionaries describing the quotas. Quota attributes are mapped to dictionary keys,
all quotas attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/quota."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
data_center=dict(required=True),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_quota_facts', 'community.general.ovirt_quota_facts')
if is_old_facts:
module.deprecate("The 'ovirt_quota_facts' module has been renamed to 'ovirt_quota_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
datacenters_service = connection.system_service().data_centers_service()
dc_name = module.params['data_center']
dc = search_by_name(datacenters_service, dc_name)
if dc is None:
raise Exception("Datacenter '%s' was not found." % dc_name)
quotas_service = datacenters_service.service(dc.id).quotas_service()
if module.params['name']:
quotas = [
e for e in quotas_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
else:
quotas = quotas_service.list()
result = dict(
ovirt_quotas=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in quotas
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,140 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_scheduling_policy_facts
short_description: Retrieve information about one or more oVirt scheduling policies
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_scheduling_policy_info) instead.
description:
- "Retrieve information about one or more oVirt scheduling policies."
notes:
- "This module returns a variable C(ovirt_scheduling_policies),
which contains a list of scheduling policies. You need to register the result with
the I(register) keyword to use it."
options:
id:
description:
- "ID of the scheduling policy."
name:
description:
- "Name of the scheduling policy, can be used as glob expression."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all scheduling policies with name InClusterUpgrade
ovirt_scheduling_policy_info:
name: InClusterUpgrade
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_scheduling_policies }}"
'''
RETURN = '''
ovirt_scheduling_policies:
description: "List of dictionaries describing the scheduling policies.
Scheduling policies attributes are mapped to dictionary keys,
all scheduling policies attributes can be found at following
url: https://ovirt.example.com/ovirt-engine/api/model#types/scheduling_policy."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
id=dict(default=None),
name=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_scheduling_policy_facts', 'community.general.ovirt_scheduling_policy_facts')
if is_old_facts:
module.deprecate("The 'ovirt_scheduling_policy_facts' module has been renamed to 'ovirt_scheduling_policy_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
system_service = connection.system_service()
sched_policies_service = system_service.scheduling_policies_service()
if module.params['name']:
sched_policies = [
e for e in sched_policies_service.list()
if fnmatch.fnmatch(e.name, module.params['name'])
]
elif module.params['id']:
sched_policies = [
sched_policies_service.service(module.params['id']).get()
]
else:
sched_policies = sched_policies_service.list()
result = dict(
ovirt_scheduling_policies=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in sched_policies
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,136 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
# 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
DOCUMENTATION = '''
---
module: ovirt_snapshot_facts
short_description: Retrieve information about one or more oVirt/RHV virtual machine snapshots
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_snapshot_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV virtual machine snapshots."
notes:
- "This module returns a variable C(ovirt_snapshots), which
contains a list of snapshots. You need to register the result with
the I(register) keyword to use it."
options:
vm:
description:
- "Name of the VM with snapshot."
required: true
description:
description:
- "Description of the snapshot, can be used as glob expression."
snapshot_id:
description:
- "Id of the snapshot we want to retrieve information about."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all snapshots which description start with update for VM named centos7
ovirt_snapshot_info:
vm: centos7
description: update*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_snapshots }}"
'''
RETURN = '''
ovirt_snapshots:
description: "List of dictionaries describing the snapshot. Snapshot attributes are mapped to dictionary keys,
all snapshot attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/snapshot."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
vm=dict(required=True),
description=dict(default=None),
snapshot_id=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_snapshot_facts', 'community.general.ovirt_snapshot_facts')
if is_old_facts:
module.deprecate("The 'ovirt_snapshot_facts' module has been renamed to 'ovirt_snapshot_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vms_service = connection.system_service().vms_service()
vm_name = module.params['vm']
vm = search_by_name(vms_service, vm_name)
if vm is None:
raise Exception("VM '%s' was not found." % vm_name)
snapshots_service = vms_service.service(vm.id).snapshots_service()
if module.params['description']:
snapshots = [
e for e in snapshots_service.list()
if fnmatch.fnmatch(e.description, module.params['description'])
]
elif module.params['snapshot_id']:
snapshots = [
snapshots_service.snapshot_service(module.params['snapshot_id']).get()
]
else:
snapshots = snapshots_service.list()
result = dict(
ovirt_snapshots=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in snapshots
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,125 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_storage_domain_facts
short_description: Retrieve information about one or more oVirt/RHV storage domains
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_storage_domain_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV storage domains."
notes:
- "This module returns a variable C(ovirt_storage_domains), which
contains a list of storage domains. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search storage domain X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: >
Gather information about all storage domains which names
start with data and belong to data center west
ovirt_storage_domain_info:
pattern: name=data* and datacenter=west
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_storage_domains }}"
'''
RETURN = '''
ovirt_storage_domains:
description: "List of dictionaries describing the storage domains. Storage_domain attributes are mapped to dictionary keys,
all storage domains attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/storage_domain."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_storage_domain_facts', 'community.general.ovirt_storage_domain_facts')
if is_old_facts:
module.deprecate("The 'ovirt_storage_domain_facts' module has been renamed to 'ovirt_storage_domain_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
storage_domains = storage_domains_service.list(search=module.params['pattern'])
result = dict(
ovirt_storage_domains=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in storage_domains
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,141 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_storage_template_facts
short_description: Retrieve information about one or more oVirt/RHV templates relate to a storage domain.
author: "Maor Lipchuk (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_storage_template_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV templates relate to a storage domain."
notes:
- "This module returns a variable C(ovirt_storage_templates), which
contains a list of templates. You need to register the result with
the I(register) keyword to use it."
options:
unregistered:
description:
- "Flag which indicates whether to get unregistered templates which contain one or more
disks which reside on a storage domain or diskless templates."
type: bool
default: false
max:
description:
- "Sets the maximum number of templates to return. If not specified all the templates are returned."
storage_domain:
description:
- "The storage domain name where the templates should be listed."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all templates which relate to a storage domain and are unregistered
ovirt_storage_template_info:
unregistered: yes
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_storage_templates }}"
'''
RETURN = '''
ovirt_storage_templates:
description: "List of dictionaries describing the Templates. Template attributes are mapped to dictionary keys,
all Templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name
)
def main():
argument_spec = ovirt_info_full_argument_spec(
storage_domain=dict(default=None),
max=dict(default=None, type='int'),
unregistered=dict(default=False, type='bool'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_storage_template_facts', 'community.general.ovirt_storage_template_facts')
if is_old_facts:
module.deprecate("The 'ovirt_storage_template_facts' module has been renamed to 'ovirt_storage_template_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
templates_service = storage_domain_service.templates_service()
# Find the unregistered Template we want to register:
if module.params.get('unregistered'):
templates = templates_service.list(unregistered=True)
else:
templates = templates_service.list(max=module.params['max'])
result = dict(
ovirt_storage_templates=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in templates
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,141 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_storage_vm_facts
short_description: Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain.
author: "Maor Lipchuk (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_storage_vm_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV virtual machines relate to a storage domain."
notes:
- "This module returns a variable C(ovirt_storage_vms), which
contains a list of virtual machines. You need to register the result with
the I(register) keyword to use it."
options:
unregistered:
description:
- "Flag which indicates whether to get unregistered virtual machines which contain one or more
disks which reside on a storage domain or diskless virtual machines."
type: bool
default: false
max:
description:
- "Sets the maximum number of virtual machines to return. If not specified all the virtual machines are returned."
storage_domain:
description:
- "The storage domain name where the virtual machines should be listed."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all VMs which relate to a storage domain and are unregistered
ovirt_vms_info:
unregistered: yes
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_storage_vms }}"
'''
RETURN = '''
ovirt_storage_vms:
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
get_id_by_name
)
def main():
argument_spec = ovirt_info_full_argument_spec(
storage_domain=dict(default=None),
max=dict(default=None, type='int'),
unregistered=dict(default=False, type='bool'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_storage_vm_facts', 'community.general.ovirt_storage_vm_facts')
if is_old_facts:
module.deprecate("The 'ovirt_storage_vm_facts' module has been renamed to 'ovirt_storage_vm_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
storage_domains_service = connection.system_service().storage_domains_service()
sd_id = get_id_by_name(storage_domains_service, module.params['storage_domain'])
storage_domain_service = storage_domains_service.storage_domain_service(sd_id)
vms_service = storage_domain_service.vms_service()
# Find the unregistered VM we want to register:
if module.params.get('unregistered'):
vms = vms_service.list(unregistered=True)
else:
vms = vms_service.list()
result = dict(
ovirt_storage_vms=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vms
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,171 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_tag_facts
short_description: Retrieve information about one or more oVirt/RHV tags
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_tag_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV tags."
notes:
- "This module returns a variable C(ovirt_tags), which
contains a list of tags. You need to register the result with
the I(register) keyword to use it."
options:
name:
description:
- "Name of the tag which should be listed."
vm:
description:
- "Name of the VM, which tags should be listed."
host:
description:
- "Name of the host, which tags should be listed."
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all tags, which names start with tag
ovirt_tag_info:
name: tag*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_tags }}"
- name: Gather information about all tags, which are assigned to VM postgres
ovirt_tag_info:
vm: postgres
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_tags }}"
- name: Gather information about all tags, which are assigned to host west
ovirt_tag_info:
host: west
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_tags }}"
'''
RETURN = '''
ovirt_tags:
description: "List of dictionaries describing the tags. Tags attributes are mapped to dictionary keys,
all tags attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/tag."
returned: On success.
type: list
'''
import fnmatch
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
search_by_name,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
name=dict(default=None),
host=dict(default=None),
vm=dict(default=None),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_tag_facts', 'community.general.ovirt_tag_facts')
if is_old_facts:
module.deprecate("The 'ovirt_tag_facts' module has been renamed to 'ovirt_tag_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
tags_service = connection.system_service().tags_service()
tags = []
all_tags = tags_service.list()
if module.params['name']:
tags.extend([
t for t in all_tags
if fnmatch.fnmatch(t.name, module.params['name'])
])
if module.params['host']:
hosts_service = connection.system_service().hosts_service()
host = search_by_name(hosts_service, module.params['host'])
if host is None:
raise Exception("Host '%s' was not found." % module.params['host'])
tags.extend(hosts_service.host_service(host.id).tags_service().list())
if module.params['vm']:
vms_service = connection.system_service().vms_service()
vm = search_by_name(vms_service, module.params['vm'])
if vm is None:
raise Exception("Vm '%s' was not found." % module.params['vm'])
tags.extend(vms_service.vm_service(vm.id).tags_service().list())
if not (module.params['vm'] or module.params['host'] or module.params['name']):
tags = all_tags
result = dict(
ovirt_tags=[
get_dict_of_struct(
struct=t,
connection=connection,
fetch_nested=module.params['fetch_nested'],
attributes=module.params['nested_attributes'],
) for t in tags
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,123 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_template_facts
short_description: Retrieve information about one or more oVirt/RHV templates
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_template_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV templates."
notes:
- "This module returns a variable C(ovirt_templates), which
contains a list of templates. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search template X from datacenter Y use following pattern:
name=X and datacenter=Y"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all templates which names start with centos and belongs to data center west
ovirt_template_info:
pattern: name=centos* and datacenter=west
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_templates }}"
'''
RETURN = '''
ovirt_templates:
description: "List of dictionaries describing the templates. Template attributes are mapped to dictionary keys,
all templates attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/template."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_template_facts', 'community.general.ovirt_template_facts')
if is_old_facts:
module.deprecate("The 'ovirt_template_facts' module has been renamed to 'ovirt_template_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
templates_service = connection.system_service().templates_service()
templates = templates_service.list(search=module.params['pattern'])
result = dict(
ovirt_templates=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in templates
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,122 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_user_facts
short_description: Retrieve information about one or more oVirt/RHV users
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_user_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV users."
notes:
- "This module returns a variable C(ovirt_users), which
contains a list of users. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search user X use following pattern: name=X"
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all users which first names start with john
ovirt_user_info:
pattern: name=john*
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_users }}"
'''
RETURN = '''
ovirt_users:
description: "List of dictionaries describing the users. User attributes are mapped to dictionary keys,
all users attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/user."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_user_facts', 'community.general.ovirt_user_facts')
if is_old_facts:
module.deprecate("The 'ovirt_user_facts' module has been renamed to 'ovirt_user_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
users_service = connection.system_service().users_service()
users = users_service.list(search=module.params['pattern'])
result = dict(
ovirt_users=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in users
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,165 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2016 Red Hat, Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ovirt_vm_facts
short_description: Retrieve information about one or more oVirt/RHV virtual machines
author: "Ondra Machacek (@machacekondra)"
deprecated:
removed_in: 3.0.0 # was Ansible 2.13
why: When migrating to collection we decided to use only _info modules.
alternative: Use M(ovirt.ovirt.ovirt_vm_info) instead.
description:
- "Retrieve information about one or more oVirt/RHV virtual machines."
notes:
- "This module returns a variable C(ovirt_vms), which
contains a list of virtual machines. You need to register the result with
the I(register) keyword to use it."
options:
pattern:
description:
- "Search term which is accepted by oVirt/RHV search backend."
- "For example to search VM X from cluster Y use following pattern:
name=X and cluster=Y"
all_content:
description:
- "If I(true) all the attributes of the virtual machines should be
included in the response."
type: bool
default: false
case_sensitive:
description:
- "If I(true) performed search will take case into account."
type: bool
default: true
max:
description:
- "The maximum number of results to return."
next_run:
description:
- "Indicates if the returned result describes the virtual machine as it is currently running or if describes
the virtual machine with the modifications that have already been performed but that will only come into
effect when the virtual machine is restarted. By default the value is set by engine."
type: bool
extends_documentation_fragment:
- community.general.ovirt_facts
'''
EXAMPLES = '''
# Examples don't contain auth parameter for simplicity,
# look at ovirt_auth module to see how to reuse authentication:
- name: Gather information about all VMs which names start with centos and belong to cluster west
ovirt_vm_info:
pattern: name=centos* and cluster=west
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_vms }}"
- name: Gather info about next run configuration of virtual machine named myvm
ovirt_vm_info:
pattern: name=myvm
next_run: true
register: result
- name: Print gathered information
ansible.builtin.debug:
msg: "{{ result.ovirt_vms[0] }}"
'''
RETURN = '''
ovirt_vms:
description: "List of dictionaries describing the VMs. VM attributes are mapped to dictionary keys,
all VMs attributes can be found at following url: http://ovirt.github.io/ovirt-engine-api-model/master/#types/vm."
returned: On success.
type: list
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils._ovirt import (
check_sdk,
create_connection,
get_dict_of_struct,
ovirt_info_full_argument_spec,
)
def main():
argument_spec = ovirt_info_full_argument_spec(
pattern=dict(default='', required=False),
all_content=dict(default=False, type='bool'),
next_run=dict(default=None, type='bool'),
case_sensitive=dict(default=True, type='bool'),
max=dict(default=None, type='int'),
)
module = AnsibleModule(argument_spec)
is_old_facts = module._name in ('ovirt_vm_facts', 'community.general.ovirt_vm_facts')
if is_old_facts:
module.deprecate("The 'ovirt_vm_facts' module has been renamed to 'ovirt_vm_info', "
"and the renamed one no longer returns ansible_facts",
version='3.0.0', collection_name='community.general') # was Ansible 2.13
check_sdk(module)
try:
auth = module.params.pop('auth')
connection = create_connection(auth)
vms_service = connection.system_service().vms_service()
vms = vms_service.list(
search=module.params['pattern'],
all_content=module.params['all_content'],
case_sensitive=module.params['case_sensitive'],
max=module.params['max'],
)
if module.params['next_run']:
vms = [vms_service.vm_service(vm.id).get(next_run=True) for vm in vms]
result = dict(
ovirt_vms=[
get_dict_of_struct(
struct=c,
connection=connection,
fetch_nested=module.params.get('fetch_nested'),
attributes=module.params.get('nested_attributes'),
) for c in vms
],
)
if is_old_facts:
module.exit_json(changed=False, ansible_facts=result)
else:
module.exit_json(changed=False, **result)
except Exception as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
finally:
connection.close(logout=auth.get('token') is None)
if __name__ == '__main__':
main()

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