Compare commits

...

51 Commits
4.1.0 ... 4.2.0

Author SHA1 Message Date
Felix Fontein
6661917370 Release 4.2.0. 2021-12-21 11:58:13 +01:00
patchback[bot]
ec0bd3143a Add additional auth support to Gitlab (#705) (#3918) (#3929)
* Add additional auth support to Gitlab (#705)

- removed unused imports from module_utils.gitlab
- fix bug in gitlab_project to check if avatar_path is provided

* add doc_fragment and argument_spec for gitlab auth

* doc fixes and remove avatar_path bug fix

* small doc changes, pass validate_certs to requests call

* update changelog

(cherry picked from commit 52ad0a5fbb)

Co-authored-by: Josh <josham@users.noreply.github.com>
2021-12-20 22:20:40 +01:00
patchback[bot]
cce68def8b fix gitlab_project avatar_path open when undefined bug (#3926) (#3927) (#3928)
* fix gitlab_project avatar_path open when undefined bug (#3926)

* remove changelog fragment

(cherry picked from commit 11fcf661bf)

Co-authored-by: Josh <josham@users.noreply.github.com>
2021-12-20 20:22:29 +01:00
patchback[bot]
6f5ad22d28 Disable snap tests. (#3922) (#3923)
(cherry picked from commit 51838adf8c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-20 10:58:42 +01:00
patchback[bot]
6c53a09eef xfconf - using aggregated base class (#3919) (#3920)
* xfconf - using aggregated base class

* added changelog fragment

* fixed typo

(cherry picked from commit daabb53a2b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-20 10:15:24 +01:00
patchback[bot]
9b6e75f7f4 Icinga2 Inventory Plugin - Error handling and inventory name changer (#3906) (#3915)
* Added inventory_attr and filter error handling

* Added inventory_attr and filter error handling

* Added inventory_attr and filter error handling

* Added inventory_attr and filter error handling

* Added changelog

* Added inventory_attr and filter error handling

* Added inventory_attr and filter error handling

* Applying requested changes

* FIxes for tests

* Added inventory_attr and filter error handling

* Error handling

* Error handling

* Error handling

* Modifications to unit tests

* Remove pitfall

(cherry picked from commit 8da2c630d8)

Co-authored-by: Cliff Hults <BongoEADGC6@users.noreply.github.com>
2021-12-19 14:18:57 +01:00
patchback[bot]
e09650140d Fix nrdp string arguments without an encoding (#3909) (#3912)
* Fix nrdp string arguments without an encoding

* added changelog fragment

Signed-off-by: Jesse Harris <zigford@gmail.com>

* Update changelogs/fragments/3909-nrdp_fix_string_args_without_encoding.yaml

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

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

Co-authored-by: Jesse Harris <zigford@gmail.com>
2021-12-17 22:40:29 +01:00
patchback[bot]
67388be1a9 jira - fixed 'body' dict key error (#3867) (#3914)
* fixed

* added changelog fragment

* improved fail output when placing JIRA API requests

* Update plugins/modules/web_infrastructure/jira.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-17 22:13:43 +01:00
patchback[bot]
130d07948a proxmox - fixing onboot parameter causing module failure when not defined (#3874) (#3902)
* fixing onboot parameter when not supplied

* adding changelog fragment

(cherry picked from commit 00a1152bb1)

Co-authored-by: Andrew Pantuso <ajpantuso@gmail.com>
2021-12-14 07:00:32 +01:00
patchback[bot]
5d6fcaef53 LXD inventory: Support virtual machines (#3519) (#3900)
* LXD 4.x compatibility (Containers and VMs)

* add changelog fragment

* update fixture

* update plugin options

* backwards compatible alias

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

* Update changelogs/fragments/3519-inventory-support-lxd-4.yml

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

* add lxd 4.0 requirement

* filter for type of virtualization added. due to duplication in the namespace, "type" is not used as the keyword but "nature".

* add type filter

Since the first version of this inventory plugin only supports containers,
a filter function was added to filter between containers and
virtual machines or both.
By default only containers are displayed, as in the first version of the plugin.
This behavior will change in the future.

* rename C(nature) to C(type)

The term "nature" does not fit into the lxd namespace.
Therefore i renamed nature to type.

* update changelog fragment

* Update plugins/inventory/lxd.py

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

* Apply suggestions from code review

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

* rename typefilter to type_filter

* fix tests with type_filter

* Update plugins/inventory/lxd.py

* Update plugins/inventory/lxd.py

Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Frank Dornheim <“dornheim@posteo.de@users.noreply.github.com”>
(cherry picked from commit 8825ef4711)

Co-authored-by: Élie <elie@deloumeau.fr>
2021-12-14 06:42:47 +01:00
patchback[bot]
f044a83c49 Pass missing vlan-related options (flags, ingress, egress) to nmcli (#3896) (#3899)
* Pass missing vlan-related options (flags, ingress, egress) to nmcli

Signed-off-by: Jean-Francois Panisset <panisset@gmail.com>

* Follow style: comma on last parameter

Signed-off-by: Jean-Francois Panisset <panisset@gmail.com>

* PEP8 code style fix

Signed-off-by: Jean-Francois Panisset <panisset@gmail.com>

* add missing changelog fragment

Signed-off-by: Jean-Francois Panisset <panisset@gmail.com>
(cherry picked from commit 6cec2e2f58)

Co-authored-by: Jean-Francois Panisset <32653482+jfpanisset@users.noreply.github.com>
2021-12-13 21:59:37 +01:00
patchback[bot]
e3f7e8dadf Docs improvements. (#3893) (#3894)
(cherry picked from commit 59bbaeed77)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-12 11:46:31 +01:00
patchback[bot]
8d1a028dbd Modules for managing HPE iLO (#3740) (#3892)
* Adding HPE ilo modules

* lint fix

* symlink created

* Fan message enhancement

* Removed comments

* Added uniform constuct

* Update plugins/module_utils/redfish_utils.py

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

* Update plugins/module_utils/redfish_utils.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_config.py

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

* Added info module and minor changes

* lint fixes

* lint fixes

* lint fixes

* lint fixes

* Added tests and modifed ilo_redfish_info

* Modified tests

* lint fix

* result overwrite fixed

* result overwrite fixed

* Added result

* Changed RESULT

* Modified contains

* Added License

* lint fix

* Changed RESULT

* lint fix

* Changed return

* Changed return

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_config.py

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

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

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

* Added - changed

* Modified changed attribute

* Changed modified

* lint fix

* Removed req

* Minor changes

* Update plugins/modules/remote_management/redfish/ilo_redfish_info.py

Co-authored-by: Rajeevalochana Kallur <rajeevalochana.kallur@hpe.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 8508e3fa6f)

Co-authored-by: Bhavya <44067558+Bhavya06@users.noreply.github.com>
2021-12-11 21:56:10 +01:00
patchback[bot]
8823e5c061 hponcfg - revamped the module using ModuleHelper (#3840) (#3891)
* hponcfg - revamped the module using ModuleHelper

* added changelog fragment

* fixed imports

* Update plugins/modules/remote_management/hpilo/hponcfg.py

* fixed

(cherry picked from commit 7cbe1bcf63)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-11 21:35:23 +01:00
patchback[bot]
102456d033 add dnsimple_info module, see issue #3569 (#3739) (#3890)
* add dnsimple_info module, see issue #3569

https://github.com/ansible-collections/community.general/issues/3569#issuecomment-945002861

* Update plugins/modules/net_tools/dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update BOTMETA.yml

Update dnsimple_info.py

Create dnsimple_info.py

Create dnsimple_info.py

pep8

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update dnsimple_info.py

add returns

pep8 spacing

Update dnsimple_info.py

Update dnsimple_info.py

change return results to list

fix time stamps

Update dnsimple_info.py

remove extra comma

Update plugins/modules/net_tools/dnsimple_info.py

Update test_dnsimple_info.py

Update dnsimple_info.py

fix descriptions

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

missing punctuation throughout docs

Update dnsimple_info.py

add elements in descriptions

Update dnsimple_info.py

indentation error

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

Update dnsimple_info.py

refactor, remove unneeded arguments

refactor and error handling

formatting

add unit test

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update plugins/modules/net_tools/dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

assert fail/exit

Update test_dnsimple_info.py

pep8 fixes

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

Update test_dnsimple_info.py

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

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

Co-authored-by: Edward Hilgendorf <edward@hilgendorf.me>
2021-12-11 21:29:27 +01:00
patchback[bot]
aad4c55d3d lxc_container - invoke run_command passing list (#3851) (#3886)
* lxc_container - invoke run_command passing list

* added changelog fragment

* Update plugins/modules/cloud/lxc/lxc_container.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-10 06:43:19 +01:00
patchback[bot]
e31c98f17f jira - Add support for Bearer token auth (#3838) (#3884)
* jira - Add support for Bearer token auth

* jira - Add support for Bearer token auth

* added changelog fragment

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

* fix indent issue

* fix overindent

* jira - Add support for Bearer token auth

* jira - Add support for Bearer token auth

* added changelog fragment

* minor doc fix to be clearer.

Be clear about the exclusivity between username and token
as well as password and token.

* Update changelogs/fragments/3838-jira-token.yaml

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>

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

Co-authored-by: Kambiz Aghaiepour <kambiz@aghaiepour.com>
2021-12-09 22:05:02 +01:00
patchback[bot]
6a5dfc5579 aix_lvg - invoke run_command passing list (#3834) (#3883)
* aix_lvg - invoke run_command passing list

* added changelog fragment

(cherry picked from commit 4bddf9e12c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-09 22:01:28 +01:00
Felix Fontein
ab7efef9df nmcli: adding ipv6 address list support (#3776) (#3885)
* rebase

* Add changelog fragment

* add suggestions

* split PR into two

* Add multiple address support but with #3768 fiexed

* rebase

* clean some merge artifacts

* update the wording

(cherry picked from commit 90c0980e8d)

Co-authored-by: Alex Groshev <38885591+haddystuff@users.noreply.github.com>
2021-12-09 22:00:33 +01:00
patchback[bot]
ca9c763b57 aix_filesystems - invoke run_command passing list (#3833) (#3882)
* aix_filesystems - invoke run_command passing list

* added changelog fragment

(cherry picked from commit 70f73f42f8)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-09 22:00:12 +01:00
patchback[bot]
cfeb40ed23 Update lxd connection to use all documented vars for options (#3798) (#3881)
* Update lxd connection to use documented vars

* Add a changelog fragment

* Add clarification to changelog description

* Shorten changelog fragment description

(cherry picked from commit 8f6866dba6)

Co-authored-by: Conner Crosby <conner@cavcrosby.tech>
2021-12-09 21:58:06 +01:00
patchback[bot]
c495d136fa add module gitlab_branch (#3795) (#3879)
* add module gitlab_branch

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

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

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

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

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

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

* Update gitlab_branch.py

* Update gitlab_branch.py

* Update gitlab_branch.py

* add integration tests

* Update BOTMETA.yml

* Update gitlab_branch.py

* Update tests/integration/targets/gitlab_branch/aliases

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

* Update main.yml

Co-authored-by: paitrault <aymeric.paitrault@inetum.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c69e4f4ac9)

Co-authored-by: paytroff <paytroff@gmail.com>
2021-12-09 21:19:13 +01:00
patchback[bot]
d9e2d6682b small docs update for timezone module (#3876) (#3878)
* small docs update for timezone module
fixes #3242

* Update plugins/modules/system/timezone.py

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

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

Co-authored-by: Anatoly Pugachev <matorola@gmail.com>
2021-12-09 21:19:03 +01:00
Felix Fontein
d7fe288ffd Prepare 4.2.0 release. 2021-12-08 20:22:04 +01:00
patchback[bot]
7de89699f7 update scaleway maintainers (#3472) (#3873)
* update scaleway maintainers

* Fix

* Fix sieben -> remyleone

Co-authored-by: scaleway-bot <github@scaleway.com>
(cherry picked from commit 80d650f60a)

Co-authored-by: Rémy Léone <remy.leone@gmail.com>
2021-12-08 20:20:59 +01:00
patchback[bot]
b0a9cceeb5 interfaces_file: unit tests improved (#3863) (#3869)
* interfaces_file: fixed unit tests and added README, added test cases for #3862

* typo fix for interfaces_file unit tests README.md

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

* typo fix for interfaces_file unit tests README.md

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

* typo fix for interfaces_file unit tests README.md

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

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

Co-authored-by: Roman Belyakovsky <ihryamzik@gmail.com>
2021-12-08 12:51:25 +01:00
patchback[bot]
b08f0b2f82 interfaces_file - fixed dup options bug (#3862) (#3866)
* interfaces_file - fixed dup options bug

* added changelog fragment

(cherry picked from commit 3dd5b0d343)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-08 05:54:48 +00:00
patchback[bot]
f23f409bd6 MH additional tests (#3850) (#3859)
(cherry picked from commit d50f30c618)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-05 22:14:16 +01:00
patchback[bot]
cfea62793f MH decorators - added decorators for check_mode (#3849) (#3860)
* MH decorators - added decorators for check_mode

* added changelog fragment

(cherry picked from commit fb79c2998e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-05 22:14:08 +01:00
patchback[bot]
62bda91466 Add stable-4 to nightly CI jobs; make stable-2 weekly. (#3852) (#3857)
(cherry picked from commit 727c9a4032)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-12-05 17:41:15 +01:00
patchback[bot]
473d5fa2af Moved changelog fragment file to the right directory (#3853) (#3858)
* moved changelog fragment file to the right directory

* fixed filename

(cherry picked from commit 4f4150117d)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-05 17:40:43 +01:00
patchback[bot]
cc76d684d5 opentelemetry: honour ignore errors (#3837) (#3847)
* opentelemetry: honour the ignore_errors

* fix-encoding-pragma

* Add changelog fragment

* opentelemetry: ignore produces unset span status

(cherry picked from commit ce6d0a749e)

Co-authored-by: Victor Martinez <victormartinezrubio@gmail.com>
2021-12-04 19:55:17 +01:00
patchback[bot]
7a6770c731 nmcli - add support for addr-gen-mode and ip6-privacy options (#3802) (#3845)
* Add support for addr-gen-mode and ip6-privacy options

* Apply suggestions from code review

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

* try to solve conflict

* add suggested code + fix some of its issues

* Update plugins/modules/net_tools/nmcli.py

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

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

Co-authored-by: Alex Groshev <38885591+haddystuff@users.noreply.github.com>
2021-12-04 19:18:49 +01:00
patchback[bot]
d2214af6e8 java_cert - invoke run_command passing list (#3835) (#3842)
* java_cert - invoke run_command passing list

* added changelog fragment

(cherry picked from commit 6b91c56c4e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-03 08:07:15 +01:00
patchback[bot]
fad1220869 monit - invoke run_command passing list (#3821) (#3832)
* monit - invoke run_command passing list

* added changelog fragment

* fixed unit test

* further adjustments

* fixed handling of command_args

* better handling of command_args

(cherry picked from commit 52d4907480)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-02 08:12:52 +01:00
patchback[bot]
fe09516235 svc - invoke run_command passing list (#3829) (#3830)
* svc - invoke run_command passing list

* added changelog fragment

(cherry picked from commit ccb74ffd7c)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-01 20:43:16 +01:00
patchback[bot]
78cd8886f4 ip_netns - invoke run_command passing list (#3822) (#3828)
* ip_netns - invoke run_command passing list

* added changelog fragment

(cherry picked from commit ba9578f12a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-01 13:19:28 +01:00
patchback[bot]
6b99d48f06 logstash_plugin - invoke run_command passing list (#3808) (#3827)
* logstash_plugin - invoke run_command passing list

* added changelog fragment

* rogue chglog frag escaped its caged and was seen running around into a different PR

(cherry picked from commit c587d21ba0)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-01 07:09:49 +01:00
patchback[bot]
6e0e17a7e3 xattr - invoke run_command passing list (#3806) (#3820)
* xattr - invoke run_command passing list

* added changelog fragment

* Update plugins/modules/files/xattr.py

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

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

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-12-01 06:58:39 +01:00
patchback[bot]
90de95c7b2 pipx - fixed --include-apps bug (#3800) (#3818)
* pipx - fixed --include-apps bug

* added changelog fragment

* skipped freebsd for the last test

(cherry picked from commit bc619bcefc)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 08:33:31 +01:00
patchback[bot]
07c6b8b24e ModuleHelper - deprecate attribute VarDict (#3801) (#3819)
* ModuleHelper - deprecate attribute VarDict

* added changelog fragment

(cherry picked from commit 2896131ca7)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 08:32:56 +01:00
patchback[bot]
d106de6d51 python_requirements_info - improvements (#3797) (#3816)
* python_requirements_info - improvements

- returns python version broken down into its components
- minor refactoring

* adjusted indentation in the documentaiton blocks

* added changelog fragment

* fixes from PR review + assertion in test

(cherry picked from commit ff0c065ca2)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 08:32:42 +01:00
patchback[bot]
e96101fb3f Improve modules gitlab (#3792) (#3815)
* correction doc

* Update gitlab_group.py

* improve gitlab

* Update changelogs/3766-improve_gitlab_group_and_project.yml

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

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

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

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

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

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

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

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

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

* correction

* correction sanity project

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

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

* modif condition default_branch arg

* Update gitlab_project.py

change indent if defautl_branch inside if initialize_with_radme

Co-authored-by: paitrault <aymeric.paitrault@inetum.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c6dcae5fda)

Co-authored-by: paytroff <paytroff@gmail.com>
2021-11-30 06:53:17 +01:00
patchback[bot]
a60d55f03c ansible_galaxy_install - minor documentation fix (#3804) (#3814)
* ansible_galaxy_install - minor documentation fix

* further adjustments

(cherry picked from commit 49bdc0f218)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 06:53:07 +01:00
patchback[bot]
d6a09ada98 iso_extract - invoke run_command passing list (#3805) (#3812)
* iso_extract - invoke run_command passing list

* added changelog fragment

(cherry picked from commit d60edc4ac1)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 06:53:00 +01:00
patchback[bot]
9ddb75a3a2 logentries - invoke run_command passing list (#3807) (#3811)
* logentries - invoke run_command passing list

* added changelog fragment

(cherry picked from commit cb0ade4323)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-30 06:52:49 +01:00
patchback[bot]
b85ff2a997 Fixing ip address without mask bug (#3784) (#3803)
* change ip6 type to list of str and fix problem with setting addresses without netmask

* change ip6 type to list of str and fix problem with setting addresses without netmask

* Add changelog fragment

* add suggestions

* fix no mask using bug

* Make change independed from feature branch

(cherry picked from commit aae3ae1a8e)

Co-authored-by: Alex Groshev <38885591+haddystuff@users.noreply.github.com>
2021-11-30 06:01:50 +01:00
patchback[bot]
3d1ca5638b python_requirements_info - fail when version operator used without version (#3785) (#3793)
* python_requirements_info - fail when version operator used without version

* added changelog fragment

* simplified way of achieving the same result

(cherry picked from commit 59c1859fb3)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-26 20:53:58 +01:00
patchback[bot]
35fd4700bf MH DeprecateAttrsMixin (#3727) (#3794)
* initial commit for deprecate_attrs

* completed tests

* added spaces

* test now works when tehre is more than one deprecation

* trying == instead of eq in jinja

* new approach to testing

* removed extraneous debug message

(cherry picked from commit 887b3882dc)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-11-26 20:53:49 +01:00
patchback[bot]
9add9df7d6 Keycloak: add sssd provider for user federation (#3780) (#3788)
* add sssd provider

* add changelog fragment

* fix message

* add version

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

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

Co-authored-by: Laurent Paumier <30328363+laurpaum@users.noreply.github.com>
2021-11-25 13:23:21 +01:00
Felix Fontein
cdb747b41d Next expected release is 4.2.0. 2021-11-23 06:44:41 +01:00
172 changed files with 4505 additions and 729 deletions

View File

@@ -24,14 +24,15 @@ schedules:
always: true
branches:
include:
- stable-2
- stable-3
- stable-4
- cron: 0 11 * * 0
displayName: Weekly (old stable branches)
always: true
branches:
include:
- stable-1
- stable-2
variables:
- name: checkoutPath

16
.github/BOTMETA.yml vendored
View File

@@ -156,7 +156,7 @@ files:
maintainers: conloos
$inventories/nmap.py: {}
$inventories/online.py:
maintainers: sieben
maintainers: remyleone
$inventories/opennebula.py:
maintainers: feldsam
labels: cloud opennebula
@@ -341,7 +341,7 @@ files:
$modules/cloud/oneandone/:
maintainers: aajdinov edevenport
$modules/cloud/online/:
maintainers: sieben
maintainers: remyleone
$modules/cloud/opennebula/:
maintainers: $team_opennebula
$modules/cloud/opennebula/one_host.py:
@@ -411,11 +411,11 @@ files:
$modules/cloud/scaleway/scaleway_ip_info.py:
maintainers: Spredzy
$modules/cloud/scaleway/scaleway_organization_info.py:
maintainers: sieben Spredzy
maintainers: Spredzy
$modules/cloud/scaleway/scaleway_security_group.py:
maintainers: DenBeke
$modules/cloud/scaleway/scaleway_security_group_info.py:
maintainers: sieben Spredzy
maintainers: Spredzy
$modules/cloud/scaleway/scaleway_security_group_rule.py:
maintainers: DenBeke
$modules/cloud/scaleway/scaleway_server_info.py:
@@ -619,6 +619,8 @@ files:
labels: cloudflare_dns
$modules/net_tools/dnsimple.py:
maintainers: drcapulet
$modules/net_tools/dnsimple_info.py:
maintainers: edhilgendorf
$modules/net_tools/dnsmadeeasy.py:
maintainers: briceburg
$modules/net_tools/gandi_livedns.py:
@@ -951,6 +953,8 @@ files:
maintainers: SamyCoenen
$modules/source_control/gitlab/gitlab_user.py:
maintainers: LennertMertens stgrace
$modules/source_control/gitlab/gitlab_branch.py:
maintainers: paytroff
$modules/source_control/hg.py:
maintainers: yeukhon
$modules/storage/emc/emc_vnx_sg_member.py:
@@ -1224,9 +1228,9 @@ macros:
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
team_oracle: manojmeda mross22 nalsaber
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
team_redfish: mraineri tomasg2012 xmadsen renxulei
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06
team_rhn: FlossWare alikins barnabycourt vritant
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
team_scaleway: remyleone abarbare
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso

View File

@@ -6,6 +6,88 @@ Community General Release Notes
This changelog describes changes after version 3.0.0.
v4.2.0
======
Release Summary
---------------
Regular bugfix and feature release.
Minor Changes
-------------
- aix_filesystem - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3833).
- aix_lvg - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3834).
- gitlab - add more token authentication support with the new options ``api_oauth_token`` and ``api_job_token`` (https://github.com/ansible-collections/community.general/issues/705).
- gitlab_group, gitlab_project - add new option ``avatar_path`` (https://github.com/ansible-collections/community.general/pull/3792).
- gitlab_project - add new option ``default_branch`` to gitlab_project (if ``readme = true``) (https://github.com/ansible-collections/community.general/pull/3792).
- hponcfg - revamped module using ModuleHelper (https://github.com/ansible-collections/community.general/pull/3840).
- icinga2 inventory plugin - added the ``display_name`` field to variables (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
- icinga2 inventory plugin - inventory object names are changable using ``inventory_attr`` in your config file to the host object name, address, or display_name fields (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
- ip_netns - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3822).
- iso_extract - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3805).
- java_cert - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3835).
- jira - add support for Bearer token auth (https://github.com/ansible-collections/community.general/pull/3838).
- keycloak_user_federation - add sssd user federation support (https://github.com/ansible-collections/community.general/issues/3767).
- logentries - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3807).
- logstash_plugin - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3808).
- lxc_container - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3851).
- lxd connection plugin - make sure that ``ansible_lxd_host``, ``ansible_executable``, and ``ansible_lxd_executable`` work (https://github.com/ansible-collections/community.general/pull/3798).
- lxd inventory plugin - support virtual machines (https://github.com/ansible-collections/community.general/pull/3519).
- module_helper module utils - added decorators ``check_mode_skip`` and ``check_mode_skip_returns`` for skipping methods when ``check_mode=True`` (https://github.com/ansible-collections/community.general/pull/3849).
- monit - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3821).
- nmcli - add multiple addresses support for ``ip6`` parameter (https://github.com/ansible-collections/community.general/issues/1088).
- nmcli - add support for ``eui64`` and ``ipv6privacy`` parameters (https://github.com/ansible-collections/community.general/issues/3357).
- python_requirements_info - returns python version broken down into its components, and some minor refactoring (https://github.com/ansible-collections/community.general/pull/3797).
- svc - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3829).
- xattr - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3806).
- xfconf - minor refactor on the base class for the module (https://github.com/ansible-collections/community.general/pull/3919).
Deprecated Features
-------------------
- module_helper module utils - deprecated the attribute ``ModuleHelper.VarDict`` (https://github.com/ansible-collections/community.general/pull/3801).
Bugfixes
--------
- icinga2 inventory plugin - handle 404 error when filter produces no results (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
- interfaces_file - fixed the check for existing option in interface (https://github.com/ansible-collections/community.general/issues/3841).
- jira - fixed bug where module returns error related to dictionary key ``body`` (https://github.com/ansible-collections/community.general/issues/3419).
- nmcli - fix returning "changed" when no mask set for IPv4 or IPv6 addresses on task rerun (https://github.com/ansible-collections/community.general/issues/3768).
- nmcli - pass ``flags``, ``ingress``, ``egress`` params to ``nmcli`` (https://github.com/ansible-collections/community.general/issues/1086).
- nrdp callback plugin - fix error ``string arguments without an encoding`` (https://github.com/ansible-collections/community.general/issues/3903).
- opentelemetry_plugin - honour ``ignore_errors`` when a task has failed instead of reporting an error (https://github.com/ansible-collections/community.general/pull/3837).
- pipx - passes the correct command line option ``--include-apps`` (https://github.com/ansible-collections/community.general/issues/3791).
- proxmox - fixed ``onboot`` parameter causing module failures when undefined (https://github.com/ansible-collections/community.general/issues/3844).
- python_requirements_info - fails if version operator used without version (https://github.com/ansible-collections/community.general/pull/3785).
New Modules
-----------
Net Tools
~~~~~~~~~
- dnsimple_info - Pull basic info from DNSimple API
Remote Management
~~~~~~~~~~~~~~~~~
redfish
^^^^^^^
- ilo_redfish_config - Sets or updates configuration attributes on HPE iLO with Redfish OEM extensions
- ilo_redfish_info - Gathers server information through iLO using Redfish APIs
Source Control
~~~~~~~~~~~~~~
gitlab
^^^^^^
- gitlab_branch - Create or delete a branch
v4.1.0
======

View File

@@ -1117,3 +1117,124 @@ releases:
name: revbitspss
namespace: null
release_date: '2021-11-23'
4.2.0:
changes:
bugfixes:
- icinga2 inventory plugin - handle 404 error when filter produces no results
(https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
- interfaces_file - fixed the check for existing option in interface (https://github.com/ansible-collections/community.general/issues/3841).
- jira - fixed bug where module returns error related to dictionary key ``body``
(https://github.com/ansible-collections/community.general/issues/3419).
- nmcli - fix returning "changed" when no mask set for IPv4 or IPv6 addresses
on task rerun (https://github.com/ansible-collections/community.general/issues/3768).
- nmcli - pass ``flags``, ``ingress``, ``egress`` params to ``nmcli`` (https://github.com/ansible-collections/community.general/issues/1086).
- nrdp callback plugin - fix error ``string arguments without an encoding``
(https://github.com/ansible-collections/community.general/issues/3903).
- opentelemetry_plugin - honour ``ignore_errors`` when a task has failed instead
of reporting an error (https://github.com/ansible-collections/community.general/pull/3837).
- pipx - passes the correct command line option ``--include-apps`` (https://github.com/ansible-collections/community.general/issues/3791).
- proxmox - fixed ``onboot`` parameter causing module failures when undefined
(https://github.com/ansible-collections/community.general/issues/3844).
- python_requirements_info - fails if version operator used without version
(https://github.com/ansible-collections/community.general/pull/3785).
deprecated_features:
- module_helper module utils - deprecated the attribute ``ModuleHelper.VarDict``
(https://github.com/ansible-collections/community.general/pull/3801).
minor_changes:
- aix_filesystem - calling ``run_command`` with arguments as ``list`` instead
of ``str`` (https://github.com/ansible-collections/community.general/pull/3833).
- aix_lvg - calling ``run_command`` with arguments as ``list`` instead of ``str``
(https://github.com/ansible-collections/community.general/pull/3834).
- gitlab - add more token authentication support with the new options ``api_oauth_token``
and ``api_job_token`` (https://github.com/ansible-collections/community.general/issues/705).
- gitlab_group, gitlab_project - add new option ``avatar_path`` (https://github.com/ansible-collections/community.general/pull/3792).
- gitlab_project - add new option ``default_branch`` to gitlab_project (if ``readme
= true``) (https://github.com/ansible-collections/community.general/pull/3792).
- hponcfg - revamped module using ModuleHelper (https://github.com/ansible-collections/community.general/pull/3840).
- icinga2 inventory plugin - added the ``display_name`` field to variables (https://github.com/ansible-collections/community.general/issues/3875,
https://github.com/ansible-collections/community.general/pull/3906).
- icinga2 inventory plugin - inventory object names are changable using ``inventory_attr``
in your config file to the host object name, address, or display_name fields
(https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
- ip_netns - calling ``run_command`` with arguments as ``list`` instead of ``str``
(https://github.com/ansible-collections/community.general/pull/3822).
- iso_extract - calling ``run_command`` with arguments as ``list`` instead of
``str`` (https://github.com/ansible-collections/community.general/pull/3805).
- java_cert - calling ``run_command`` with arguments as ``list`` instead of
``str`` (https://github.com/ansible-collections/community.general/pull/3835).
- jira - add support for Bearer token auth (https://github.com/ansible-collections/community.general/pull/3838).
- keycloak_user_federation - add sssd user federation support (https://github.com/ansible-collections/community.general/issues/3767).
- logentries - calling ``run_command`` with arguments as ``list`` instead of
``str`` (https://github.com/ansible-collections/community.general/pull/3807).
- logstash_plugin - calling ``run_command`` with arguments as ``list`` instead
of ``str`` (https://github.com/ansible-collections/community.general/pull/3808).
- lxc_container - calling ``run_command`` with arguments as ``list`` instead
of ``str`` (https://github.com/ansible-collections/community.general/pull/3851).
- lxd connection plugin - make sure that ``ansible_lxd_host``, ``ansible_executable``,
and ``ansible_lxd_executable`` work (https://github.com/ansible-collections/community.general/pull/3798).
- lxd inventory plugin - support virtual machines (https://github.com/ansible-collections/community.general/pull/3519).
- module_helper module utils - added decorators ``check_mode_skip`` and ``check_mode_skip_returns``
for skipping methods when ``check_mode=True`` (https://github.com/ansible-collections/community.general/pull/3849).
- monit - calling ``run_command`` with arguments as ``list`` instead of ``str``
(https://github.com/ansible-collections/community.general/pull/3821).
- nmcli - add multiple addresses support for ``ip6`` parameter (https://github.com/ansible-collections/community.general/issues/1088).
- nmcli - add support for ``eui64`` and ``ipv6privacy`` parameters (https://github.com/ansible-collections/community.general/issues/3357).
- python_requirements_info - returns python version broken down into its components,
and some minor refactoring (https://github.com/ansible-collections/community.general/pull/3797).
- svc - calling ``run_command`` with arguments as ``list`` instead of ``str``
(https://github.com/ansible-collections/community.general/pull/3829).
- xattr - calling ``run_command`` with arguments as ``list`` instead of ``str``
(https://github.com/ansible-collections/community.general/pull/3806).
- xfconf - minor refactor on the base class for the module (https://github.com/ansible-collections/community.general/pull/3919).
release_summary: Regular bugfix and feature release.
fragments:
- 1088-add_multiple_ipv6_address_support.yml
- 3357-nmcli-eui64-and-ipv6privacy.yml
- 3519-inventory-support-lxd-4.yml
- 3768-nmcli_fix_changed_when_no_mask_set.yml
- 3780-add-keycloak-sssd-user-federation.yml
- 3785-python_requirements_info-versionless-op.yaml
- 3792-improve_gitlab_group_and_project.yml
- 3797-python_requirements_info-improvements.yaml
- 3798-fix-lxd-connection-option-vars-support.yml
- 3800-pipx-include-apps.yaml
- 3801-mh-deprecate-vardict-attr.yaml
- 3805-iso_extract-run_command-list.yaml
- 3806-xattr-run_command-list.yaml
- 3807-logentries-run_command-list.yaml
- 3808-logstash_plugin-run_command-list.yaml
- 3821-monit-run-list.yaml
- 3822-ip_netns-run-list.yaml
- 3829-svc-run-list.yaml
- 3833-aix_filesystem-run-list.yaml
- 3834-aix-lvg-run-list.yaml
- 3835-java-cert-run-list.yaml
- 3837-opentelemetry_plugin-honour_ignore_errors.yaml
- 3838-jira-token.yaml
- 3840-hponcfg-mh-revamp.yaml
- 3849-mh-check-mode-decos.yaml
- 3851-lxc-container-run-list.yaml
- 3862-interfaces-file-fix-dup-option.yaml
- 3867-jira-fix-body.yaml
- 3874-proxmox-fix-onboot-param.yml
- 3875-icinga2-inv-fix.yml
- 3896-nmcli_vlan_missing_options.yaml
- 3909-nrdp_fix_string_args_without_encoding.yaml
- 3919-xfconf-baseclass.yaml
- 4.2.0.yml
- 705-gitlab-auth-support.yml
modules:
- description: Pull basic info from DNSimple API
name: dnsimple_info
namespace: net_tools
- description: Create or delete a branch
name: gitlab_branch
namespace: source_control.gitlab
- description: Sets or updates configuration attributes on HPE iLO with Redfish
OEM extensions
name: ilo_redfish_config
namespace: remote_management.redfish
- description: Gathers server information through iLO using Redfish APIs
name: ilo_redfish_info
namespace: remote_management.redfish
release_date: '2021-12-21'

View File

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

View File

@@ -70,6 +70,7 @@ import os
import json
from ansible.module_utils.six.moves.urllib.parse import urlencode
from ansible.module_utils.common.text.converters import to_bytes
from ansible.module_utils.urls import open_url
from ansible.plugins.callback import CallbackBase
@@ -143,7 +144,7 @@ class CallbackModule(CallbackBase):
body = {
'cmd': 'submitcheck',
'token': self.token,
'XMLDATA': bytes(xmldata)
'XMLDATA': to_bytes(xmldata)
}
try:

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# (C) 2021, Victor Martinez <VictorMartinezRubio@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -267,6 +268,8 @@ class OpenTelemetrySource(object):
elif host_data.status == 'skipped':
message = res['skip_reason'] if 'skip_reason' in res else 'skipped'
status = Status(status_code=StatusCode.UNSET)
elif host_data.status == 'ignored':
status = Status(status_code=StatusCode.UNSET)
span.set_status(status)
if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action:
@@ -462,10 +465,15 @@ class CallbackModule(CallbackBase):
)
def v2_runner_on_failed(self, result, ignore_errors=False):
self.errors += 1
if ignore_errors:
status = 'ignored'
else:
status = 'failed'
self.errors += 1
self.opentelemetry.finish_task(
self.tasks_data,
'failed',
status,
result
)

View File

@@ -89,9 +89,9 @@ class Connection(ConnectionBase):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"exec",
"%s:%s" % (self.get_option("remote"), self._host),
"%s:%s" % (self.get_option("remote"), self.get_option("remote_addr")),
"--",
self._play_context.executable, "-c", cmd
self.get_option("executable"), "-c", cmd
])
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@@ -126,7 +126,7 @@ class Connection(ConnectionBase):
local_cmd.extend([
"file", "push",
in_path,
"%s:%s/%s" % (self.get_option("remote"), self._host, out_path)
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), out_path)
])
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
@@ -145,7 +145,7 @@ class Connection(ConnectionBase):
local_cmd.extend(["--project", self.get_option("project")])
local_cmd.extend([
"file", "pull",
"%s:%s/%s" % (self.get_option("remote"), self._host, in_path),
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), in_path),
out_path
])

View File

@@ -0,0 +1,31 @@
# -*- 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
class ModuleDocFragment(object):
# Standard files documentation fragment
DOCUMENTATION = r'''
requirements:
- requests (Python library U(https://pypi.org/project/requests/))
options:
api_token:
description:
- GitLab access token with API permissions.
type: str
api_oauth_token:
description:
- GitLab OAuth token for logging in.
type: str
version_added: 4.2.0
api_job_token:
description:
- GitLab CI job token for logging in.
type: str
version_added: 4.2.0
'''

View File

@@ -35,13 +35,23 @@ DOCUMENTATION = '''
type: string
required: true
host_filter:
description: An Icinga2 API valid host filter.
description:
- An Icinga2 API valid host filter. Leave blank for no filtering
type: string
required: false
validate_certs:
description: Enables or disables SSL certificate verification.
type: boolean
default: true
inventory_attr:
description:
- Allows the override of the inventory name based on different attributes.
- This allows for changing the way limits are used.
- The current default, C(address), is sometimes not unique or present. We recommend to use C(name) instead.
type: string
default: address
choices: ['name', 'display_name', 'address']
version_added: 4.2.0
'''
EXAMPLES = r'''
@@ -52,6 +62,7 @@ user: ansible
password: secure
host_filter: \"linux-servers\" in host.groups
validate_certs: false
inventory_attr: name
'''
import json
@@ -59,6 +70,7 @@ import json
from ansible.errors import AnsibleParserError
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.module_utils.urls import open_url
from ansible.module_utils.six.moves.urllib.error import HTTPError
class InventoryModule(BaseInventoryPlugin, Constructable):
@@ -76,6 +88,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self.icinga2_password = None
self.ssl_verify = None
self.host_filter = None
self.inventory_attr = None
self.cache_key = None
self.use_cache = None
@@ -114,9 +127,21 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
if data is not None:
request_args['data'] = json.dumps(data)
self.display.vvv("Request Args: %s" % request_args)
response = open_url(request_url, **request_args)
try:
response = open_url(request_url, **request_args)
except HTTPError as e:
try:
error_body = json.loads(e.read().decode())
self.display.vvv("Error returned: {0}".format(error_body))
except Exception:
error_body = {"status": None}
if e.code == 404 and error_body.get('status') == "No objects found.":
raise AnsibleParserError("Host filter returned no data. Please confirm your host_filter value is valid")
raise AnsibleParserError("Unexpected data returned: {0} -- {1}".format(e, error_body))
response_body = response.read()
json_data = json.loads(response_body.decode('utf-8'))
self.display.vvv("Returned Data: %s" % json.dumps(json_data, indent=4, sort_keys=True))
if 200 <= response.status <= 299:
return json_data
if response.status == 404 and json_data['status'] == "No objects found.":
@@ -155,7 +180,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
"""Query for all hosts """
self.display.vvv("Querying Icinga2 for inventory")
query_args = {
"attrs": ["address", "state_type", "state", "groups"],
"attrs": ["address", "display_name", "state_type", "state", "groups"],
}
if self.host_filter is not None:
query_args['host_filter'] = self.host_filter
@@ -177,24 +202,35 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
"""Convert Icinga2 API data to JSON format for Ansible"""
groups_dict = {"_meta": {"hostvars": {}}}
for entry in json_data:
host_name = entry['name']
host_attrs = entry['attrs']
if self.inventory_attr == "name":
host_name = entry.get('name')
if self.inventory_attr == "address":
# When looking for address for inventory, if missing fallback to object name
if host_attrs.get('address', '') != '':
host_name = host_attrs.get('address')
else:
host_name = entry.get('name')
if self.inventory_attr == "display_name":
host_name = host_attrs.get('display_name')
if host_attrs['state'] == 0:
host_attrs['state'] = 'on'
else:
host_attrs['state'] = 'off'
host_groups = host_attrs['groups']
host_addr = host_attrs['address']
self.inventory.add_host(host_addr)
host_groups = host_attrs.get('groups')
self.inventory.add_host(host_name)
for group in host_groups:
if group not in self.inventory.groups.keys():
self.inventory.add_group(group)
self.inventory.add_child(group, host_addr)
self.inventory.set_variable(host_addr, 'address', host_addr)
self.inventory.set_variable(host_addr, 'hostname', host_name)
self.inventory.set_variable(host_addr, 'state',
self.inventory.add_child(group, host_name)
# If the address attribute is populated, override ansible_host with the value
if host_attrs.get('address') != '':
self.inventory.set_variable(host_name, 'ansible_host', host_attrs.get('address'))
self.inventory.set_variable(host_name, 'hostname', entry.get('name'))
self.inventory.set_variable(host_name, 'display_name', host_attrs.get('display_name'))
self.inventory.set_variable(host_name, 'state',
host_attrs['state'])
self.inventory.set_variable(host_addr, 'state_type',
self.inventory.set_variable(host_name, 'state_type',
host_attrs['state_type'])
return groups_dict
@@ -211,6 +247,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
self.icinga2_password = self.get_option('password')
self.ssl_verify = self.get_option('validate_certs')
self.host_filter = self.get_option('host_filter')
self.inventory_attr = self.get_option('inventory_attr')
# Not currently enabled
# self.cache_key = self.get_cache_key(path)
# self.use_cache = cache and self.get_option('cache')

View File

@@ -15,6 +15,7 @@ DOCUMENTATION = r'''
author: "Frank Dornheim (@conloos)"
requirements:
- ipaddress
- lxd >= 4.0
options:
plugin:
description: Token that ensures this is a source file for the 'lxd' plugin.
@@ -49,26 +50,38 @@ DOCUMENTATION = r'''
- 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.
description: Filter the instance according to the current status.
type: str
default: none
choices: [ 'STOPPED', 'STARTING', 'RUNNING', 'none' ]
prefered_container_network_interface:
type_filter:
description:
- If a container has multiple network interfaces, select which one is the prefered as pattern.
- Filter the instances by type C(virtual-machine), C(container) or C(both).
- The first version of the inventory only supported containers.
type: str
default: container
choices: [ 'virtual-machine', 'container', 'both' ]
version_added: 4.2.0
prefered_instance_network_interface:
description:
- If an instance 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.
- The option has been renamed from I(prefered_container_network_interface) to I(prefered_instance_network_interface) in community.general 3.8.0.
The old name still works as an alias.
type: str
default: eth
prefered_container_network_family:
aliases:
- prefered_container_network_interface
prefered_instance_network_family:
description:
- If a container has multiple network interfaces, which one is the prefered by family.
- If an instance 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).
- Create groups by the following keywords C(location), C(network_range), C(os), C(pattern), C(profile), C(release), C(type), C(vlanid).
- See example for syntax.
type: dict
'''
@@ -83,38 +96,49 @@ plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket
state: RUNNING
# simple lxd.yml including virtual machines and containers
plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket
type_filter: both
# 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
osUbuntu:
type: os
attribute: ubuntu
testpattern:
type: pattern
attribute: test
profileDefault:
type: profile
attribute: default
profileX11:
type: profile
attribute: x11
releaseFocal:
type: release
attribute: focal
releaseBionic:
type: release
attribute: bionic
typeVM:
type: type
attribute: virtual-machine
typeContainer:
type: type
attribute: container
vlan666:
type: vlanid
attribute: 666
'''
import binascii
@@ -283,10 +307,10 @@ class InventoryModule(BaseInventoryPlugin):
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
def _get_instances(self):
"""Get instancenames
Returns all containernames
Returns all instancenames
Args:
None
@@ -295,25 +319,27 @@ class InventoryModule(BaseInventoryPlugin):
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']]
list(names): names of all instances"""
# e.g. {
# "metadata": [
# "/1.0/instances/foo",
# "/1.0/instances/bar"
# ],
# "status": "Success",
# "status_code": 200,
# "type": "sync"
# }
instances = self.socket.do('GET', '/1.0/instances')
return [m.split('/')[3] for m in instances['metadata']]
def _get_config(self, branch, name):
"""Get inventory of container
"""Get inventory of instance
Get config of container
Get config of instance
Args:
str(branch): Name oft the API-Branch
str(name): Name of Container
str(name): Name of instance
Kwargs:
None
Source:
@@ -321,7 +347,7 @@ class InventoryModule(BaseInventoryPlugin):
Raises:
None
Returns:
dict(config): Config of the container"""
dict(config): Config of the instance"""
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])))}
@@ -329,13 +355,13 @@ class InventoryModule(BaseInventoryPlugin):
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
def get_instance_data(self, names):
"""Create Inventory of the instance
Iterate through the different branches of the containers and collect Informations.
Iterate through the different branches of the instances and collect Informations.
Args:
list(names): List of container names
list(names): List of instance names
Kwargs:
None
Raises:
@@ -344,20 +370,20 @@ class InventoryModule(BaseInventoryPlugin):
None"""
# tuple(('instances','metadata/templates')) to get section in branch
# e.g. /1.0/instances/<name>/metadata/templates
branches = ['containers', ('instances', 'state')]
container_config = {}
branches = ['instances', ('instances', 'state')]
instance_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)
instance_config['instances'] = self._get_config(branch, name)
self.data = dict_merge(instance_config, self.data)
def get_network_data(self, names):
"""Create Inventory of the container
"""Create Inventory of the instance
Iterate through the different branches of the containers and collect Informations.
Iterate through the different branches of the instances and collect Informations.
Args:
list(names): List of container names
list(names): List of instance names
Kwargs:
None
Raises:
@@ -376,26 +402,26 @@ class InventoryModule(BaseInventoryPlugin):
network_config['networks'] = {name: None}
self.data = dict_merge(network_config, self.data)
def extract_network_information_from_container_config(self, container_name):
def extract_network_information_from_instance_config(self, instance_name):
"""Returns the network interface configuration
Returns the network ipv4 and ipv6 config of the container without local-link
Returns the network ipv4 and ipv6 config of the instance without local-link
Args:
str(container_name): Name oft he container
str(instance_name): Name oft he instance
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))
instance_network_interfaces = self._get_data_entry('instances/{0}/state/metadata/network'.format(instance_name))
network_configuration = None
if container_network_interfaces:
if instance_network_interfaces:
network_configuration = {}
gen_interface_names = [interface_name for interface_name in container_network_interfaces if interface_name != 'lo']
gen_interface_names = [interface_name for interface_name in instance_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']
gen_address = [address for address in instance_network_interfaces[interface_name]['addresses'] if address.get('scope') != 'link']
network_configuration[interface_name] = []
for address in gen_address:
address_set = {}
@@ -406,24 +432,24 @@ class InventoryModule(BaseInventoryPlugin):
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
def get_prefered_instance_network_interface(self, instance_name):
"""Helper to get the prefered interface of thr instance
Helper to get the prefered interface provide by neme pattern from 'prefered_container_network_interface'.
Helper to get the prefered interface provide by neme pattern from 'prefered_instance_network_interface'.
Args:
str(containe_name): name of container
str(containe_name): name of instance
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))
instance_network_interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name))
prefered_interface = None # init
if container_network_interfaces: # container have network interfaces
if instance_network_interfaces: # instance 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)]
net_generator = [interface for interface in instance_network_interfaces if interface.startswith(self.prefered_instance_network_interface)]
selected_interfaces = [] # init
for interface in net_generator:
selected_interfaces.append(interface)
@@ -431,13 +457,13 @@ class InventoryModule(BaseInventoryPlugin):
prefered_interface = sorted(selected_interfaces)[0]
return prefered_interface
def get_container_vlans(self, container_name):
"""Get VLAN(s) from container
def get_instance_vlans(self, instance_name):
"""Get VLAN(s) from instance
Helper to get the VLAN_ID from the container
Helper to get the VLAN_ID from the instance
Args:
str(containe_name): name of container
str(containe_name): name of instance
Kwargs:
None
Raises:
@@ -450,13 +476,13 @@ class InventoryModule(BaseInventoryPlugin):
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
# get networkdevices of instance 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)))
devices = self._get_data_entry('instances/{0}/instances/metadata/expanded_devices'.format(to_native(instance_name)))
for device in devices:
if 'network' in devices[device]:
if devices[device]['network'] in network_vlans:
@@ -492,14 +518,14 @@ class InventoryModule(BaseInventoryPlugin):
except KeyError:
return None
def _set_data_entry(self, container_name, key, value, path=None):
def _set_data_entry(self, instance_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(instance_name): name of instance
str(key): same as dict
*(value): same as dict
Kwargs:
@@ -510,24 +536,24 @@ class InventoryModule(BaseInventoryPlugin):
None"""
if not path:
path = self.data['inventory']
if container_name not in path:
path[container_name] = {}
if instance_name not in path:
path[instance_name] = {}
try:
if isinstance(value, dict) and key in path[container_name]:
path[container_name] = dict_merge(value, path[container_name][key])
if isinstance(value, dict) and key in path[instance_name]:
path[instance_name] = dict_merge(value, path[instance_name][key])
else:
path[container_name][key] = value
path[instance_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):
def extract_information_from_instance_configs(self):
"""Process configuration information
Preparation of the data
Args:
dict(configs): Container configurations
dict(configs): instance configurations
Kwargs:
None
Raises:
@@ -538,33 +564,35 @@ class InventoryModule(BaseInventoryPlugin):
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))
for instance_name in self.data['instances']:
self._set_data_entry(instance_name, 'os', self._get_data_entry(
'instances/{0}/instances/metadata/config/image.os'.format(instance_name)))
self._set_data_entry(instance_name, 'release', self._get_data_entry(
'instances/{0}/instances/metadata/config/image.release'.format(instance_name)))
self._set_data_entry(instance_name, 'version', self._get_data_entry(
'instances/{0}/instances/metadata/config/image.version'.format(instance_name)))
self._set_data_entry(instance_name, 'profile', self._get_data_entry(
'instances/{0}/instances/metadata/profiles'.format(instance_name)))
self._set_data_entry(instance_name, 'location', self._get_data_entry(
'instances/{0}/instances/metadata/location'.format(instance_name)))
self._set_data_entry(instance_name, 'state', self._get_data_entry(
'instances/{0}/instances/metadata/config/volatile.last_state.power'.format(instance_name)))
self._set_data_entry(instance_name, 'type', self._get_data_entry(
'instances/{0}/instances/metadata/type'.format(instance_name)))
self._set_data_entry(instance_name, 'network_interfaces', self.extract_network_information_from_instance_config(instance_name))
self._set_data_entry(instance_name, 'preferred_interface', self.get_prefered_instance_network_interface(instance_name))
self._set_data_entry(instance_name, 'vlan_ids', self.get_instance_vlans(instance_name))
def build_inventory_network(self, container_name):
"""Add the network interfaces of the container to the inventory
def build_inventory_network(self, instance_name):
"""Add the network interfaces of the instance 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>'
- if the instance have no interface -> 'ansible_connection: local'
- get preferred_interface & prefered_instance_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
- first Interface from: network_interfaces prefered_instance_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
Args:
str(container_name): name of container
str(instance_name): name of instance
Kwargs:
None
Raises:
@@ -572,45 +600,45 @@ class InventoryModule(BaseInventoryPlugin):
Returns:
None"""
def interface_selection(container_name):
"""Select container Interface for inventory
def interface_selection(instance_name):
"""Select instance Interface for inventory
Logic:
- get preferred_interface & prefered_container_network_family -> str(IP)
- first Interface from: network_interfaces prefered_container_network_family -> str(IP)
- get preferred_interface & prefered_instance_network_family -> str(IP)
- first Interface from: network_interfaces prefered_instance_network_family -> str(IP)
Args:
str(container_name): name of container
str(instance_name): name of instance
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
prefered_interface = self._get_data_entry('inventory/{0}/preferred_interface'.format(instance_name)) # name or None
prefered_instance_network_family = self.prefered_instance_network_family
ip_address = ''
if prefered_interface:
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(container_name, prefered_interface))
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(instance_name, prefered_interface))
for config in interface:
if config['family'] == prefered_container_network_family:
if config['family'] == prefered_instance_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
interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name))
for interface in interfaces.values():
for config in interface:
if config['family'] == prefered_instance_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))
if self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name)): # instance have network interfaces
self.inventory.set_variable(instance_name, 'ansible_connection', 'ssh')
self.inventory.set_variable(instance_name, 'ansible_host', interface_selection(instance_name))
else:
self.inventory.set_variable(container_name, 'ansible_connection', 'local')
self.inventory.set_variable(instance_name, 'ansible_connection', 'local')
def build_inventory_hosts(self):
"""Build host-part dynamic inventory
@@ -626,29 +654,33 @@ class InventoryModule(BaseInventoryPlugin):
None
Returns:
None"""
for container_name in self.data['inventory']:
# Only consider containers that match the "state" filter, if self.state is not None
for instance_name in self.data['inventory']:
instance_state = str(self._get_data_entry('inventory/{0}/state'.format(instance_name)) or "STOPPED").lower()
# Only consider instances 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():
if self.filter.lower() != instance_state:
continue
# add container
self.inventory.add_host(container_name)
# add instance
self.inventory.add_host(instance_name)
# add network informations
self.build_inventory_network(container_name)
self.build_inventory_network(instance_name)
# add os
self.inventory.set_variable(container_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(container_name)).lower())
self.inventory.set_variable(instance_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(instance_name)).lower())
# add release
self.inventory.set_variable(container_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(container_name)).lower())
self.inventory.set_variable(instance_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(instance_name)).lower())
# add profile
self.inventory.set_variable(container_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(container_name)))
self.inventory.set_variable(instance_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(instance_name)))
# add state
self.inventory.set_variable(container_name, 'ansible_lxd_state', self._get_data_entry('inventory/{0}/state'.format(container_name)).lower())
self.inventory.set_variable(instance_name, 'ansible_lxd_state', instance_state)
# add type
self.inventory.set_variable(instance_name, 'ansible_lxd_type', self._get_data_entry('inventory/{0}/type'.format(instance_name)))
# 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)))
if self._get_data_entry('inventory/{0}/location'.format(instance_name)) != "none": # wrong type by lxd 'none' != 'None'
self.inventory.set_variable(instance_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(instance_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)))
if self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)):
self.inventory.set_variable(instance_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)))
def build_inventory_groups_location(self, group_name):
"""create group by attribute: location
@@ -665,9 +697,9 @@ class InventoryModule(BaseInventoryPlugin):
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)
for instance_name in self.inventory.hosts:
if 'ansible_lxd_location' in self.inventory.get_host(instance_name).get_vars():
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_pattern(self, group_name):
"""create group by name pattern
@@ -686,10 +718,10 @@ class InventoryModule(BaseInventoryPlugin):
regex_pattern = self.groupby[group_name].get('attribute')
for container_name in self.inventory.hosts:
result = re.search(regex_pattern, container_name)
for instance_name in self.inventory.hosts:
result = re.search(regex_pattern, instance_name)
if result:
self.inventory.add_child(group_name, container_name)
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_network_range(self, group_name):
"""check if IP is in network-class
@@ -712,14 +744,14 @@ class InventoryModule(BaseInventoryPlugin):
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]:
for instance_name in self.inventory.hosts:
if self.data['inventory'][instance_name].get('network_interfaces') is not None:
for interface in self.data['inventory'][instance_name].get('network_interfaces'):
for interface_family in self.data['inventory'][instance_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)
self.inventory.add_child(group_name, instance_name)
except ValueError:
# Ignore invalid IP addresses returned by lxd
pass
@@ -730,7 +762,7 @@ class InventoryModule(BaseInventoryPlugin):
Args:
str(group_name): Group name
Kwargs:
Noneself.data['inventory'][container_name][interface]
None
Raises:
None
Returns:
@@ -739,12 +771,12 @@ class InventoryModule(BaseInventoryPlugin):
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)
gen_instances = [
instance_name for instance_name in self.inventory.hosts
if 'ansible_lxd_os' in self.inventory.get_host(instance_name).get_vars()]
for instance_name in gen_instances:
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_os'):
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_release(self, group_name):
"""create group by attribute: release
@@ -761,12 +793,12 @@ class InventoryModule(BaseInventoryPlugin):
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)
gen_instances = [
instance_name for instance_name in self.inventory.hosts
if 'ansible_lxd_release' in self.inventory.get_host(instance_name).get_vars()]
for instance_name in gen_instances:
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_release'):
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_profile(self, group_name):
"""create group by attribute: profile
@@ -783,12 +815,12 @@ class InventoryModule(BaseInventoryPlugin):
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)
gen_instances = [
instance_name for instance_name in self.inventory.hosts.keys()
if 'ansible_lxd_profile' in self.inventory.get_host(instance_name).get_vars().keys()]
for instance_name in gen_instances:
if self.groupby[group_name].get('attribute').lower() in self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_profile'):
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_vlanid(self, group_name):
"""create group by attribute: vlanid
@@ -805,12 +837,34 @@ class InventoryModule(BaseInventoryPlugin):
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)
gen_instances = [
instance_name for instance_name in self.inventory.hosts.keys()
if 'ansible_lxd_vlan_ids' in self.inventory.get_host(instance_name).get_vars().keys()]
for instance_name in gen_instances:
if self.groupby[group_name].get('attribute') in self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_vlan_ids').values():
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups_type(self, group_name):
"""create group by attribute: type
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_instances = [
instance_name for instance_name in self.inventory.hosts
if 'ansible_lxd_type' in self.inventory.get_host(instance_name).get_vars()]
for instance_name in gen_instances:
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_type'):
self.inventory.add_child(group_name, instance_name)
def build_inventory_groups(self):
"""Build group-part dynamic inventory
@@ -839,6 +893,7 @@ class InventoryModule(BaseInventoryPlugin):
* 'release'
* 'profile'
* 'vlanid'
* 'type'
Args:
str(group_name): Group name
@@ -864,6 +919,8 @@ class InventoryModule(BaseInventoryPlugin):
self.build_inventory_groups_profile(group_name)
elif self.groupby[group_name].get('type') == 'vlanid':
self.build_inventory_groups_vlanid(group_name)
elif self.groupby[group_name].get('type') == 'type':
self.build_inventory_groups_type(group_name)
else:
raise AnsibleParserError('Unknown group type: {0}'.format(to_native(group_name)))
@@ -890,10 +947,30 @@ class InventoryModule(BaseInventoryPlugin):
self.build_inventory_hosts()
self.build_inventory_groups()
def cleandata(self):
"""Clean the dynamic inventory
The first version of the inventory only supported container.
This will change in the future.
The following function cleans up the data and remove the all items with the wrong type.
Args:
None
Kwargs:
None
Raises:
None
Returns:
None"""
iter_keys = list(self.data['instances'].keys())
for instance_name in iter_keys:
if self._get_data_entry('instances/{0}/instances/metadata/type'.format(instance_name)) != self.type_filter:
del self.data['instances'][instance_name]
def _populate(self):
"""Return the hosts and groups
Returns the processed container configurations from the lxd import
Returns the processed instance configurations from the lxd import
Args:
None
@@ -906,10 +983,16 @@ class InventoryModule(BaseInventoryPlugin):
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_instance_data(self._get_instances())
self.get_network_data(self._get_networks())
self.extract_information_from_container_configs()
# The first version of the inventory only supported containers.
# This will change in the future.
# The following function cleans up the data.
if self.type_filter != 'both':
self.cleandata()
self.extract_information_from_instance_configs()
# self.display.vvv(self.save_json_data([os.path.abspath(__file__)]))
@@ -948,8 +1031,9 @@ class InventoryModule(BaseInventoryPlugin):
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')
self.prefered_instance_network_family = self.get_option('prefered_instance_network_family')
self.prefered_instance_network_interface = self.get_option('prefered_instance_network_interface')
self.type_filter = self.get_option('type_filter')
if self.get_option('state').lower() == 'none': # none in config is str()
self.filter = None
else:

View File

@@ -8,7 +8,7 @@ __metaclass__ = type
DOCUMENTATION = r'''
name: online
author:
- Remy Leone (@sieben)
- Remy Leone (@remyleone)
short_description: Scaleway (previously Online SAS or Online.net) inventory source
description:
- Get inventory hosts from Scaleway (previously Online SAS or Online.net).

View File

@@ -9,7 +9,7 @@ __metaclass__ = type
DOCUMENTATION = r'''
name: scaleway
author:
- Remy Leone (@sieben)
- Remy Leone (@remyleone)
short_description: Scaleway inventory source
description:
- Get inventory hosts from Scaleway.

View File

@@ -93,7 +93,7 @@ DOCUMENTATION = '''
environment variable and keep I(endpoints), I(host), and I(port) unused.
seealso:
- module: community.general.etcd3
- ref: etcd_lookup
- ref: ansible_collections.community.general.etcd_lookup
description: The etcd v2 lookup.
requirements:

View File

@@ -7,29 +7,40 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from distutils.version import StrictVersion
from ansible.module_utils.basic import missing_required_lib
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.common.text.converters import to_native
try:
from urllib import quote_plus # Python 2.X
from urlparse import urljoin
except ImportError:
from urllib.parse import quote_plus # Python 3+
from urllib.parse import quote_plus, urljoin # Python 3+
import traceback
GITLAB_IMP_ERR = None
try:
import gitlab
import requests
HAS_GITLAB_PACKAGE = True
except Exception:
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
def auth_argument_spec(spec=None):
arg_spec = (dict(
api_token=dict(type='str', no_log=True),
api_oauth_token=dict(type='str', no_log=True),
api_job_token=dict(type='str', no_log=True),
))
if spec:
arg_spec.update(spec)
return arg_spec
def find_project(gitlab_instance, identifier):
try:
project = gitlab_instance.projects.get(identifier)
@@ -58,6 +69,8 @@ def gitlab_authentication(module):
gitlab_user = module.params['api_username']
gitlab_password = module.params['api_password']
gitlab_token = module.params['api_token']
gitlab_oauth_token = module.params['api_oauth_token']
gitlab_job_token = module.params['api_job_token']
if not HAS_GITLAB_PACKAGE:
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
@@ -70,7 +83,16 @@ def gitlab_authentication(module):
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
private_token=gitlab_token, api_version=4)
else:
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token, api_version=4)
# We can create an oauth_token using a username and password
# https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
if gitlab_user:
data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}
resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=validate_certs)
resp_data = resp.json()
gitlab_oauth_token = resp_data["access_token"]
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,
oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
gitlab_instance.auth()
except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:

View File

@@ -0,0 +1,232 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
class iLORedfishUtils(RedfishUtils):
def get_ilo_sessions(self):
result = {}
# listing all users has always been slower than other operations, why?
session_list = []
sessions_results = []
# Get these entries, but does not fail if not found
properties = ['Description', 'Id', 'Name', 'UserName']
# Changed self.sessions_uri to Hardcoded string.
response = self.get_request(
self.root_uri + self.service_root + "SessionService/Sessions/")
if not response['ret']:
return response
result['ret'] = True
data = response['data']
if 'Oem' in data:
if data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]:
current_session = data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]
for sessions in data[u'Members']:
# session_list[] are URIs
session_list.append(sessions[u'@odata.id'])
# for each session, get details
for uri in session_list:
session = {}
if uri != current_session:
response = self.get_request(self.root_uri + uri)
if not response['ret']:
return response
data = response['data']
for property in properties:
if property in data:
session[property] = data[property]
sessions_results.append(session)
result["msg"] = sessions_results
result["ret"] = True
return result
def set_ntp_server(self, mgr_attributes):
result = {}
setkey = mgr_attributes['mgr_attr_name']
nic_info = self.get_manager_ethernet_uri()
ethuri = nic_info["nic_addr"]
response = self.get_request(self.root_uri + ethuri)
if not response['ret']:
return response
result['ret'] = True
data = response['data']
payload = {"DHCPv4": {
"UseNTPServers": ""
}}
if data["DHCPv4"]["UseNTPServers"]:
payload["DHCPv4"]["UseNTPServers"] = False
res_dhv4 = self.patch_request(self.root_uri + ethuri, payload)
if not res_dhv4['ret']:
return res_dhv4
payload = {"DHCPv6": {
"UseNTPServers": ""
}}
if data["DHCPv6"]["UseNTPServers"]:
payload["DHCPv6"]["UseNTPServers"] = False
res_dhv6 = self.patch_request(self.root_uri + ethuri, payload)
if not res_dhv6['ret']:
return res_dhv6
datetime_uri = self.manager_uri + "DateTime"
response = self.get_request(self.root_uri + datetime_uri)
if not response['ret']:
return response
data = response['data']
ntp_list = data[setkey]
if(len(ntp_list) == 2):
ntp_list.pop(0)
ntp_list.append(mgr_attributes['mgr_attr_value'])
payload = {setkey: ntp_list}
response1 = self.patch_request(self.root_uri + datetime_uri, payload)
if not response1['ret']:
return response1
return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgr_attributes['mgr_attr_name']}
def set_time_zone(self, attr):
key = attr['mgr_attr_name']
uri = self.manager_uri + "DateTime/"
response = self.get_request(self.root_uri + uri)
if not response['ret']:
return response
data = response["data"]
if key not in data:
return {'ret': False, 'changed': False, 'msg': "Key %s not found" % key}
timezones = data["TimeZoneList"]
index = ""
for tz in timezones:
if attr['mgr_attr_value'] in tz["Name"]:
index = tz["Index"]
break
payload = {key: {"Index": index}}
response = self.patch_request(self.root_uri + uri, payload)
if not response['ret']:
return response
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
def set_dns_server(self, attr):
key = attr['mgr_attr_name']
nic_info = self.get_manager_ethernet_uri()
uri = nic_info["nic_addr"]
response = self.get_request(self.root_uri + uri)
if not response['ret']:
return response
data = response['data']
dns_list = data["Oem"]["Hpe"]["IPv4"][key]
if len(dns_list) == 3:
dns_list.pop(0)
dns_list.append(attr['mgr_attr_value'])
payload = {
"Oem": {
"Hpe": {
"IPv4": {
key: dns_list
}
}
}
}
response = self.patch_request(self.root_uri + uri, payload)
if not response['ret']:
return response
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
def set_domain_name(self, attr):
key = attr['mgr_attr_name']
nic_info = self.get_manager_ethernet_uri()
ethuri = nic_info["nic_addr"]
response = self.get_request(self.root_uri + ethuri)
if not response['ret']:
return response
data = response['data']
payload = {"DHCPv4": {
"UseDomainName": ""
}}
if data["DHCPv4"]["UseDomainName"]:
payload["DHCPv4"]["UseDomainName"] = False
res_dhv4 = self.patch_request(self.root_uri + ethuri, payload)
if not res_dhv4['ret']:
return res_dhv4
payload = {"DHCPv6": {
"UseDomainName": ""
}}
if data["DHCPv6"]["UseDomainName"]:
payload["DHCPv6"]["UseDomainName"] = False
res_dhv6 = self.patch_request(self.root_uri + ethuri, payload)
if not res_dhv6['ret']:
return res_dhv6
domain_name = attr['mgr_attr_value']
payload = {"Oem": {
"Hpe": {
key: domain_name
}
}}
response = self.patch_request(self.root_uri + ethuri, payload)
if not response['ret']:
return response
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
def set_wins_registration(self, mgrattr):
Key = mgrattr['mgr_attr_name']
nic_info = self.get_manager_ethernet_uri()
ethuri = nic_info["nic_addr"]
payload = {
"Oem": {
"Hpe": {
"IPv4": {
Key: False
}
}
}
}
response = self.patch_request(self.root_uri + ethuri, payload)
if not response['ret']:
return response
return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgrattr['mgr_attr_name']}

View File

@@ -52,3 +52,36 @@ def module_fails_on_exception(func):
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
output=self.output, vars=self.vars.output(), **self.output)
return wrapper
def check_mode_skip(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
if not self.module.check_mode:
return func(self, *args, **kwargs)
return wrapper
def check_mode_skip_returns(callable=None, value=None):
def deco(func):
if callable is not None:
@wraps(func)
def wrapper_callable(self, *args, **kwargs):
if self.module.check_mode:
return callable(self, *args, **kwargs)
return func(self, *args, **kwargs)
return wrapper_callable
if value is not None:
@wraps(func)
def wrapper_value(self, *args, **kwargs):
if self.module.check_mode:
return value
return func(self, *args, **kwargs)
return wrapper_value
if callable is None and value is None:
return check_mode_skip
return deco

View File

@@ -0,0 +1,61 @@
# -*- 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
class DeprecateAttrsMixin(object):
def _deprecate_setup(self, attr, target, module):
if target is None:
target = self
if not hasattr(target, attr):
raise ValueError("Target {0} has no attribute {1}".format(target, attr))
if module is None:
if isinstance(target, AnsibleModule):
module = target
elif hasattr(target, "module") and isinstance(target.module, AnsibleModule):
module = target.module
else:
raise ValueError("Failed to automatically discover the AnsibleModule instance. Pass 'module' parameter explicitly.")
# setup internal state dicts
value_attr = "__deprecated_attr_value"
trigger_attr = "__deprecated_attr_trigger"
if not hasattr(target, value_attr):
setattr(target, value_attr, {})
if not hasattr(target, trigger_attr):
setattr(target, trigger_attr, {})
value_dict = getattr(target, value_attr)
trigger_dict = getattr(target, trigger_attr)
return target, module, value_dict, trigger_dict
def _deprecate_attr(self, attr, msg, version=None, date=None, collection_name=None, target=None, value=None, module=None):
target, module, value_dict, trigger_dict = self._deprecate_setup(attr, target, module)
value_dict[attr] = getattr(target, attr, value)
trigger_dict[attr] = False
def _trigger():
if not trigger_dict[attr]:
module.deprecate(msg, version=version, date=date, collection_name=collection_name)
trigger_dict[attr] = True
def _getter(_self):
_trigger()
return value_dict[attr]
def _setter(_self, new_value):
_trigger()
value_dict[attr] = new_value
# override attribute
prop = property(_getter)
setattr(target, attr, prop)
setattr(target, "_{0}_setter".format(attr), prop.setter(_setter))

View File

@@ -13,9 +13,10 @@ from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd im
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
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin
class ModuleHelper(VarsMixin, DependencyMixin, ModuleHelperBase):
class ModuleHelper(DeprecateAttrsMixin, VarsMixin, DependencyMixin, ModuleHelperBase):
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
facts_name = None
output_params = ()
@@ -36,6 +37,15 @@ class ModuleHelper(VarsMixin, DependencyMixin, ModuleHelperBase):
fact=name in self.facts_params,
)
self._deprecate_attr(
attr="VarDict",
msg="ModuleHelper.VarDict attribute is deprecated, use VarDict from "
"the ansible_collections.community.general.plugins.module_utils.mh.mixins.vars module instead",
version="6.0.0",
collection_name="community.general",
target=ModuleHelper,
module=self.module)
def update_output(self, **kwargs):
self.update_vars(meta={"output": True}, **kwargs)

View File

@@ -54,6 +54,17 @@ def proxmox_to_ansible_bool(value):
return True if value == 1 else False
def ansible_to_proxmox_bool(value):
'''Convert Ansible representation of a boolean to be proxmox-friendly'''
if value is None:
return None
if not isinstance(value, bool):
raise ValueError("%s must be of type bool not %s" % (value, type(value)))
return 1 if value else 0
class ProxmoxAnsible(object):
"""Base class for Proxmox modules"""
def __init__(self, module):

View File

@@ -1834,12 +1834,16 @@ class RedfishUtils(object):
result['ret'] = True
data = response['data']
for device in data[u'Fans']:
fan = {}
for property in properties:
if property in device:
fan[property] = device[property]
fan_results.append(fan)
# Checking if fans are present
if u'Fans' in data:
for device in data[u'Fans']:
fan = {}
for property in properties:
if property in device:
fan[property] = device[property]
fan_results.append(fan)
else:
return {'ret': False, 'msg': "No Fans present"}
result["entries"] = fan_results
return result
@@ -2701,39 +2705,14 @@ class RedfishUtils(object):
return self.aggregate_managers(self.get_manager_health_report)
def set_manager_nic(self, nic_addr, nic_config):
# Get EthernetInterface collection
response = self.get_request(self.root_uri + self.manager_uri)
if response['ret'] is False:
return response
data = response['data']
if 'EthernetInterfaces' not in data:
return {'ret': False, 'msg': "EthernetInterfaces resource not found"}
ethernetinterfaces_uri = data["EthernetInterfaces"]["@odata.id"]
response = self.get_request(self.root_uri + ethernetinterfaces_uri)
if response['ret'] is False:
return response
data = response['data']
uris = [a.get('@odata.id') for a in data.get('Members', []) if
a.get('@odata.id')]
# Get the manager ethernet interface uri
nic_info = self.get_manager_ethernet_uri(nic_addr)
# Find target EthernetInterface
target_ethernet_uri = None
target_ethernet_current_setting = None
if nic_addr == 'null':
# Find root_uri matched EthernetInterface when nic_addr is not specified
nic_addr = (self.root_uri).split('/')[-1]
nic_addr = nic_addr.split(':')[0] # split port if existing
for uri in uris:
response = self.get_request(self.root_uri + uri)
if response['ret'] is False:
return response
data = response['data']
if '"' + nic_addr.lower() + '"' in str(data).lower() or "'" + nic_addr.lower() + "'" in str(data).lower():
target_ethernet_uri = uri
target_ethernet_current_setting = data
break
if target_ethernet_uri is None:
return {'ret': False, 'msg': "No matched EthernetInterface found under Manager"}
if nic_info.get('nic_addr') is None:
return nic_info
else:
target_ethernet_uri = nic_info['nic_addr']
target_ethernet_current_setting = nic_info['ethernet_setting']
# Convert input to payload and check validity
payload = {}
@@ -2797,6 +2776,50 @@ class RedfishUtils(object):
return response
return {'ret': True, 'changed': True, 'msg': "Modified Manager NIC"}
# A helper function to get the EthernetInterface URI
def get_manager_ethernet_uri(self, nic_addr='null'):
# Get EthernetInterface collection
response = self.get_request(self.root_uri + self.manager_uri)
if not response['ret']:
return response
data = response['data']
if 'EthernetInterfaces' not in data:
return {'ret': False, 'msg': "EthernetInterfaces resource not found"}
ethernetinterfaces_uri = data["EthernetInterfaces"]["@odata.id"]
response = self.get_request(self.root_uri + ethernetinterfaces_uri)
if not response['ret']:
return response
data = response['data']
uris = [a.get('@odata.id') for a in data.get('Members', []) if
a.get('@odata.id')]
# Find target EthernetInterface
target_ethernet_uri = None
target_ethernet_current_setting = None
if nic_addr == 'null':
# Find root_uri matched EthernetInterface when nic_addr is not specified
nic_addr = (self.root_uri).split('/')[-1]
nic_addr = nic_addr.split(':')[0] # split port if existing
for uri in uris:
response = self.get_request(self.root_uri + uri)
if not response['ret']:
return response
data = response['data']
data_string = json.dumps(data)
if nic_addr.lower() in data_string.lower():
target_ethernet_uri = uri
target_ethernet_current_setting = data
break
nic_info = {}
nic_info['nic_addr'] = target_ethernet_uri
nic_info['ethernet_setting'] = target_ethernet_current_setting
if target_ethernet_uri is None:
return {}
else:
return nic_info
def set_hostinterface_attributes(self, hostinterface_config, hostinterface_id=None):
response = self.get_request(self.root_uri + self.manager_uri)
if response['ret'] is False:

View File

@@ -422,6 +422,7 @@ import shutil
import subprocess
import tempfile
import time
import shlex
try:
import lxc
@@ -661,9 +662,8 @@ class LxcContainerManagement(object):
"""
for key, value in variables_dict.items():
build_command.append(
'%s %s' % (key, value)
)
build_command.append(str(key))
build_command.append(str(value))
return build_command
def _get_vars(self, variables):
@@ -686,24 +686,6 @@ class LxcContainerManagement(object):
return_dict[v] = _var
return return_dict
def _run_command(self, build_command, unsafe_shell=False):
"""Return information from running an Ansible Command.
This will squash the build command list into a string and then
execute the command via Ansible. The output is returned to the method.
This output is returned as `return_code`, `stdout`, `stderr`.
:param build_command: Used for the command and all options.
:type build_command: ``list``
:param unsafe_shell: Enable or Disable unsafe sell commands.
:type unsafe_shell: ``bol``
"""
return self.module.run_command(
' '.join(build_command),
use_unsafe_shell=unsafe_shell
)
def _config(self):
"""Configure an LXC container.
@@ -810,7 +792,7 @@ class LxcContainerManagement(object):
elif self.module.params.get('backing_store') == 'overlayfs':
build_command.append('--snapshot')
rc, return_data, err = self._run_command(build_command)
rc, return_data, err = self.module.run_command(build_command)
if rc != 0:
message = "Failed executing %s." % os.path.basename(clone_cmd)
self.failure(
@@ -843,7 +825,7 @@ class LxcContainerManagement(object):
build_command = [
self.module.get_bin_path('lxc-create', True),
'--name %s' % self.container_name,
'--name', self.container_name,
'--quiet'
]
@@ -869,10 +851,12 @@ class LxcContainerManagement(object):
log_path = os.getenv('HOME')
build_command.extend([
'--logfile %s' % os.path.join(
'--logfile',
os.path.join(
log_path, 'lxc-%s.log' % self.container_name
),
'--logpriority %s' % self.module.params.get(
'--logpriority',
self.module.params.get(
'container_log_level'
).upper()
])
@@ -880,9 +864,10 @@ class LxcContainerManagement(object):
# Add the template commands to the end of the command if there are any
template_options = self.module.params.get('template_options', None)
if template_options:
build_command.append('-- %s' % template_options)
build_command.append('--')
build_command += shlex.split(template_options)
rc, return_data, err = self._run_command(build_command)
rc, return_data, err = self.module.run_command(build_command)
if rc != 0:
message = "Failed executing lxc-create."
self.failure(
@@ -1186,7 +1171,7 @@ class LxcContainerManagement(object):
self.module.get_bin_path('lxc-config', True),
"lxc.bdev.lvm.vg"
]
rc, vg, err = self._run_command(build_command)
rc, vg, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1204,7 +1189,7 @@ class LxcContainerManagement(object):
build_command = [
self.module.get_bin_path('lvs', True)
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1231,7 +1216,7 @@ class LxcContainerManagement(object):
'--units',
'g'
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1262,7 +1247,7 @@ class LxcContainerManagement(object):
'--units',
'g'
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1311,7 +1296,7 @@ class LxcContainerManagement(object):
os.path.join(vg, source_lv),
"-L%sg" % snapshot_size_gb
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1336,7 +1321,7 @@ class LxcContainerManagement(object):
"/dev/%s/%s" % (vg, lv_name),
mount_point,
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1380,9 +1365,8 @@ class LxcContainerManagement(object):
'.'
]
rc, stdout, err = self._run_command(
build_command=build_command,
unsafe_shell=True
rc, stdout, err = self.module.run_command(
build_command
)
os.umask(old_umask)
@@ -1410,7 +1394,7 @@ class LxcContainerManagement(object):
"-f",
"%s/%s" % (vg, lv_name),
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1442,11 +1426,10 @@ class LxcContainerManagement(object):
self.module.get_bin_path('rsync', True),
'-aHAX',
fs_path,
temp_dir
temp_dir,
]
rc, stdout, err = self._run_command(
rc, stdout, err = self.module.run_command(
build_command,
unsafe_shell=True
)
if rc != 0:
self.failure(
@@ -1467,7 +1450,7 @@ class LxcContainerManagement(object):
self.module.get_bin_path('umount', True),
mount_point,
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,
@@ -1489,12 +1472,12 @@ class LxcContainerManagement(object):
build_command = [
self.module.get_bin_path('mount', True),
'-t overlayfs',
'-o lowerdir=%s,upperdir=%s' % (lowerdir, upperdir),
'-t', 'overlayfs',
'-o', 'lowerdir=%s,upperdir=%s' % (lowerdir, upperdir),
'overlayfs',
mount_point,
]
rc, stdout, err = self._run_command(build_command)
rc, stdout, err = self.module.run_command(build_command)
if rc != 0:
self.failure(
err=err,

View File

@@ -359,6 +359,10 @@ except ImportError:
from ansible.module_utils.basic import AnsibleModule, env_fallback
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.proxmox import (
ansible_to_proxmox_bool
)
VZ_TYPE = None
@@ -605,14 +609,14 @@ def main():
netif=module.params['netif'],
mounts=module.params['mounts'],
ip_address=module.params['ip_address'],
onboot=int(module.params['onboot']),
onboot=ansible_to_proxmox_bool(module.params['onboot']),
cpuunits=module.params['cpuunits'],
nameserver=module.params['nameserver'],
searchdomain=module.params['searchdomain'],
force=int(module.params['force']),
force=ansible_to_proxmox_bool(module.params['force']),
pubkey=module.params['pubkey'],
features=",".join(module.params['features']) if module.params['features'] is not None else None,
unprivileged=int(module.params['unprivileged']),
unprivileged=ansible_to_proxmox_bool(module.params['unprivileged']),
description=module.params['description'],
hookscript=module.params['hookscript'])

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the servers.
- U(https://www.online.net/en/dedicated-server)
author:
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.online

View File

@@ -12,7 +12,7 @@ short_description: Gather information about Online user.
description:
- Gather information about the user.
author:
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.online
'''

View File

@@ -16,7 +16,7 @@ DOCUMENTATION = '''
---
module: scaleway_compute
short_description: Scaleway compute management module
author: Remy Leone (@sieben)
author: Remy Leone (@remyleone)
description:
- "This module manages compute instances on Scaleway."
extends_documentation_fragment:

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway images available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.scaleway

View File

@@ -13,7 +13,7 @@ DOCUMENTATION = '''
---
module: scaleway_ip
short_description: Scaleway IP management module
author: Remy Leone (@sieben)
author: Remy Leone (@remyleone)
description:
- This module manages IP on Scaleway account
U(https://developer.scaleway.com)

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway ips available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.scaleway

View File

@@ -16,7 +16,7 @@ DOCUMENTATION = '''
---
module: scaleway_lb
short_description: Scaleway load-balancer management module
author: Remy Leone (@sieben)
author: Remy Leone (@remyleone)
description:
- "This module manages load-balancers on Scaleway."
extends_documentation_fragment:

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway organizations available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
options:
api_url:
description:

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway security groups available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
options:
region:
type: str

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway servers available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.scaleway

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway snapshot available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.scaleway

View File

@@ -16,7 +16,7 @@ DOCUMENTATION = '''
---
module: scaleway_sshkey
short_description: Scaleway SSH keys management module
author: Remy Leone (@sieben)
author: Remy Leone (@remyleone)
description:
- This module manages SSH keys on Scaleway account
U(https://developer.scaleway.com)

View File

@@ -16,7 +16,7 @@ DOCUMENTATION = '''
---
module: scaleway_user_data
short_description: Scaleway user_data management module
author: Remy Leone (@sieben)
author: Remy Leone (@remyleone)
description:
- "This module manages user_data on compute instances on Scaleway."
- "It can be used to configure cloud-init for instance"

View File

@@ -15,7 +15,7 @@ description:
- Gather information about the Scaleway volumes available.
author:
- "Yanis Guenane (@Spredzy)"
- "Remy Leone (@sieben)"
- "Remy Leone (@remyleone)"
extends_documentation_fragment:
- community.general.scaleway

View File

@@ -60,6 +60,7 @@ extends_documentation_fragment:
- community.general.redis.documentation
seealso:
- module: community.general.redis_data_incr
- module: community.general.redis_data_info
- module: community.general.redis
'''

View File

@@ -47,7 +47,7 @@ notes:
run the C(GET) command on the key, otherwise the module will fail.
seealso:
- module: community.general.redis_set
- module: community.general.redis_data
- module: community.general.redis_data_info
- module: community.general.redis
'''

View File

@@ -26,6 +26,8 @@ extends_documentation_fragment:
- community.general.redis
seealso:
- module: community.general.redis_data
- module: community.general.redis_data_incr
- module: community.general.redis_info
- module: community.general.redis
'''

View File

@@ -0,0 +1 @@
./net_tools/dnsimple_info.py

View File

@@ -85,11 +85,6 @@ import os.path
import shutil
import tempfile
try: # python 3.3+
from shlex import quote
except ImportError: # older python
from pipes import quote
from ansible.module_utils.basic import AnsibleModule
@@ -154,9 +149,9 @@ def main():
# Use 7zip when we have a binary, otherwise try to mount
if binary:
cmd = '%s x "%s" -o"%s" %s' % (binary, image, tmp_dir, ' '.join([quote(f) for f in extract_files]))
cmd = [binary, 'x', image, '-o%s' % tmp_dir] + extract_files
else:
cmd = 'mount -o loop,ro "%s" "%s"' % (image, tmp_dir)
cmd = [module.get_bin_path('mount'), '-o', 'loop,ro', image, tmp_dir]
rc, out, err = module.run_command(cmd)
if rc != 0:
@@ -201,7 +196,7 @@ def main():
result['changed'] = True
finally:
if not binary:
module.run_command('umount "%s"' % tmp_dir)
module.run_command([module.get_bin_path('umount'), tmp_dir])
shutil.rmtree(tmp_dir)

View File

@@ -12,9 +12,9 @@ DOCUMENTATION = '''
module: xattr
short_description: Manage user defined extended attributes
description:
- Manages filesystem user defined extended attributes.
- Requires that extended attributes are enabled on the target filesystem
and that the setfattr/getfattr utilities are present.
- Manages filesystem user defined extended attributes.
- Requires that extended attributes are enabled on the target filesystem
and that the setfattr/getfattr utilities are present.
options:
path:
description:
@@ -34,13 +34,13 @@ options:
type: str
value:
description:
- The value to set the named name/key to, it automatically sets the C(state) to 'set'.
- The value to set the named name/key to, it automatically sets the I(state) to C(present).
type: str
state:
description:
- defines which state you want to do.
C(read) retrieves the current value for a C(key) (default)
C(present) sets C(name) to C(value), default if value is set
C(read) retrieves the current value for a I(key) (default)
C(present) sets I(path) to C(value), default if value is set
C(all) dumps all data
C(keys) retrieves all keys
C(absent) deletes the key
@@ -49,14 +49,14 @@ options:
default: read
follow:
description:
- If C(yes), dereferences symlinks and sets/gets attributes on symlink target,
- If C(true), dereferences symlinks and sets/gets attributes on symlink target,
otherwise acts on symlink itself.
type: bool
default: yes
default: true
notes:
- As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well.
author:
- Brian Coca (@bcoca)
- Brian Coca (@bcoca)
'''
EXAMPLES = '''
@@ -116,7 +116,8 @@ def get_xattr(module, path, key, follow):
if key is None:
cmd.append('-d')
else:
cmd.append('-n %s' % key)
cmd.append('-n')
cmd.append(key)
cmd.append(path)
return _run_xattr(module, cmd, False)
@@ -127,8 +128,10 @@ def set_xattr(module, path, key, value, follow):
cmd = [module.get_bin_path('setfattr', True)]
if not follow:
cmd.append('-h')
cmd.append('-n %s' % key)
cmd.append('-v %s' % value)
cmd.append('-n')
cmd.append(key)
cmd.append('-v')
cmd.append(value)
cmd.append(path)
return _run_xattr(module, cmd)
@@ -139,7 +142,8 @@ def rm_xattr(module, path, key, follow):
cmd = [module.get_bin_path('setfattr', True)]
if not follow:
cmd.append('-h')
cmd.append('-x %s' % key)
cmd.append('-x')
cmd.append(key)
cmd.append(path)
return _run_xattr(module, cmd, False)
@@ -148,7 +152,7 @@ def rm_xattr(module, path, key, follow):
def _run_xattr(module, cmd, check_rc=True):
try:
(rc, out, err) = module.run_command(' '.join(cmd), check_rc=check_rc)
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
except Exception as e:
module.fail_json(msg="%s!" % to_native(e))

View File

@@ -0,0 +1 @@
source_control/gitlab/gitlab_branch.py

View File

@@ -64,6 +64,7 @@ options:
choices:
- ldap
- kerberos
- sssd
provider_type:
description:
@@ -83,9 +84,10 @@ options:
config:
description:
- Dict specifying the configuration options for the provider; the contents differ depending on
the value of I(provider_id). Examples are given below for C(ldap) and C(kerberos). It is easiest
to obtain valid config values by dumping an already-existing user federation configuration
through check-mode in the I(existing) field.
the value of I(provider_id). Examples are given below for C(ldap), C(kerberos) and C(sssd).
It is easiest to obtain valid config values by dumping an already-existing user federation
configuration through check-mode in the I(existing) field.
- The value C(sssd) has been supported since community.general 4.2.0.
type: dict
suboptions:
enabled:
@@ -531,6 +533,22 @@ EXAMPLES = '''
allowPasswordAuthentication: false
updateProfileFirstLogin: false
- name: Create sssd user federation
community.general.keycloak_user_federation:
auth_keycloak_url: https://keycloak.example.com/auth
auth_realm: master
auth_username: admin
auth_password: password
realm: my-realm
name: my-sssd
state: present
provider_id: sssd
provider_type: org.keycloak.storage.UserStorageProvider
config:
priority: 0
enabled: true
cachePolicy: DEFAULT
- name: Delete user federation
community.general.keycloak_user_federation:
auth_keycloak_url: https://keycloak.example.com/auth
@@ -765,7 +783,7 @@ def main():
realm=dict(type='str', default='master'),
id=dict(type='str'),
name=dict(type='str'),
provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos']),
provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos', 'sssd']),
provider_type=dict(type='str', aliases=['providerType'], default='org.keycloak.storage.UserStorageProvider'),
parent_id=dict(type='str', aliases=['parentId']),
mappers=dict(type='list', elements='dict', options=mapper_spec),
@@ -843,8 +861,8 @@ def main():
# special handling of mappers list to allow change detection
if module.params.get('mappers') is not None:
if module.params['provider_id'] == 'kerberos':
module.fail_json(msg='Cannot configure mappers for Kerberos federations.')
if module.params['provider_id'] in ['kerberos', 'sssd']:
module.fail_json(msg='Cannot configure mappers for {type} provider.'.format(type=module.params['provider_id']))
for change in module.params['mappers']:
change = dict((k, v) for k, v in change.items() if change[k] is not None)
if change.get('id') is None and change.get('name') is None:

View File

@@ -0,0 +1 @@
remote_management/redfish/ilo_redfish_config.py

View File

@@ -0,0 +1 @@
remote_management/redfish/ilo_redfish_info.py

View File

@@ -63,7 +63,7 @@ def query_log_status(module, le_path, path, state="present"):
""" Returns whether a log is followed or not. """
if state == "present":
rc, out, err = module.run_command("%s followed %s" % (le_path, path))
rc, out, err = module.run_command([le_path, "followed", path])
if rc == 0:
return True
@@ -87,7 +87,7 @@ def follow_log(module, le_path, logs, name=None, logtype=None):
cmd.extend(['--name', name])
if logtype:
cmd.extend(['--type', logtype])
rc, out, err = module.run_command(' '.join(cmd))
rc, out, err = module.run_command(cmd)
if not query_log_status(module, le_path, log):
module.fail_json(msg="failed to follow '%s': %s" % (log, err.strip()))

View File

@@ -82,7 +82,7 @@ PACKAGE_STATE_MAP = dict(
def is_plugin_present(module, plugin_bin, plugin_name):
cmd_args = [plugin_bin, "list", plugin_name]
rc, out, err = module.run_command(" ".join(cmd_args))
rc, out, err = module.run_command(cmd_args)
return rc == 0

View File

@@ -122,7 +122,7 @@ class Monit(object):
return self._monit_version
def _get_monit_version(self):
rc, out, err = self.module.run_command('%s -V' % self.monit_bin_path, check_rc=True)
rc, out, err = self.module.run_command([self.monit_bin_path, '-V'], check_rc=True)
version_line = out.split('\n')[0]
raw_version = re.search(r"([0-9]+\.){1,2}([0-9]+)?", version_line).group()
return raw_version, tuple(map(int, raw_version.split('.')))
@@ -140,7 +140,7 @@ class Monit(object):
@property
def command_args(self):
return "-B" if self.monit_version() > (5, 18) else ""
return ["-B"] if self.monit_version() > (5, 18) else []
def get_status(self, validate=False):
"""Return the status of the process in monit.
@@ -149,7 +149,7 @@ class Monit(object):
"""
monit_command = "validate" if validate else "status"
check_rc = False if validate else True # 'validate' always has rc = 1
command = ' '.join([self.monit_bin_path, monit_command, self.command_args, self.process_name])
command = [self.monit_bin_path, monit_command] + self.command_args + [self.process_name]
rc, out, err = self.module.run_command(command, check_rc=check_rc)
return self._parse_status(out, err)
@@ -182,7 +182,8 @@ class Monit(object):
return status
def is_process_present(self):
rc, out, err = self.module.run_command('%s summary %s' % (self.monit_bin_path, self.command_args), check_rc=True)
command = [self.monit_bin_path, 'summary'] + self.command_args
rc, out, err = self.module.run_command(command, check_rc=True)
return bool(re.findall(r'\b%s\b' % self.process_name, out))
def is_process_running(self):
@@ -190,7 +191,7 @@ class Monit(object):
def run_command(self, command):
"""Runs a monit command, and returns the new status."""
return self.module.run_command('%s %s %s' % (self.monit_bin_path, command, self.process_name), check_rc=True)
return self.module.run_command([self.monit_bin_path, command, self.process_name], check_rc=True)
def wait_for_status_change(self, current_status):
running_status = self.get_status()
@@ -228,7 +229,7 @@ class Monit(object):
return current_status
def reload(self):
rc, out, err = self.module.run_command('%s reload' % self.monit_bin_path)
rc, out, err = self.module.run_command([self.monit_bin_path, 'reload'])
if rc != 0:
self.exit_fail('monit reload failed', stdout=out, stderr=err)
self.exit_success(state='reloaded')

View File

@@ -0,0 +1,335 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: Edward Hilgendorf, <edward@hilgendorf.me>
# 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: dnsimple_info
short_description: Pull basic info from DNSimple API
version_added: "4.2.0"
description: Retrieve existing records and domains from DNSimple API.
options:
name:
description:
- The domain name to retrieve info from.
- Will return all associated records for this domain if specified.
- If not specified, will return all domains associated with the account ID.
type: str
account_id:
description: The account ID to query.
required: true
type: str
api_key:
description: The API key to use.
required: true
type: str
record:
description:
- The record to find.
- If specified, only this record will be returned instead of all records.
required: false
type: str
sandbox:
description: Whether or not to use sandbox environment.
required: false
default: false
type: bool
author:
- Edward Hilgendorf (@edhilgendorf)
'''
EXAMPLES = r'''
- name: Get all domains from an account
community.general.dnsimple_info:
account_id: "1234"
api_key: "1234"
- name: Get all records from a domain
community.general.dnsimple_info:
name: "example.com"
account_id: "1234"
api_key: "1234"
- name: Get all info from a matching record
community.general.dnsimple_info:
name: "example.com"
record: "subdomain"
account_id: "1234"
api_key: "1234"
'''
RETURN = r'''
dnsimple_domain_info:
description: Returns a list of dictionaries of all domains associated with the supplied account ID.
type: list
elements: dict
returned: success when I(name) is not specified
sample:
- account_id: 1234
created_at: '2021-10-16T21:25:42Z'
id: 123456
last_transferred_at:
name: example.com
reverse: false
secondary: false
updated_at: '2021-11-10T20:22:50Z'
contains:
account_id:
description: The account ID.
type: int
created_at:
description: When the domain entry was created.
type: str
id:
description: ID of the entry.
type: int
last_transferred_at:
description: Date the domain was transferred, or empty if not.
type: str
name:
description: Name of the record.
type: str
reverse:
description: Whether or not it is a reverse zone record.
type: bool
updated_at:
description: When the domain entry was updated.
type: str
dnsimple_records_info:
description: Returns a list of dictionaries with all records for the domain supplied.
type: list
elements: dict
returned: success when I(name) is specified, but I(record) is not
sample:
- content: ns1.dnsimple.com admin.dnsimple.com
created_at: '2021-10-16T19:07:34Z'
id: 12345
name: 'catheadbiscuit'
parent_id: null
priority: null
regions:
- global
system_record: true
ttl: 3600
type: SOA
updated_at: '2021-11-15T23:55:51Z'
zone_id: example.com
contains:
content:
description: Content of the returned record.
type: str
created_at:
description: When the domain entry was created.
type: str
id:
description: ID of the entry.
type: int
name:
description: Name of the record.
type: str
parent_id:
description: Parent record or null.
type: int
priority:
description: Priority setting of the record.
type: str
regions:
description: List of regions where the record is available.
type: list
system_record:
description: Whether or not it is a system record.
type: bool
ttl:
description: Record TTL.
type: int
type:
description: Record type.
type: str
updated_at:
description: When the domain entry was updated.
type: str
zone_id:
description: ID of the zone that the record is associated with.
type: str
dnsimple_record_info:
description: Returns a list of dictionaries that match the record supplied.
returned: success when I(name) and I(record) are specified
type: list
elements: dict
sample:
- content: 1.2.3.4
created_at: '2021-11-15T23:55:51Z'
id: 123456
name: catheadbiscuit
parent_id: null
priority: null
regions:
- global
system_record: false
ttl: 3600
type: A
updated_at: '2021-11-15T23:55:51Z'
zone_id: example.com
contains:
content:
description: Content of the returned record.
type: str
created_at:
description: When the domain entry was created.
type: str
id:
description: ID of the entry.
type: int
name:
description: Name of the record.
type: str
parent_id:
description: Parent record or null.
type: int
priority:
description: Priority setting of the record.
type: str
regions:
description: List of regions where the record is available.
type: list
system_record:
description: Whether or not it is a system record.
type: bool
ttl:
description: Record TTL.
type: int
type:
description: Record type.
type: str
updated_at:
description: When the domain entry was updated.
type: str
zone_id:
description: ID of the zone that the record is associated with.
type: str
'''
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import missing_required_lib
import json
try:
from requests import Request, Session
except ImportError:
HAS_ANOTHER_LIBRARY = False
ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
else:
HAS_ANOTHER_LIBRARY = True
def build_url(account, key, is_sandbox):
headers = {'Accept': 'application/json',
'Authorization': 'Bearer ' + key}
url = 'https://api{sandbox}.dnsimple.com/'.format(
sandbox=".sandbox" if is_sandbox else "") + 'v2/' + account
req = Request(url=url, headers=headers)
prepped_request = req.prepare()
return prepped_request
def iterate_data(module, request_object):
base_url = request_object.url
response = Session().send(request_object)
if 'pagination' in response.json():
data = response.json()["data"]
pages = response.json()["pagination"]["total_pages"]
if int(pages) > 1:
for page in range(1, pages):
page = page + 1
request_object.url = base_url + '&page=' + str(page)
new_results = Session().send(request_object)
data = data + new_results.json()["data"]
return(data)
else:
module.fail_json('API Call failed, check ID, key and sandbox values')
def record_info(dnsimple_mod, req_obj):
req_obj.url, req_obj.method = req_obj.url + '/zones/' + dnsimple_mod.params["name"] + '/records?name=' + dnsimple_mod.params["record"], 'GET'
return iterate_data(dnsimple_mod, req_obj)
def domain_info(dnsimple_mod, req_obj):
req_obj.url, req_obj.method = req_obj.url + '/zones/' + dnsimple_mod.params["name"] + '/records?per_page=100', 'GET'
return iterate_data(dnsimple_mod, req_obj)
def account_info(dnsimple_mod, req_obj):
req_obj.url, req_obj.method = req_obj.url + '/zones/?per_page=100', 'GET'
return iterate_data(dnsimple_mod, req_obj)
def main():
# define available arguments/parameters a user can pass to the module
fields = {
"account_id": {"required": True, "type": "str"},
"api_key": {"required": True, "type": "str", "no_log": True},
"name": {"required": False, "type": "str"},
"record": {"required": False, "type": "str"},
"sandbox": {"required": False, "type": "bool", "default": False}
}
result = {
'changed': False
}
module = AnsibleModule(
argument_spec=fields,
supports_check_mode=True
)
params = module.params
req = build_url(params['account_id'],
params['api_key'],
params['sandbox'])
if not HAS_ANOTHER_LIBRARY:
# Needs: from ansible.module_utils.basic import missing_required_lib
module.exit_json(
msg=missing_required_lib('another_library'),
exception=ANOTHER_LIBRARY_IMPORT_ERROR)
# At minimum we need account and key
if params['account_id'] and params['api_key']:
# If we have a record return info on that record
if params['name'] and params['record']:
result['dnsimple_record_info'] = record_info(module, req)
module.exit_json(**result)
# If we have the account only and domain, return records for the domain
elif params['name']:
result['dnsimple_records_info'] = domain_info(module, req)
module.exit_json(**result)
# If we have the account only, return domains
else:
result['dnsimple_domain_info'] = account_info(module, req)
module.exit_json(**result)
else:
module.fail_json(msg="Need at least account_id and api_key")
if __name__ == '__main__':
main()

View File

@@ -76,7 +76,7 @@ class Namespace(object):
def exists(self):
'''Check if the namespace already exists'''
rc, out, err = self.module.run_command('ip netns list')
rc, out, err = self.module.run_command(['ip', 'netns', 'list'])
if rc != 0:
self.module.fail_json(msg=to_text(err))
return self.name in out

View File

@@ -70,7 +70,7 @@ options:
ip4:
description:
- List of IPv4 addresses to this interface.
- Use the format C(192.0.2.24/24).
- Use the format C(192.0.2.24/24) or C(192.0.2.24).
- If defined and I(method4) is not specified, automatically set C(ipv4.method) to C(manual).
type: list
elements: str
@@ -143,10 +143,11 @@ options:
version_added: 3.3.0
ip6:
description:
- The IPv6 address to this interface.
- Use the format C(abbe::cafe).
- List of IPv6 addresses to this interface.
- Use the format C(abbe::cafe/128) or C(abbe::cafe).
- If defined and I(method6) is not specified, automatically set C(ipv6.method) to C(manual).
type: str
type: list
elements: str
gw6:
description:
- The IPv6 gateway for this interface.
@@ -183,6 +184,18 @@ options:
type: str
choices: [ignore, auto, dhcp, link-local, manual, shared, disabled]
version_added: 2.2.0
ip_privacy6:
description:
- If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one.
type: str
choices: [disabled, prefer-public-addr, prefer-temp-addr, unknown]
version_added: 4.2.0
addr_gen_mode6:
description:
- Configure method for creating the address for use with IPv6 Stateless Address Autoconfiguration.
type: str
choices: [eui64, stable-privacy]
version_added: 4.2.0
mtu:
description:
- The connection MTU, e.g. 9000. This can't be applied when creating the interface and is done once the interface has been created.
@@ -1011,6 +1024,16 @@ EXAMPLES = r'''
- 192.0.3.100/24
state: present
- name: Add second ip6 address
community.general.nmcli:
conn_name: my-eth1
ifname: eth1
type: ethernet
ip6:
- 2001:db8::cafe
- 2002:db8::cafe
state: present
- name: Add VxLan
community.general.nmcli:
type: vxlan
@@ -1171,6 +1194,8 @@ class Nmcli(object):
self.dns6_search = module.params['dns6_search']
self.dns6_ignore_auto = module.params['dns6_ignore_auto']
self.method6 = module.params['method6']
self.ip_privacy6 = module.params['ip_privacy6']
self.addr_gen_mode6 = module.params['addr_gen_mode6']
self.mtu = module.params['mtu']
self.stp = module.params['stp']
self.priority = module.params['priority']
@@ -1255,7 +1280,7 @@ class Nmcli(object):
# IP address options.
if self.ip_conn_type and not self.master:
options.update({
'ipv4.addresses': self.ip4,
'ipv4.addresses': self.enforce_ipv4_cidr_notation(self.ip4),
'ipv4.dhcp-client-id': self.dhcp_client_id,
'ipv4.dns': self.dns4,
'ipv4.dns-search': self.dns4_search,
@@ -1268,13 +1293,15 @@ class Nmcli(object):
'ipv4.never-default': self.never_default4,
'ipv4.method': self.ipv4_method,
'ipv4.may-fail': self.may_fail4,
'ipv6.addresses': self.ip6,
'ipv6.addresses': self.enforce_ipv6_cidr_notation(self.ip6),
'ipv6.dns': self.dns6,
'ipv6.dns-search': self.dns6_search,
'ipv6.ignore-auto-dns': self.dns6_ignore_auto,
'ipv6.gateway': self.gw6,
'ipv6.ignore-auto-routes': self.gw6_ignore_auto,
'ipv6.method': self.ipv6_method,
'ipv6.ip6-privacy': self.ip_privacy6,
'ipv6.addr-gen-mode': self.addr_gen_mode6
})
# Layer 2 options.
@@ -1346,6 +1373,9 @@ class Nmcli(object):
options.update({
'vlan.id': self.vlanid,
'vlan.parent': self.vlandev,
'vlan.flags': self.flags,
'vlan.ingress': self.ingress,
'vlan.egress': self.egress,
})
elif self.type == 'vxlan':
options.update({
@@ -1388,6 +1418,8 @@ class Nmcli(object):
elif setting == self.mtu_setting:
# MTU is 'auto' by default when detecting changes.
convert_func = self.mtu_to_string
elif setting == 'ipv6.ip6-privacy':
convert_func = self.ip6_privacy_to_num
elif setting_type is list:
# Convert lists to strings for nmcli create/modify commands.
convert_func = self.list_to_string
@@ -1441,6 +1473,23 @@ class Nmcli(object):
else:
return to_text(mtu)
@staticmethod
def ip6_privacy_to_num(privacy):
ip6_privacy_values = {
'disabled': '0',
'prefer-public-addr': '1 (enabled, prefer public IP)',
'prefer-temp-addr': '2 (enabled, prefer temporary IP)',
'unknown': '-1',
}
if privacy is None:
return None
if privacy not in ip6_privacy_values:
raise AssertionError('{privacy} is invalid ip_privacy6 option'.format(privacy=privacy))
return ip6_privacy_values[privacy]
@property
def slave_conn_type(self):
return self.type in (
@@ -1458,6 +1507,18 @@ class Nmcli(object):
'sit',
)
@staticmethod
def enforce_ipv4_cidr_notation(ip4_addresses):
if ip4_addresses is None:
return None
return [address if '/' in address else address + '/32' for address in ip4_addresses]
@staticmethod
def enforce_ipv6_cidr_notation(ip6_addresses):
if ip6_addresses is None:
return None
return [address if '/' in address else address + '/128' for address in ip6_addresses]
@staticmethod
def bool_to_string(boolean):
if boolean:
@@ -1483,6 +1544,7 @@ class Nmcli(object):
'802-11-wireless.hidden'):
return bool
elif setting in ('ipv4.addresses',
'ipv6.addresses',
'ipv4.dns',
'ipv4.dns-search',
'ipv4.routes',
@@ -1786,13 +1848,15 @@ def main():
method4=dict(type='str', choices=['auto', 'link-local', 'manual', 'shared', 'disabled']),
may_fail4=dict(type='bool', default=True),
dhcp_client_id=dict(type='str'),
ip6=dict(type='str'),
ip6=dict(type='list', elements='str'),
gw6=dict(type='str'),
gw6_ignore_auto=dict(type='bool', default=False),
dns6=dict(type='list', elements='str'),
dns6_search=dict(type='list', elements='str'),
dns6_ignore_auto=dict(type='bool', default=False),
method6=dict(type='str', choices=['ignore', 'auto', 'dhcp', 'link-local', 'manual', 'shared', 'disabled']),
ip_privacy6=dict(type='str', choices=['disabled', 'prefer-public-addr', 'prefer-temp-addr', 'unknown']),
addr_gen_mode6=dict(type='str', choices=['eui64', 'stable-privacy']),
# Bond Specific vars
mode=dict(type='str', default='balance-rr',
choices=['802.3ad', 'active-backup', 'balance-alb', 'balance-rr', 'balance-tlb', 'balance-xor', 'broadcast']),

View File

@@ -127,7 +127,7 @@ ansible_sysname:
type: str
sample: ubuntu-user
ansible_syslocation:
description: The physical location of this node (e.g., `telephone closet, 3rd floor').
description: The physical location of this node (e.g., C(telephone closet, 3rd floor)).
returned: success
type: str
sample: Sitting on the Dock of the Bay

View File

@@ -10,7 +10,7 @@ __metaclass__ = type
DOCUMENTATION = """
module: ansible_galaxy_install
author:
- "Alexei Znamensky (@russoz)"
- "Alexei Znamensky (@russoz)"
short_description: Install Ansible roles or collections using ansible-galaxy
version_added: 3.5.0
description:
@@ -24,44 +24,46 @@ requirements:
options:
type:
description:
- The type of installation performed by C(ansible-galaxy).
- If I(type) is C(both), then I(requirements_file) must be passed and it may contain both roles and collections.
- "Note however that the opposite is not true: if using a I(requirements_file), then I(type) can be any of the three choices."
- "B(Ansible 2.9): The option C(both) will have the same effect as C(role)."
- The type of installation performed by C(ansible-galaxy).
- If I(type) is C(both), then I(requirements_file) must be passed and it may contain both roles and collections.
- "Note however that the opposite is not true: if using a I(requirements_file), then I(type) can be any of the three choices."
- "B(Ansible 2.9): The option C(both) will have the same effect as C(role)."
type: str
choices: [collection, role, both]
required: true
name:
description:
- Name of the collection or role being installed.
- Versions can be specified with C(ansible-galaxy) usual formats. For example, C(community.docker:1.6.1) or C(ansistrano.deploy,3.8.0).
- I(name) and I(requirements_file) are mutually exclusive.
- Name of the collection or role being installed.
- >
Versions can be specified with C(ansible-galaxy) usual formats.
For example, the collection C(community.docker:1.6.1) or the role C(ansistrano.deploy,3.8.0).
- I(name) and I(requirements_file) are mutually exclusive.
type: str
requirements_file:
description:
- Path to a file containing a list of requirements to be installed.
- It works for I(type) equals to C(collection) and C(role).
- I(name) and I(requirements_file) are mutually exclusive.
- "B(Ansible 2.9): It can only be used to install either I(type=role) or I(type=collection), but not both at the same run."
- Path to a file containing a list of requirements to be installed.
- It works for I(type) equals to C(collection) and C(role).
- I(name) and I(requirements_file) are mutually exclusive.
- "B(Ansible 2.9): It can only be used to install either I(type=role) or I(type=collection), but not both at the same run."
type: path
dest:
description:
- The path to the directory containing your collections or roles, according to the value of I(type).
- >
Please notice that C(ansible-galaxy) will not install collections with I(type=both), when I(requirements_file)
contains both roles and collections and I(dest) is specified.
- The path to the directory containing your collections or roles, according to the value of I(type).
- >
Please notice that C(ansible-galaxy) will not install collections with I(type=both), when I(requirements_file)
contains both roles and collections and I(dest) is specified.
type: path
force:
description:
- Force overwriting an existing role or collection.
- Using I(force=true) is mandatory when downgrading.
- "B(Ansible 2.9 and 2.10): Must be C(true) to upgrade roles and collections."
- Force overwriting an existing role or collection.
- Using I(force=true) is mandatory when downgrading.
- "B(Ansible 2.9 and 2.10): Must be C(true) to upgrade roles and collections."
type: bool
default: false
ack_ansible29:
description:
- Acknowledge using Ansible 2.9 with its limitations, and prevents the module from generating warnings about them.
- This option is completely ignored if using a version Ansible greater than C(2.9.x).
- Acknowledge using Ansible 2.9 with its limitations, and prevents the module from generating warnings about them.
- This option is completely ignored if using a version of Ansible greater than C(2.9.x).
type: bool
default: false
"""
@@ -114,9 +116,9 @@ RETURN = """
returned: always
installed_roles:
description:
- If I(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
- If I(name) is specified, returns that role name and the version installed per path.
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
- If I(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
- If I(name) is specified, returns that role name and the version installed per path.
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
type: dict
returned: always when installing roles
contains:
@@ -131,9 +133,9 @@ RETURN = """
ansistrano.deploy: 3.8.0
installed_collections:
description:
- If I(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
- If I(name) is specified, returns that collection name and the version installed per path.
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
- If I(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
- If I(name) is specified, returns that collection name and the version installed per path.
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
type: dict
returned: always when installing collections
contains:

View File

@@ -167,7 +167,7 @@ class PipX(CmdStateModuleHelper):
command_args_formats = dict(
state=dict(fmt=lambda v: [_state_map.get(v, v)]),
name_source=dict(fmt=lambda n, s: [s] if s else [n], stars=1),
install_deps=dict(fmt="--install-deps", style=ArgFormat.BOOLEAN),
install_deps=dict(fmt="--include-deps", style=ArgFormat.BOOLEAN),
inject_packages=dict(fmt=lambda v: v),
force=dict(fmt="--force", style=ArgFormat.BOOLEAN),
include_injected=dict(fmt="--include-injected", style=ArgFormat.BOOLEAN),

View File

@@ -69,12 +69,13 @@ EXAMPLES = r'''
executable: /opt/hp/tools/hponcfg
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.module_helper import (
CmdModuleHelper, ArgFormat
)
def main():
module = AnsibleModule(
class HPOnCfg(CmdModuleHelper):
module = dict(
argument_spec=dict(
src=dict(type='path', required=True, aliases=['path']),
minfw=dict(type='str'),
@@ -82,29 +83,24 @@ def main():
verbose=dict(default=False, type='bool'),
)
)
command_args_formats = dict(
src=dict(fmt=["-f", "{0}"]),
verbose=dict(fmt="-v", style=ArgFormat.BOOLEAN),
minfw=dict(fmt=["-m", "{0}"]),
)
check_rc = True
# Consider every action a change (not idempotent yet!)
changed = True
def __init_module__(self):
self.command = self.vars.executable
# Consider every action a change (not idempotent yet!)
self.changed = True
src = module.params['src']
minfw = module.params['minfw']
executable = module.params['executable']
verbose = module.params['verbose']
def __run__(self):
self.run_command(params=['src', 'verbose', 'minfw'])
options = ' -f %s' % src
if verbose:
options += ' -v'
if minfw:
options += ' -m %s' % minfw
rc, stdout, stderr = module.run_command('%s %s' % (executable, options))
if rc != 0:
module.fail_json(rc=rc, msg="Failed to run hponcfg", stdout=stdout, stderr=stderr)
module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
def main():
HPOnCfg.execute()
if __name__ == '__main__':

View File

@@ -0,0 +1,175 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ilo_redfish_config
short_description: Sets or updates configuration attributes on HPE iLO with Redfish OEM extensions
version_added: 4.2.0
description:
- Builds Redfish URIs locally and sends them to iLO to
set or update a configuration attribute.
- For use with HPE iLO operations that require Redfish OEM extensions.
options:
category:
required: true
type: str
description:
- Command category to execute on iLO.
choices: ['Manager']
command:
required: true
description:
- List of commands to execute on iLO.
type: list
elements: str
baseuri:
required: true
description:
- Base URI of iLO.
type: str
username:
description:
- User for authentication with iLO.
type: str
password:
description:
- Password for authentication with iLO.
type: str
auth_token:
description:
- Security token for authentication with OOB controller.
type: str
timeout:
description:
- Timeout in seconds for URL requests to iLO controller.
default: 10
type: int
attribute_name:
required: true
description:
- Name of the attribute to be configured.
type: str
attribute_value:
required: false
description:
- Value of the attribute to be configured.
type: str
author:
- "Bhavya B (@bhavya06)"
'''
EXAMPLES = '''
- name: Disable WINS Registration
community.general.ilo_redfish_config:
category: Manager
command: SetWINSReg
baseuri: 15.X.X.X
username: Admin
password: Testpass123
attribute_name: WINSRegistration
- name: Set Time Zone
community.general.ilo_redfish_config:
category: Manager
command: SetTimeZone
baseuri: 15.X.X.X
username: Admin
password: Testpass123
attribute_name: TimeZone
attribute_value: Chennai
'''
RETURN = '''
msg:
description: Message with action result or error description
returned: always
type: str
sample: "Action was successful"
'''
CATEGORY_COMMANDS_ALL = {
"Manager": ["SetTimeZone", "SetDNSserver", "SetDomainName", "SetNTPServers", "SetWINSReg"]
}
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
def main():
result = {}
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True, choices=list(
CATEGORY_COMMANDS_ALL.keys())),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
attribute_name=dict(required=True),
attribute_value=dict(),
timeout=dict(type='int', default=10)
),
required_together=[
('username', 'password'),
],
required_one_of=[
('username', 'auth_token'),
],
mutually_exclusive=[
('username', 'auth_token'),
],
supports_check_mode=False
)
category = module.params['category']
command_list = module.params['command']
creds = {"user": module.params['username'],
"pswd": module.params['password'],
"token": module.params['auth_token']}
timeout = module.params['timeout']
root_uri = "https://" + module.params['baseuri']
rf_utils = iLORedfishUtils(creds, root_uri, timeout, module)
mgr_attributes = {'mgr_attr_name': module.params['attribute_name'],
'mgr_attr_value': module.params['attribute_value']}
changed = False
offending = [
cmd for cmd in command_list if cmd not in CATEGORY_COMMANDS_ALL[category]]
if offending:
module.fail_json(msg=to_native("Invalid Command(s): '%s'. Allowed Commands = %s" % (
offending, CATEGORY_COMMANDS_ALL[category])))
if category == "Manager":
resource = rf_utils._find_managers_resource()
if not resource['ret']:
module.fail_json(msg=to_native(resource['msg']))
dispatch = dict(
SetTimeZone=rf_utils.set_time_zone,
SetDNSserver=rf_utils.set_dns_server,
SetDomainName=rf_utils.set_domain_name,
SetNTPServers=rf_utils.set_ntp_server,
SetWINSReg=rf_utils.set_wins_registration
)
for command in command_list:
result[command] = dispatch[command](mgr_attributes)
if 'changed' in result[command]:
changed |= result[command]['changed']
module.exit_json(ilo_redfish_config=result, changed=changed)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,186 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: ilo_redfish_info
short_description: Gathers server information through iLO using Redfish APIs
version_added: 4.2.0
description:
- Builds Redfish URIs locally and sends them to iLO to
get information back.
- For use with HPE iLO operations that require Redfish OEM extensions.
options:
category:
required: true
description:
- List of categories to execute on iLO.
type: list
elements: str
command:
required: true
description:
- List of commands to execute on iLO.
type: list
elements: str
baseuri:
required: true
description:
- Base URI of iLO.
type: str
username:
description:
- User for authentication with iLO.
type: str
password:
description:
- Password for authentication with iLO.
type: str
auth_token:
description:
- Security token for authentication with iLO.
type: str
timeout:
description:
- Timeout in seconds for URL requests to iLO.
default: 10
type: int
author:
- "Bhavya B (@bhavya06)"
'''
EXAMPLES = '''
- name: Get iLO Sessions
community.general.ilo_redfish_info:
category: Sessions
command: GetiLOSessions
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
register: result_sessions
'''
RETURN = '''
ilo_redfish_info:
description: Returns iLO sessions.
type: dict
contains:
GetiLOSessions:
description: Returns the iLO session msg and whether the function executed successfully.
type: dict
contains:
ret:
description: Check variable to see if the information was succesfully retrived.
type: bool
msg:
description: Information of all active iLO sessions.
type: list
elements: dict
contains:
Description:
description: Provides a description of the resource.
type: str
Id:
description: The sessionId.
type: str
Name:
description: The name of the resource.
type: str
UserName:
description: Name to use to log in to the management processor.
type: str
returned: always
'''
CATEGORY_COMMANDS_ALL = {
"Sessions": ["GetiLOSessions"]
}
CATEGORY_COMMANDS_DEFAULT = {
"Sessions": "GetiLOSessions"
}
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
def main():
result = {}
category_list = []
module = AnsibleModule(
argument_spec=dict(
category=dict(required=True, type='list', elements='str'),
command=dict(required=True, type='list', elements='str'),
baseuri=dict(required=True),
username=dict(),
password=dict(no_log=True),
auth_token=dict(no_log=True),
timeout=dict(type='int', default=10)
),
required_together=[
('username', 'password'),
],
required_one_of=[
('username', 'auth_token'),
],
mutually_exclusive=[
('username', 'auth_token'),
],
supports_check_mode=True
)
creds = {"user": module.params['username'],
"pswd": module.params['password'],
"token": module.params['auth_token']}
timeout = module.params['timeout']
root_uri = "https://" + module.params['baseuri']
rf_utils = iLORedfishUtils(creds, root_uri, timeout, module)
# Build Category list
if "all" in module.params['category']:
for entry in CATEGORY_COMMANDS_ALL:
category_list.append(entry)
else:
# one or more categories specified
category_list = module.params['category']
for category in category_list:
command_list = []
# Build Command list for each Category
if category in CATEGORY_COMMANDS_ALL:
if not module.params['command']:
# True if we don't specify a command --> use default
command_list.append(CATEGORY_COMMANDS_DEFAULT[category])
elif "all" in module.params['command']:
for entry in CATEGORY_COMMANDS_ALL[category]:
command_list.append(entry)
# one or more commands
else:
command_list = module.params['command']
# Verify that all commands are valid
for cmd in command_list:
# Fail if even one command given is invalid
if cmd not in CATEGORY_COMMANDS_ALL[category]:
module.fail_json(msg="Invalid Command: %s" % cmd)
else:
# Fail if even one category given is invalid
module.fail_json(msg="Invalid Category: %s" % category)
# Organize by Categories / Commands
if category == "Sessions":
for command in command_list:
if command == "GetiLOSessions":
result[command] = rf_utils.get_ilo_sessions()
module.exit_json(ilo_redfish_info=result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,184 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Werner Dijkerman (ikben@werner-dijkerman.nl)
# 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: gitlab_branch
short_description: Create or delete a branch
version_added: 4.2.0
description:
- This module allows to create or delete branches.
author:
- paytroff (@paytroff)
requirements:
- python >= 2.7
- python-gitlab >= 2.3.0
extends_documentation_fragment:
- community.general.auth_basic
- community.general.gitlab
options:
state:
description:
- Create or delete branch.
default: present
type: str
choices: ["present", "absent"]
project:
description:
- The path or name of the project.
required: true
type: str
branch:
description:
- The name of the branch that needs to be created.
required: true
type: str
ref_branch:
description:
- Reference branch to create from.
- This must be specified if I(state=present).
type: str
'''
EXAMPLES = '''
- name: Create branch branch2 from main
community.general.gitlab_branch:
api_url: https://gitlab.com
api_token: secret_access_token
project: "group1/project1"
branch: branch2
ref_branch: main
state: present
- name: Delete branch branch2
community.general.gitlab_branch:
api_url: https://gitlab.com
api_token: secret_access_token
project: "group1/project1"
branch: branch2
state: absent
'''
RETURN = '''
'''
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.api import basic_auth_argument_spec
from distutils.version import LooseVersion
GITLAB_IMP_ERR = None
try:
import gitlab
HAS_GITLAB_PACKAGE = True
except Exception:
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
class GitlabBranch(object):
def __init__(self, module, project, gitlab_instance):
self.repo = gitlab_instance
self._module = module
self.project = self.get_project(project)
def get_project(self, project):
try:
return self.repo.projects.get(project)
except Exception as e:
return False
def get_branch(self, branch):
try:
return self.project.branches.get(branch)
except Exception as e:
return False
def create_branch(self, branch, ref_branch):
return self.project.branches.create({'branch': branch, 'ref': ref_branch})
def delete_branch(self, branch):
branch.unprotect()
return branch.delete()
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(
project=dict(type='str', required=True),
branch=dict(type='str', required=True),
ref_branch=dict(type='str', required=False),
state=dict(type='str', default="present", choices=["absent", "present"]),
)
module = AnsibleModule(
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
required_if=[
['state', 'present', ['ref_branch'], True],
],
supports_check_mode=False
)
project = module.params['project']
branch = module.params['branch']
ref_branch = module.params['ref_branch']
state = module.params['state']
if not HAS_GITLAB_PACKAGE:
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
gitlab_version = gitlab.__version__
if LooseVersion(gitlab_version) < LooseVersion('2.3.0'):
module.fail_json(msg="community.general.gitlab_proteched_branch requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
gitlab_instance = gitlab_authentication(module)
this_gitlab = GitlabBranch(module=module, project=project, gitlab_instance=gitlab_instance)
this_branch = this_gitlab.get_branch(branch)
if not this_branch and state == "present":
r_branch = this_gitlab.get_branch(ref_branch)
if not r_branch:
module.fail_json(msg="Ref branch {b} not exist.".format(b=ref_branch))
this_gitlab.create_branch(branch, ref_branch)
module.exit_json(changed=True, msg="Created the branch {b}.".format(b=branch))
elif this_branch and state == "present":
module.exit_json(changed=False, msg="Branch {b} already exist".format(b=branch))
elif this_branch and state == "absent":
try:
this_gitlab.delete_branch(this_branch)
module.exit_json(changed=True, msg="Branch {b} deleted.".format(b=branch))
except Exception as e:
module.fail_json(msg="Error delete branch.", exception=traceback.format_exc())
else:
module.exit_json(changed=False, msg="No changes are needed.")
if __name__ == '__main__':
main()

View File

@@ -14,7 +14,7 @@ DOCUMENTATION = '''
module: gitlab_deploy_key
short_description: Manages GitLab project deploy keys.
description:
- Adds, updates and removes project deploy keys
- Adds, updates and removes project deploy keys
author:
- Marcus Watkins (@marwatk)
- Guillaume Martinez (@Lunik)
@@ -22,13 +22,10 @@ requirements:
- python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- GitLab token for logging in.
type: str
project:
description:
- Id or Full path of project in the form of group/name.
@@ -126,7 +123,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import find_project, gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_project, gitlab_authentication
class GitLabDeployKey(object):
@@ -238,8 +235,8 @@ class GitLabDeployKey(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
state=dict(type='str', default="present", choices=["absent", "present"]),
project=dict(type='str', required=True),
key=dict(type='str', required=True, no_log=False),
@@ -251,13 +248,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token']
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password']
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True,
)

View File

@@ -22,13 +22,10 @@ requirements:
- python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- GitLab token for logging in.
type: str
name:
description:
- Name of the group you want to create.
@@ -83,6 +80,12 @@ options:
- Require all users in this group to setup two-factor authentication.
type: bool
version_added: 3.7.0
avatar_path:
description:
- Absolute path image to configure avatar. File size should not exceed 200 kb.
- This option is only used on creation, not for updates.
type: path
version_added: 4.2.0
'''
EXAMPLES = '''
@@ -169,7 +172,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, gitlab_authentication
class GitLabGroup(object):
@@ -212,6 +215,13 @@ class GitLabGroup(object):
if options.get('require_two_factor_authentication'):
payload['require_two_factor_authentication'] = options['require_two_factor_authentication']
group = self.create_group(payload)
# add avatar to group
if options['avatar_path']:
try:
group.avatar = open(options['avatar_path'], 'rb')
except IOError as e:
self._module.fail_json(msg='Cannot open {0}: {1}'.format(options['avatar_path'], e))
changed = True
else:
changed, group = self.update_group(self.group_object, {
@@ -296,8 +306,8 @@ class GitLabGroup(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
name=dict(type='str', required=True),
path=dict(type='str'),
description=dict(type='str'),
@@ -308,19 +318,23 @@ def main():
auto_devops_enabled=dict(type='bool'),
subgroup_creation_level=dict(type='str', choices=['maintainer', 'owner']),
require_two_factor_authentication=dict(type='bool'),
avatar_path=dict(type='path'),
))
module = AnsibleModule(
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True,
)
@@ -335,6 +349,7 @@ def main():
auto_devops_enabled = module.params['auto_devops_enabled']
subgroup_creation_level = module.params['subgroup_creation_level']
require_two_factor_authentication = module.params['require_two_factor_authentication']
avatar_path = module.params['avatar_path']
if not HAS_GITLAB_PACKAGE:
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
@@ -373,6 +388,7 @@ def main():
"auto_devops_enabled": auto_devops_enabled,
"subgroup_creation_level": subgroup_creation_level,
"require_two_factor_authentication": require_two_factor_authentication,
"avatar_path": avatar_path,
}):
module.exit_json(changed=True, msg="Successfully created or updated the group %s" % group_name, group=gitlab_group.group_object._attrs)
else:

View File

@@ -12,78 +12,76 @@ DOCUMENTATION = r'''
module: gitlab_group_members
short_description: Manage group members on GitLab Server
description:
- This module allows to add and remove members to/from a group, or change a member's access level in a group on GitLab.
- This module allows to add and remove members to/from a group, or change a member's access level in a group on GitLab.
version_added: '1.2.0'
author: Zainab Alsaffar (@zanssa)
requirements:
- python-gitlab python module <= 1.15.0
- administrator rights on the GitLab server
extends_documentation_fragment: community.general.auth_basic
- python-gitlab python module <= 1.15.0
- administrator rights on the GitLab server
extends_documentation_fragment:
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- A personal access token to authenticate with the GitLab API.
required: true
gitlab_group:
description:
- The C(full_path) of the GitLab group the member is added to/removed from.
- Setting this to C(name) or C(path) is deprecated and will be removed in community.general 6.0.0. Use C(full_path) instead.
required: true
type: str
gitlab_user:
description:
- A username or a list of usernames to add to/remove from the GitLab group.
- Mutually exclusive with I(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
- Mutually exclusive with I(gitlab_users_access).
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- Mutually exclusive with I(gitlab_user) and I(access_level).
- Use together with I(purge_users) to remove all users not specified here from the group.
type: list
elements: dict
suboptions:
name:
description: A username or a list of usernames to add to/remove from the GitLab group.
type: str
gitlab_group:
description:
- The C(full_path) of the GitLab group the member is added to/removed from.
- Setting this to C(name) or C(path) is deprecated and will be removed in community.general 6.0.0. Use C(full_path) instead.
required: true
type: str
gitlab_user:
access_level:
description:
- A username or a list of usernames to add to/remove from the GitLab group.
- Mutually exclusive with I(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
- Mutually exclusive with I(gitlab_users_access).
- The access level for the user.
- Required if I(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- Mutually exclusive with I(gitlab_user) and I(access_level).
- Use together with I(purge_users) to remove all users not specified here from the group.
type: list
elements: dict
suboptions:
name:
description: A username or a list of usernames to add to/remove from the GitLab group.
type: str
required: true
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
required: true
version_added: 3.6.0
state:
description:
- State of the member in the group.
- On C(present), it adds a user to a GitLab group.
- On C(absent), it removes a user from a GitLab group.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
If omitted do not purge orphaned members.
- Is only used when I(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
version_added: 3.6.0
required: true
version_added: 3.6.0
state:
description:
- State of the member in the group.
- On C(present), it adds a user to a GitLab group.
- On C(absent), it removes a user from a GitLab group.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
If omitted do not purge orphaned members.
- Is only used when I(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
version_added: 3.6.0
notes:
- Supports C(check_mode).
- Supports C(check_mode).
'''
EXAMPLES = r'''
@@ -155,7 +153,7 @@ RETURN = r''' # '''
from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
import traceback
@@ -241,8 +239,8 @@ class GitLabGroup(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', required=True, no_log=True),
gitlab_group=dict(type='str', required=True),
gitlab_user=dict(type='list', elements='str'),
state=dict(type='str', default='present', choices=['present', 'absent']),
@@ -262,16 +260,19 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['gitlab_user', 'gitlab_users_access'],
['access_level', 'gitlab_users_access'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
['gitlab_user', 'access_level'],
],
required_one_of=[
['api_username', 'api_token'],
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
['gitlab_user', 'gitlab_users_access'],
],
required_if=[

View File

@@ -24,6 +24,7 @@ requirements:
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.gitlab
options:
state:
@@ -32,11 +33,6 @@ options:
default: present
type: str
choices: ["present", "absent"]
api_token:
description:
- GitLab access token with API permissions.
required: true
type: str
group:
description:
- The path and name of the group.
@@ -144,7 +140,7 @@ except Exception:
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
class GitlabGroupVariables(object):
@@ -268,8 +264,8 @@ def native_python_main(this_gitlab, purge, var_list, state, module):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(
api_token=dict(type='str', required=True, no_log=True),
group=dict(type='str', required=True),
purge=dict(type='bool', required=False, default=False),
vars=dict(type='dict', required=False, default=dict(), no_log=True),
@@ -280,13 +276,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True
)

View File

@@ -15,7 +15,7 @@ DOCUMENTATION = '''
module: gitlab_hook
short_description: Manages GitLab project hooks.
description:
- Adds, updates and removes project hook
- Adds, updates and removes project hook
author:
- Marcus Watkins (@marwatk)
- Guillaume Martinez (@Lunik)
@@ -23,13 +23,10 @@ requirements:
- python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- GitLab token for logging in.
type: str
project:
description:
- Id or Full path of the project in the form of group/name.
@@ -176,7 +173,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import find_project, gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_project, gitlab_authentication
class GitLabHook(object):
@@ -297,8 +294,8 @@ class GitLabHook(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
state=dict(type='str', default="present", choices=["absent", "present"]),
project=dict(type='str', required=True),
hook_url=dict(type='str', required=True),
@@ -319,13 +316,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token']
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password']
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True,
)

View File

@@ -23,13 +23,10 @@ requirements:
- python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- GitLab token for logging in.
type: str
group:
description:
- Id or the full path of the group of which this projects belongs to.
@@ -162,6 +159,18 @@ options:
- Enable shared runners for this project.
type: bool
version_added: "3.7.0"
avatar_path:
description:
- Absolute path image to configure avatar. File size should not exceed 200 kb.
- This option is only used on creation, not for updates.
type: path
version_added: "4.2.0"
default_branch:
description:
- Default branch name for a new project.
- This option is only used on creation, not for updates. This is also only used if I(initialize_with_readme=true).
type: str
version_added: "4.2.0"
'''
EXAMPLES = r'''
@@ -197,6 +206,19 @@ EXAMPLES = r'''
initialize_with_readme: true
state: present
delegate_to: localhost
- name: get the initial root password
ansible.builtin.shell: |
grep 'Password:' /etc/gitlab/initial_root_password | sed -e 's/Password\: \(.*\)/\1/'
register: initial_root_password
- name: Create a GitLab Project using a username/password via oauth_token
community.general.gitlab_project:
api_url: https://gitlab.example.com/
api_username: root
api_password: "{{ initial_root_password }}"
name: my_second_project
group: "10481470"
'''
RETURN = r'''
@@ -237,7 +259,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, find_project, gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, find_project, gitlab_authentication
class GitLabProject(object):
@@ -280,8 +302,19 @@ class GitLabProject(object):
})
if options['initialize_with_readme']:
project_options['initialize_with_readme'] = options['initialize_with_readme']
if options['default_branch']:
project_options['default_branch'] = options['default_branch']
project_options = self.get_options_with_value(project_options)
project = self.create_project(namespace, project_options)
# add avatar to project
if options['avatar_path']:
try:
project.avatar = open(options['avatar_path'], 'rb')
except IOError as e:
self._module.fail_json(msg='Cannot open {0}: {1}'.format(options['avatar_path'], e))
changed = True
else:
changed, project = self.update_project(self.project_object, project_options)
@@ -363,13 +396,14 @@ class GitLabProject(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
group=dict(type='str'),
name=dict(type='str', required=True),
path=dict(type='str'),
description=dict(type='str'),
initialize_with_readme=dict(type='bool', default=False),
default_branch=dict(type='str'),
issues_enabled=dict(type='bool', default=True),
merge_requests_enabled=dict(type='bool', default=True),
merge_method=dict(type='str', default='merge', choices=["merge", "rebase_merge", "ff"]),
@@ -388,20 +422,24 @@ def main():
squash_option=dict(type='str', choices=['never', 'always', 'default_off', 'default_on']),
ci_config_path=dict(type='str'),
shared_runners_enabled=dict(type='bool'),
avatar_path=dict(type='path'),
))
module = AnsibleModule(
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
['group', 'username'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True,
)
@@ -429,6 +467,11 @@ def main():
squash_option = module.params['squash_option']
ci_config_path = module.params['ci_config_path']
shared_runners_enabled = module.params['shared_runners_enabled']
avatar_path = module.params['avatar_path']
default_branch = module.params['default_branch']
if default_branch and not initialize_with_readme:
module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
if not HAS_GITLAB_PACKAGE:
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
@@ -480,6 +523,7 @@ def main():
"path": project_path,
"description": project_description,
"initialize_with_readme": initialize_with_readme,
"default_branch": default_branch,
"issues_enabled": issues_enabled,
"merge_requests_enabled": merge_requests_enabled,
"merge_method": merge_method,
@@ -496,6 +540,7 @@ def main():
"squash_option": squash_option,
"ci_config_path": ci_config_path,
"shared_runners_enabled": shared_runners_enabled,
"avatar_path": avatar_path,
}):
module.exit_json(changed=True, msg="Successfully created or updated the project %s" % project_name, project=gitlab_project.project_object._attrs)

View File

@@ -14,95 +14,75 @@ module: gitlab_project_members
short_description: Manage project members on GitLab Server
version_added: 2.2.0
description:
- This module allows to add and remove members to/from a project, or change a member's access level in a project on GitLab.
- This module allows to add and remove members to/from a project, or change a member's access level in a project on GitLab.
author:
- Sergey Mikhaltsov (@metanovii)
- Zainab Alsaffar (@zanssa)
- Sergey Mikhaltsov (@metanovii)
- Zainab Alsaffar (@zanssa)
requirements:
- python-gitlab python module <= 1.15.0
- owner or maintainer rights to project on the GitLab server
- python-gitlab python module <= 1.15.0
- owner or maintainer rights to project on the GitLab server
extends_documentation_fragment:
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- A personal access token to authenticate with the GitLab API.
project:
description:
- The name (or full path) of the GitLab project the member is added to/removed from.
required: true
type: str
gitlab_user:
description:
- A username or a list of usernames to add to/remove from the GitLab project.
- Mutually exclusive with I(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- Mutually exclusive with I(gitlab_user) and I(access_level).
- Use together with I(purge_users) to remove all users not specified here from the project.
type: list
elements: dict
suboptions:
name:
description: A username or a list of usernames to add to/remove from the GitLab project.
type: str
required: true
type: str
validate_certs:
access_level:
description:
- Whether or not to validate TLS/SSL certificates when supplying a HTTPS endpoint.
- Should only be set to C(false) if you can guarantee that you are talking to the correct server
and no man-in-the-middle attack can happen.
default: true
type: bool
api_username:
description:
- The username to use for authentication against the API.
type: str
api_password:
description:
- The password to use for authentication against the API.
type: str
api_url:
description:
- The resolvable endpoint for the API.
type: str
project:
description:
- The name (or full path) of the GitLab project the member is added to/removed from.
required: true
type: str
gitlab_user:
description:
- A username or a list of usernames to add to/remove from the GitLab project.
- Mutually exclusive with I(gitlab_users_access).
type: list
elements: str
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
- The access level for the user.
- Required if I(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
gitlab_users_access:
description:
- Provide a list of user to access level mappings.
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
- Mutually exclusive with I(gitlab_user) and I(access_level).
- Use together with I(purge_users) to remove all users not specified here from the project.
type: list
elements: dict
suboptions:
name:
description: A username or a list of usernames to add to/remove from the GitLab project.
type: str
required: true
access_level:
description:
- The access level for the user.
- Required if I(state=present), user state is set to present.
type: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
required: true
version_added: 3.7.0
state:
description:
- State of the member in the project.
- On C(present), it adds a user to a GitLab project.
- On C(absent), it removes a user from a GitLab project.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
If omitted do not purge orphaned members.
- Is only used when I(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
version_added: 3.7.0
required: true
version_added: 3.7.0
state:
description:
- State of the member in the project.
- On C(present), it adds a user to a GitLab project.
- On C(absent), it removes a user from a GitLab project.
choices: ['present', 'absent']
default: 'present'
type: str
purge_users:
description:
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
If omitted do not purge orphaned members.
- Is only used when I(state=present).
type: list
elements: str
choices: ['guest', 'reporter', 'developer', 'maintainer']
version_added: 3.7.0
notes:
- Supports C(check_mode).
- Supports C(check_mode).
'''
EXAMPLES = r'''
@@ -176,7 +156,7 @@ RETURN = r''' # '''
from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
import traceback
@@ -257,8 +237,8 @@ class GitLabProjectMembers(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', required=True, no_log=True),
project=dict(type='str', required=True),
gitlab_user=dict(type='list', elements='str'),
state=dict(type='str', default='present', choices=['present', 'absent']),
@@ -280,7 +260,10 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
['gitlab_user', 'gitlab_users_access'],
['access_level', 'gitlab_users_access'],
],
@@ -289,7 +272,7 @@ def main():
['gitlab_user', 'access_level'],
],
required_one_of=[
['api_username', 'api_token'],
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
['gitlab_user', 'gitlab_users_access'],
],
required_if=[

View File

@@ -20,7 +20,8 @@ requirements:
- python >= 2.7
- python-gitlab python module
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
state:
@@ -30,11 +31,6 @@ options:
default: present
type: str
choices: ["present", "absent"]
api_token:
description:
- GitLab access token with API permissions.
required: true
type: str
project:
description:
- The path and name of the project.
@@ -143,7 +139,7 @@ except Exception:
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
class GitlabProjectVariables(object):
@@ -270,8 +266,8 @@ def native_python_main(this_gitlab, purge, var_list, state, module):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(
api_token=dict(type='str', required=True, no_log=True),
project=dict(type='str', required=True),
purge=dict(type='bool', required=False, default=False),
vars=dict(type='dict', required=False, default=dict(), no_log=True),
@@ -282,13 +278,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True
)

View File

@@ -18,7 +18,8 @@ requirements:
- python >= 2.7
- python-gitlab >= 2.3.0
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
state:
@@ -27,11 +28,6 @@ options:
default: present
type: str
choices: ["present", "absent"]
api_token:
description:
- GitLab access token with API permissions.
required: true
type: str
project:
description:
- The path and name of the project.
@@ -87,7 +83,7 @@ except Exception:
GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
class GitlabProtectedBranch(object):
@@ -141,8 +137,8 @@ class GitlabProtectedBranch(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(
api_token=dict(type='str', required=True, no_log=True),
project=dict(type='str', required=True),
name=dict(type='str', required=True),
merge_access_levels=dict(type='str', default="maintainer", choices=["maintainer", "developer", "nobody"]),
@@ -154,13 +150,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True
)

View File

@@ -32,13 +32,10 @@ requirements:
- python >= 2.7
- python-gitlab >= 1.5.0
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- Your private token to interact with the GitLab API.
type: str
project:
description:
- ID or full path of the project in the form of group/name.
@@ -186,7 +183,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
try:
cmp
@@ -323,8 +320,8 @@ class GitLabRunner(object):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
description=dict(type='str', required=True, aliases=["name"]),
active=dict(type='bool', default=True),
owned=dict(type='bool', default=False),
@@ -342,13 +339,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token'],
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
],
required_if=[
('state', 'present', ['registration_token']),

View File

@@ -30,13 +30,10 @@ requirements:
- python-gitlab python module
- administrator rights on the GitLab server
extends_documentation_fragment:
- community.general.auth_basic
- community.general.auth_basic
- community.general.gitlab
options:
api_token:
description:
- GitLab token for logging in.
type: str
name:
description:
- Name of the user you want to create.
@@ -238,7 +235,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, gitlab_authentication
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, gitlab_authentication
class GitLabUser(object):
@@ -579,8 +576,8 @@ def sanitize_arguments(arguments):
def main():
argument_spec = basic_auth_argument_spec()
argument_spec.update(auth_argument_spec())
argument_spec.update(dict(
api_token=dict(type='str', no_log=True),
name=dict(type='str'),
state=dict(type='str', default="present", choices=["absent", "present", "blocked", "unblocked"]),
username=dict(type='str', required=True),
@@ -603,13 +600,16 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
['api_username', 'api_token'],
['api_password', 'api_token'],
['api_username', 'api_oauth_token'],
['api_username', 'api_job_token'],
['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'],
],
required_together=[
['api_username', 'api_password'],
],
required_one_of=[
['api_username', 'api_token']
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
],
supports_check_mode=True,
required_if=(

View File

@@ -183,7 +183,7 @@ def _fs_exists(module, filesystem):
:return: True or False.
"""
lsfs_cmd = module.get_bin_path('lsfs', True)
rc, lsfs_out, err = module.run_command("%s -l %s" % (lsfs_cmd, filesystem))
rc, lsfs_out, err = module.run_command([lsfs_cmd, "-l", filesystem])
if rc == 1:
if re.findall("No record matching", err):
return False
@@ -206,8 +206,7 @@ def _check_nfs_device(module, nfs_host, device):
:return: True or False.
"""
showmount_cmd = module.get_bin_path('showmount', True)
rc, showmount_out, err = module.run_command(
"%s -a %s" % (showmount_cmd, nfs_host))
rc, showmount_out, err = module.run_command([showmount_cmd, "-a", nfs_host])
if rc != 0:
module.fail_json(msg="Failed to run showmount. Error message: %s" % err)
else:
@@ -229,11 +228,11 @@ def _validate_vg(module, vg):
None (VG does not exist), message.
"""
lsvg_cmd = module.get_bin_path('lsvg', True)
rc, current_active_vgs, err = module.run_command("%s -o" % lsvg_cmd)
rc, current_active_vgs, err = module.run_command([lsvg_cmd, "-o"])
if rc != 0:
module.fail_json(msg="Failed executing %s command." % lsvg_cmd)
rc, current_all_vgs, err = module.run_command("%s" % lsvg_cmd)
rc, current_all_vgs, err = module.run_command([lsvg_cmd, "%s"])
if rc != 0:
module.fail_json(msg="Failed executing %s command." % lsvg_cmd)
@@ -253,7 +252,7 @@ def resize_fs(module, filesystem, size):
chfs_cmd = module.get_bin_path('chfs', True)
if not module.check_mode:
rc, chfs_out, err = module.run_command('%s -a size="%s" %s' % (chfs_cmd, size, filesystem))
rc, chfs_out, err = module.run_command([chfs_cmd, "-a", "size=%s" % size, filesystem])
if rc == 28:
changed = False
@@ -338,8 +337,7 @@ def create_fs(
# Creates a NFS file system.
mknfsmnt_cmd = module.get_bin_path('mknfsmnt', True)
if not module.check_mode:
rc, mknfsmnt_out, err = module.run_command('%s -f "%s" %s -h "%s" -t "%s" "%s" -w "bg"' % (
mknfsmnt_cmd, filesystem, device, nfs_server, permissions, auto_mount))
rc, mknfsmnt_out, err = module.run_command([mknfsmnt_cmd, "-f", filesystem, device, "-h", nfs_server, "-t", permissions, auto_mount, "-w", "bg"])
if rc != 0:
module.fail_json(msg="Failed to run mknfsmnt. Error message: %s" % err)
else:
@@ -357,8 +355,7 @@ def create_fs(
# Creates a LVM file system.
crfs_cmd = module.get_bin_path('crfs', True)
if not module.check_mode:
cmd = "%s -v %s -m %s %s %s %s %s %s -p %s %s -a %s" % (
crfs_cmd, fs_type, filesystem, vg, device, mount_group, auto_mount, account_subsystem, permissions, size, attributes)
cmd = [crfs_cmd, "-v", fs_type, "-m", filesystem, vg, device, mount_group, auto_mount, account_subsystem, "-p", permissions, size, "-a", attributes]
rc, crfs_out, err = module.run_command(cmd)
if rc == 10:
@@ -392,7 +389,7 @@ def remove_fs(module, filesystem, rm_mount_point):
rmfs_cmd = module.get_bin_path('rmfs', True)
if not module.check_mode:
cmd = "%s -r %s %s" % (rmfs_cmd, rm_mount_point, filesystem)
cmd = [rmfs_cmd, "-r", rm_mount_point, filesystem]
rc, rmfs_out, err = module.run_command(cmd)
if rc != 0:
module.fail_json(msg="Failed to run %s. Error message: %s" % (cmd, err))
@@ -415,8 +412,7 @@ def mount_fs(module, filesystem):
mount_cmd = module.get_bin_path('mount', True)
if not module.check_mode:
rc, mount_out, err = module.run_command(
"%s %s" % (mount_cmd, filesystem))
rc, mount_out, err = module.run_command([mount_cmd, filesystem])
if rc != 0:
module.fail_json(msg="Failed to run mount. Error message: %s" % err)
else:
@@ -436,7 +432,7 @@ def unmount_fs(module, filesystem):
unmount_cmd = module.get_bin_path('unmount', True)
if not module.check_mode:
rc, unmount_out, err = module.run_command("%s %s" % (unmount_cmd, filesystem))
rc, unmount_out, err = module.run_command([unmount_cmd, filesystem])
if rc != 0:
module.fail_json(msg="Failed to run unmount. Error message: %s" % err)
else:

View File

@@ -97,7 +97,7 @@ def _validate_pv(module, vg, pvs):
"""
lspv_cmd = module.get_bin_path('lspv', True)
rc, current_lspv, stderr = module.run_command("%s" % lspv_cmd)
rc, current_lspv, stderr = module.run_command([lspv_cmd])
if rc != 0:
module.fail_json(msg="Failed executing 'lspv' command.", rc=rc, stdout=current_lspv, stderr=stderr)
@@ -116,7 +116,7 @@ def _validate_pv(module, vg, pvs):
# Disk None, looks free.
# Check if PV is not already in use by Oracle ASM.
lquerypv_cmd = module.get_bin_path('lquerypv', True)
rc, current_lquerypv, stderr = module.run_command("%s -h /dev/%s 20 10" % (lquerypv_cmd, pv))
rc, current_lquerypv, stderr = module.run_command([lquerypv_cmd, "-h", "/dev/%s" % pv, "20", "10"])
if rc != 0:
module.fail_json(msg="Failed executing lquerypv command.", rc=rc, stdout=current_lquerypv, stderr=stderr)
@@ -144,11 +144,11 @@ def _validate_vg(module, vg):
None (VG does not exist), message.
"""
lsvg_cmd = module.get_bin_path('lsvg', True)
rc, current_active_vgs, err = module.run_command("%s -o" % lsvg_cmd)
rc, current_active_vgs, err = module.run_command([lsvg_cmd, "-o"])
if rc != 0:
module.fail_json(msg="Failed executing '%s' command." % lsvg_cmd)
rc, current_all_vgs, err = module.run_command("%s" % lsvg_cmd)
rc, current_all_vgs, err = module.run_command([lsvg_cmd])
if rc != 0:
module.fail_json(msg="Failed executing '%s' command." % lsvg_cmd)
@@ -197,7 +197,7 @@ def create_extend_vg(module, vg, pvs, pp_size, vg_type, force, vg_validation):
if not module.check_mode:
extendvg_cmd = module.get_bin_path('extendvg', True)
rc, output, err = module.run_command("%s %s %s" % (extendvg_cmd, vg, ' '.join(pvs)))
rc, output, err = module.run_command([extendvg_cmd, vg] + pvs)
if rc != 0:
changed = False
msg = "Extending volume group '%s' has failed." % vg
@@ -213,7 +213,7 @@ def create_extend_vg(module, vg, pvs, pp_size, vg_type, force, vg_validation):
if not module.check_mode:
mkvg_cmd = module.get_bin_path('mkvg', True)
rc, output, err = module.run_command("%s %s %s %s -y %s %s" % (mkvg_cmd, vg_opt[vg_type], pp_size, force_opt[force], vg, ' '.join(pvs)))
rc, output, err = module.run_command([mkvg_cmd, vg_opt[vg_type], pp_size, force_opt[force], "-y", vg] + pvs)
if rc != 0:
changed = False
msg = "Creating volume group '%s' failed." % vg
@@ -239,7 +239,7 @@ def reduce_vg(module, vg, pvs, vg_validation):
# Remove VG if pvs are note informed.
# Remark: AIX will permit remove only if the VG has not LVs.
lsvg_cmd = module.get_bin_path('lsvg', True)
rc, current_pvs, err = module.run_command("%s -p %s" % (lsvg_cmd, vg))
rc, current_pvs, err = module.run_command([lsvg_cmd, "-p", vg])
if rc != 0:
module.fail_json(msg="Failing to execute '%s' command." % lsvg_cmd)
@@ -263,7 +263,7 @@ def reduce_vg(module, vg, pvs, vg_validation):
if not module.check_mode:
reducevg_cmd = module.get_bin_path('reducevg', True)
rc, stdout, stderr = module.run_command("%s -df %s %s" % (reducevg_cmd, vg, ' '.join(pvs_to_remove)))
rc, stdout, stderr = module.run_command([reducevg_cmd, "-df", vg] + pvs_to_remove)
if rc != 0:
module.fail_json(msg="Unable to remove '%s'." % vg, rc=rc, stdout=stdout, stderr=stderr)
@@ -286,7 +286,7 @@ def state_vg(module, vg, state, vg_validation):
msg = ''
if not module.check_mode:
varyonvg_cmd = module.get_bin_path('varyonvg', True)
rc, varyonvg_out, err = module.run_command("%s %s" % (varyonvg_cmd, vg))
rc, varyonvg_out, err = module.run_command([varyonvg_cmd, vg])
if rc != 0:
module.fail_json(msg="Command 'varyonvg' failed.", rc=rc, err=err)
@@ -303,7 +303,7 @@ def state_vg(module, vg, state, vg_validation):
if not module.check_mode:
varyonvg_cmd = module.get_bin_path('varyoffvg', True)
rc, varyonvg_out, stderr = module.run_command("%s %s" % (varyonvg_cmd, vg))
rc, varyonvg_out, stderr = module.run_command([varyonvg_cmd, vg])
if rc != 0:
module.fail_json(msg="Command 'varyoffvg' failed.", rc=rc, stdout=varyonvg_out, stderr=stderr)

View File

@@ -253,7 +253,7 @@ def set_interface_option(module, lines, iface, option, raw_value, state, address
last_line_dict = iface_lines[-1]
return add_option_after_line(option, value, iface, lines, last_line_dict, iface_options, address_family)
if option in ["pre-up", "up", "down", "post-up"] and all(ito for ito in target_options if ito['value'] != value):
if option in ["pre-up", "up", "down", "post-up"] and all(ito['value'] != value for ito in target_options):
return add_option_after_line(option, value, iface, lines, target_options[-1], iface_options, address_family)
# if more than one option found edit the last one

View File

@@ -439,7 +439,7 @@ def delete_cert(module, executable, keystore_path, keystore_pass, alias, keystor
def test_keytool(module, executable):
''' Test if keytool is actually executable or not '''
module.run_command("%s" % executable, check_rc=True)
module.run_command([executable], check_rc=True)
def test_keystore(module, keystore_path):

View File

@@ -45,7 +45,7 @@ options:
required: false
type: bool
description:
- Enable or disable the service according to local preferences in *.preset files.
- Enable or disable the service according to local preferences in C(*.preset) files.
Mutually exclusive with I(enabled). Only has an effect if set to true. Will take
effect prior to I(state=reset).
user:

View File

@@ -10,8 +10,8 @@ DOCUMENTATION = '''
module: python_requirements_info
short_description: Show python path and assert dependency versions
description:
- Get info about available Python requirements on the target host, including listing required libraries and gathering versions.
- This module was called C(python_requirements_facts) before Ansible 2.9. The usage did not change.
- Get info about available Python requirements on the target host, including listing required libraries and gathering versions.
- This module was called C(python_requirements_facts) before Ansible 2.9. The usage did not change.
options:
dependencies:
type: list
@@ -21,9 +21,10 @@ options:
Supported operators: <, >, <=, >=, or ==. The bare module name like
I(ansible), the module with a specific version like I(boto3==1.6.1), or a
partial version like I(requests>2) are all valid specifications.
default: []
author:
- Will Thames (@willthames)
- Ryan Scott Brown (@ryansb)
- Will Thames (@willthames)
- Ryan Scott Brown (@ryansb)
'''
EXAMPLES = '''
@@ -33,8 +34,8 @@ EXAMPLES = '''
- name: Check for modern boto3 and botocore versions
community.general.python_requirements_info:
dependencies:
- boto3>1.6
- botocore<2
- boto3>1.6
- botocore<2
'''
RETURN = '''
@@ -48,14 +49,44 @@ python_version:
returned: always
type: str
sample: "2.7.15 (default, May 1 2018, 16:44:08)\n[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)]"
python_version_info:
description: breakdown version of python
returned: always
type: dict
contains:
major:
description: The C(major) component of the python interpreter version.
returned: always
type: int
sample: 3
minor:
description: The C(minor) component of the python interpreter version.
returned: always
type: int
sample: 8
micro:
description: The C(micro) component of the python interpreter version.
returned: always
type: int
sample: 10
releaselevel:
description: The C(releaselevel) component of the python interpreter version.
returned: always
type: str
sample: final
serial:
description: The C(serial) component of the python interpreter version.
returned: always
type: int
sample: 0
version_added: 4.2.0
python_system_path:
description: List of paths python is looking for modules in
returned: always
type: list
sample:
- /usr/local/opt/python@2/site-packages/
- /usr/lib/python/site-packages/
- /usr/lib/python/site-packages/
- /usr/local/opt/python@2/site-packages/
- /usr/lib/python/site-packages/
valid:
description: A dictionary of dependencies that matched their desired versions. If no version was specified, then I(desired) will be null
returned: always
@@ -80,8 +111,8 @@ not_found:
returned: always
type: list
sample:
- boto4
- requests
- boto4
- requests
'''
import re
@@ -106,11 +137,19 @@ operations = {
'==': operator.eq,
}
python_version_info = dict(
major=sys.version_info[0],
minor=sys.version_info[1],
micro=sys.version_info[2],
releaselevel=sys.version_info[3],
serial=sys.version_info[4],
)
def main():
module = AnsibleModule(
argument_spec=dict(
dependencies=dict(type='list', elements='str')
dependencies=dict(type='list', elements='str', default=[])
),
supports_check_mode=True,
)
@@ -119,9 +158,10 @@ def main():
msg='Could not import "distutils" and "pkg_resources" libraries to introspect python environment.',
python=sys.executable,
python_version=sys.version,
python_version_info=python_version_info,
python_system_path=sys.path,
)
pkg_dep_re = re.compile(r'(^[a-zA-Z][a-zA-Z0-9_-]+)(==|[><]=?)?([0-9.]+)?$')
pkg_dep_re = re.compile(r'(^[a-zA-Z][a-zA-Z0-9_-]+)(?:(==|[><]=?)([0-9.]+))?$')
results = dict(
not_found=[],
@@ -129,9 +169,9 @@ def main():
valid={},
)
for dep in (module.params.get('dependencies') or []):
for dep in module.params['dependencies']:
match = pkg_dep_re.match(dep)
if match is None:
if not match:
module.fail_json(msg="Failed to parse version requirement '{0}'. Must be formatted like 'ansible>2.6'".format(dep))
pkg, op, version = match.groups()
if op is not None and op not in operations:
@@ -161,6 +201,7 @@ def main():
module.exit_json(
python=sys.executable,
python_version=sys.version,
python_version_info=python_version_info,
python_system_path=sys.path,
**results
)

View File

@@ -172,7 +172,7 @@ class Svc(object):
self.execute_command([self.svc_cmd, '-dx', src_log])
def get_status(self):
(rc, out, err) = self.execute_command([self.svstat_cmd, self.svc_full])
rc, out, err = self.execute_command([self.svstat_cmd, self.svc_full])
if err is not None and err:
self.full_state = self.state = err
@@ -223,7 +223,7 @@ class Svc(object):
def execute_command(self, cmd):
try:
(rc, out, err) = self.module.run_command(' '.join(cmd))
rc, out, err = self.module.run_command(cmd)
except Exception as e:
self.module.fail_json(msg="failed to execute: %s" % to_native(e), exception=traceback.format_exc())
return (rc, out, err)

View File

@@ -19,6 +19,8 @@ description:
For Linux it can use C(timedatectl) or edit C(/etc/sysconfig/clock) or C(/etc/timezone) and C(hwclock).
On SmartOS, C(sm-set-timezone), for macOS, C(systemsetup), for BSD, C(/etc/localtime) is modified.
On AIX, C(chtz) is used.
- Make sure that the zoneinfo files are installed with the appropriate OS package, like C(tzdata) (usually always installed,
when not using a minimal installation like Alpine Linux).
- As of Ansible 2.3 support was added for SmartOS and BSDs.
- As of Ansible 2.4 support was added for macOS.
- As of Ansible 2.9 support was added for AIX 6.1+

View File

@@ -128,7 +128,7 @@ RETURN = '''
'''
from ansible_collections.community.general.plugins.module_utils.module_helper import (
ModuleHelper, CmdMixin, StateMixin, ArgFormat, ModuleHelperException
CmdStateModuleHelper, ArgFormat, ModuleHelperException
)
@@ -151,7 +151,7 @@ class XFConfException(Exception):
pass
class XFConfProperty(CmdMixin, StateMixin, ModuleHelper):
class XFConfProperty(CmdStateModuleHelper):
change_params = 'value',
diff_params = 'value',
output_params = ('property', 'channel', 'value')

View File

@@ -36,15 +36,22 @@ options:
username:
type: str
required: true
description:
- The username to log-in with.
- Must be used with I(password). Mutually exclusive with I(token).
password:
type: str
required: true
description:
- The password to log-in with.
- Must be used with I(username). Mutually exclusive with I(token).
token:
type: str
description:
- The personal access token to log-in with.
- Mutually exclusive with I(username) and I(password).
version_added: 4.2.0
project:
type: str
@@ -206,7 +213,7 @@ options:
done.
notes:
- "Currently this only works with basic-auth."
- "Currently this only works with basic-auth, or tokens."
- "To use with JIRA Cloud, pass the login e-mail as the I(username) and the API token as I(password)."
author:
@@ -408,8 +415,9 @@ class JIRA(StateModuleHelper):
choices=['attach', 'create', 'comment', 'edit', 'update', 'fetch', 'transition', 'link', 'search'],
aliases=['command'], required=True
),
username=dict(type='str', required=True),
password=dict(type='str', required=True, no_log=True),
username=dict(type='str'),
password=dict(type='str', no_log=True),
token=dict(type='str', no_log=True),
project=dict(type='str', ),
summary=dict(type='str', ),
description=dict(type='str', ),
@@ -432,6 +440,17 @@ class JIRA(StateModuleHelper):
validate_certs=dict(default=True, type='bool'),
account_id=dict(type='str'),
),
mutually_exclusive=[
['username', 'token'],
['password', 'token'],
['assignee', 'account_id'],
],
required_together=[
['username', 'password'],
],
required_one_of=[
['username', 'token'],
],
required_if=(
('operation', 'attach', ['issue', 'attachment']),
('operation', 'create', ['project', 'issuetype', 'summary']),
@@ -441,7 +460,6 @@ class JIRA(StateModuleHelper):
('operation', 'link', ['linktype', 'inwardissue', 'outwardissue']),
('operation', 'search', ['jql']),
),
mutually_exclusive=[('assignee', 'account_id')],
supports_check_mode=False
)
@@ -642,23 +660,30 @@ class JIRA(StateModuleHelper):
if data and content_type == 'application/json':
data = json.dumps(data)
headers = {}
if isinstance(additional_headers, dict):
headers = additional_headers.copy()
# NOTE: fetch_url uses a password manager, which follows the
# standard request-then-challenge basic-auth semantics. However as
# JIRA allows some unauthorised operations it doesn't necessarily
# send the challenge, so the request occurs as the anonymous user,
# resulting in unexpected results. To work around this we manually
# inject the basic-auth header up-front to ensure that JIRA treats
# inject the auth header up-front to ensure that JIRA treats
# the requests as authorized for this user.
auth = to_text(base64.b64encode(to_bytes('{0}:{1}'.format(self.vars.username, self.vars.password),
errors='surrogate_or_strict')))
headers = {}
if isinstance(additional_headers, dict):
headers = additional_headers.copy()
headers.update({
"Content-Type": content_type,
"Authorization": "Basic %s" % auth,
})
if self.vars.token is not None:
headers.update({
"Content-Type": content_type,
"Authorization": "Bearer %s" % self.vars.token,
})
else:
auth = to_text(base64.b64encode(to_bytes('{0}:{1}'.format(self.vars.username, self.vars.password),
errors='surrogate_or_strict')))
headers.update({
"Content-Type": content_type,
"Authorization": "Basic %s" % auth,
})
response, info = fetch_url(
self.module, url, data=data, method=method, timeout=self.vars.timeout, headers=headers
@@ -669,7 +694,14 @@ class JIRA(StateModuleHelper):
try:
error = json.loads(info['body'])
except Exception:
self.module.fail_json(msg=to_native(info['body']), exception=traceback.format_exc())
msg = 'The request "{method} {url}" returned the unexpected status code {status} {msg}\n{body}'.format(
status=info['status'],
msg=info['msg'],
body=info.get('body'),
url=url,
method=method,
)
self.module.fail_json(msg=to_native(msg), exception=traceback.format_exc())
if error:
msg = []
for key in ('errorMessages', 'errors'):

View File

@@ -0,0 +1,2 @@
shippable/posix/group1
disabled

View File

@@ -0,0 +1,2 @@
gitlab_branch: ansible_test_branch
gitlab_project_name: ansible_test_project

View File

@@ -0,0 +1,64 @@
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Install required libs
pip:
name: python-gitlab
state: present
- name: Create {{ gitlab_project_name }}
gitlab_project:
server_url: "{{ gitlab_host }}"
validate_certs: False
login_token: "{{ gitlab_login_token }}"
name: "{{ gitlab_project_name }}"
initialize_with_readme: True
state: present
- name: Create branch {{ gitlab_branch }}
community.general.gitlab_branch:
api_url: https://gitlab.com
api_token: secret_access_token
project: "{{ gitlab_project_name }}"
branch: "{{ gitlab_branch }}"
ref_branch: main
state: present
- name: Create branch {{ gitlab_branch }} ( Idempotency test )
community.general.gitlab_branch:
api_url: https://gitlab.com
api_token: secret_access_token
project: "{{ gitlab_project_name }}"
branch: "{{ gitlab_branch }}"
ref_branch: main
state: present
register: create_branch
- name: Test module is idempotent
assert:
that:
- create_branch is not changed
- name: Cleanup branch {{ gitlab_branch }}
community.general.gitlab_branch:
api_url: https://gitlab.com
api_token: secret_access_token
project: "{{ gitlab_project_name }}"
branch: "{{ gitlab_branch }}"
state: absent
register: delete_branch
- name: Test module is idempotent
assert:
that:
- delete_branch is changed
- name: Clean up {{ gitlab_project_name }}
gitlab_project:
server_url: "{{ gitlab_host }}"
validate_certs: False
login_token: "{{ gitlab_login_token }}"
name: "{{ gitlab_project_name }}"
state: absent

View File

@@ -0,0 +1 @@
unsupported

View File

@@ -0,0 +1,48 @@
- name: Set NTP Servers
ilo_redfish_config:
category: Manager
command: SetNTPServers
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
attribute_name: StaticNTPServers
attribute_value: 1.2.3.4
- name: Set DNS Server
ilo_redfish_config:
category: Manager
command: SetDNSserver
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
attribute_name: DNSServers
attribute_value: 192.168.1.1
- name: Set Domain name
ilo_redfish_config:
category: Manager
command: SetDomainName
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
attribute_name: DomainName
attribute_value: tst.sgp.hp.mfg
- name: Disable WINS Reg
ilo_redfish_config:
category: Manager
command: SetWINSReg
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
attribute_name: WINSRegistration
- name: Set TimeZone
ilo_redfish_config:
category: Manager
command: SetTimeZone
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
attribute_name: TimeZone
attribute_value: Chennai

View File

@@ -0,0 +1 @@
unsupported

View File

@@ -0,0 +1,8 @@
- name: Get sessions
ilo_redfish_info:
category: Sessions
command: GetiLOSessions
baseuri: "{{ baseuri }}"
username: "{{ username }}"
password: "{{ password }}"
register: result_sessions

View File

@@ -0,0 +1,7 @@
iface eth0 inet static
address 1.2.3.4
netmask 255.255.255.0
gateway 1.2.3.1
up route add -net 1.2.3.4 netmask 255.255.255.0 gw 1.2.3.1 eth0
up ip addr add 4.3.2.1/32 dev eth0
down ip addr add 4.3.2.1/32 dev eth0

View File

@@ -2,6 +2,7 @@
- name:
set_fact:
interfaces_testfile: '{{ remote_tmp_dir }}/interfaces'
interfaces_testfile_3841: '{{ remote_tmp_dir }}/interfaces_3841'
- name: Copy interfaces file
copy:
@@ -31,3 +32,32 @@
- assert:
that:
- ifile_2 is not changed
- name: 3841 - copy interfaces file
copy:
src: 'files/interfaces_ff_3841'
dest: '{{ interfaces_testfile_3841 }}'
- name: 3841 - floating_ip_interface_up_ip 2a01:a:b:c::1/64 dev eth0
interfaces_file:
option: up
iface: eth0
dest: "{{ interfaces_testfile_3841 }}"
value: 'ip addr add 2a01:a:b:c::1/64 dev eth0'
state: present
register: ifile_3841_a
- name: 3841 - floating_ip_interface_up_ip 2a01:a:b:c::1/64 dev eth0 (again)
interfaces_file:
option: up
iface: eth0
dest: "{{ interfaces_testfile_3841 }}"
value: 'ip addr add 2a01:a:b:c::1/64 dev eth0'
state: present
register: ifile_3841_b
- name: 3841 - check assertions
assert:
that:
- ifile_3841_a is changed
- ifile_3841_b is not changed

View File

@@ -30,30 +30,39 @@ EXAMPLES = ""
RETURN = ""
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
from ansible_collections.community.general.plugins.module_utils.mh.deco import check_mode_skip
class MSimple(ModuleHelper):
output_params = ('a', 'b', 'c')
module = dict(
argument_spec=dict(
a=dict(type='int'),
a=dict(type='int', default=0),
b=dict(type='str'),
c=dict(type='str'),
),
supports_check_mode=True,
)
def __init_module__(self):
self.vars.set('value', None)
self.vars.set('abc', "abc", diff=True)
@check_mode_skip
def process_a3_bc(self):
if self.vars.a == 3:
self.vars['b'] = str(self.vars.b) * 3
self.vars['c'] = str(self.vars.c) * 3
def __run__(self):
if (0 if self.vars.a is None else self.vars.a) >= 100:
if self.vars.a >= 100:
raise Exception("a >= 100")
if self.vars.c == "abc change":
self.vars['abc'] = "changed abc"
if self.vars.get('a', 0) == 2:
self.vars['b'] = str(self.vars.b) * 2
self.vars['c'] = str(self.vars.c) * 2
self.process_a3_bc()
def main():

View File

@@ -0,0 +1,64 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2021, Alexei Znamensky <russoz@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
import collections
__metaclass__ = type
DOCUMENTATION = '''
module: msimpleda
author: "Alexei Znamensky (@russoz)"
short_description: Simple module for testing DeprecationAttrsMixin
description:
- Simple module test description.
options:
a:
description: aaaa
type: int
'''
EXAMPLES = ""
RETURN = ""
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin
class MSimpleDA(ModuleHelper):
output_params = ('a',)
module = dict(
argument_spec=dict(
a=dict(type='int'),
),
)
attr1 = "abc"
attr2 = "def"
def __init_module__(self):
self._deprecate_attr(
"attr2",
msg="Attribute attr2 is deprecated",
version="9.9.9",
collection_name="community.general",
target=self.__class__,
module=self.module,
)
def __run__(self):
if self.vars.a == 1:
self.vars.attr1 = self.attr1
if self.vars.a == 2:
self.vars.attr2 = self.attr2
def main():
MSimpleDA.execute()
if __name__ == '__main__':
main()

View File

@@ -24,6 +24,10 @@ options:
c:
description: cccc
type: str
trigger_depr_attr:
description: tries to access VarDict
type: bool
default: false
state:
description: test states
type: str
@@ -45,12 +49,15 @@ class MState(StateModuleHelper):
a=dict(type='int', required=True),
b=dict(type='str'),
c=dict(type='str'),
trigger_depr_attr=dict(type='bool', default=False),
state=dict(type='str', choices=['join', 'b_x_a', 'c_x_a', 'both_x_a', 'nop'], default='join'),
),
)
def __init_module__(self):
self.vars.set('result', "abc", diff=True)
if self.vars.trigger_depr_attr:
dummy = self.VarDict
def state_join(self):
self.vars['result'] = "".join([str(self.vars.a), str(self.vars.b), str(self.vars.c)])

View File

@@ -4,3 +4,4 @@
- include_tasks: msimple.yml
- include_tasks: mdepfail.yml
- include_tasks: mstate.yml
- include_tasks: msimpleda.yml

View File

@@ -1,7 +1,7 @@
# (c) 2021, Alexei Znamensky
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- name: test msimple 1
- name: test msimple (set a=80)
msimple:
a: 80
register: simple1
@@ -55,3 +55,30 @@
- simple4.c == "abc change"
- simple4.abc == "changed abc"
- simple4 is changed
- name: test msimple 5a
msimple:
a: 3 # should triple b and c
b: oh
c: my
register: simple5a
- name: test msimple 5b
check_mode: true
msimple:
a: 3 # should triple b and c
b: oh
c: my
register: simple5b
- name: assert simple5
assert:
that:
- simple5a.a == 3
- simple5a.b == "ohohoh"
- simple5a.c == "mymymy"
- simple5a is not changed
- simple5b.a == 3
- simple5b.b == "oh"
- simple5b.c == "my"
- simple5b is not changed

View File

@@ -0,0 +1,38 @@
# (c) 2021, Alexei Znamensky
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- set_fact:
attr2_d:
msg: Attribute attr2 is deprecated
version: 9.9.9
collection_name: community.general
attr2_d_29:
msg: Attribute attr2 is deprecated
version: 9.9.9
- set_fact:
attr2_depr_dict: "{{ ((ansible_version.major, ansible_version.minor) < (2, 10))|ternary(attr2_d_29, attr2_d) }}"
- name: test msimpleda 1
msimpleda:
a: 1
register: simple1
- name: assert simple1
assert:
that:
- simple1.a == 1
- simple1.attr1 == "abc"
- ("deprecations" not in simple1) or attr2_depr_dict not in simple1.deprecations
- name: test msimpleda 2
msimpleda:
a: 2
register: simple2
- name: assert simple2
assert:
that:
- simple2.a == 2
- simple2.attr2 == "def"
- '"deprecations" in simple2'
- attr2_depr_dict in simple2.deprecations

View File

@@ -69,9 +69,25 @@
a: 5
b: foo
c: bar
trigger_depr_attr: true
state: both_x_a
register: state5
- ansible.builtin.set_fact:
vardict_gt29:
msg: >-
ModuleHelper.VarDict attribute is deprecated, use VarDict from the
ansible_collections.community.general.plugins.module_utils.mh.mixins.vars
module instead
version: 6.0.0
collection_name: community.general
vardict_29:
msg: >-
ModuleHelper.VarDict attribute is deprecated, use VarDict from the
ansible_collections.community.general.plugins.module_utils.mh.mixins.vars
module instead
version: 6.0.0
- name: assert state5
assert:
that:
@@ -80,3 +96,6 @@
- state5.c == "bar"
- state5.result == "foobarfoobarfoobarfoobarfoobar"
- state5 is changed
- vardict_depr in state5.deprecations
vars:
vardict_depr: '{{ (ansible_version.major == 2 and ansible_version.minor == 9) | ternary(vardict_29, vardict_gt29) }}'

View File

@@ -124,3 +124,29 @@
- '"ansible-lint" in inject_pkgs_ansible_lint.application'
- '"licenses" in inject_pkgs_ansible_lint.application["ansible-lint"]["injected"]'
- uninstall_ansible_lint is changed
##############################################################################
- name: install jupyter - not working smoothly in freebsd
block:
- name: ensure application jupyter is uninstalled
community.general.pipx:
name: jupyter
state: absent
- name: install application jupyter
community.general.pipx:
name: jupyter
install_deps: true
register: install_jupyter
- name: cleanup jupyter
community.general.pipx:
state: absent
name: jupyter
- name: check assertions
assert:
that:
- install_jupyter is changed
- '"ipython" in install_jupyter.stdout'
when: ansible_system != 'FreeBSD'

View File

@@ -12,6 +12,7 @@
that:
- "'python' in basic_info"
- "'python_version' in basic_info"
- basic_info.python_version_info == ansible_python.version
- name: run python_requirements_info module
python_requirements_info:
@@ -25,3 +26,15 @@
that:
- "'installed' in dep_info.valid.pip"
- "'notreal' in dep_info.not_found"
- name: wrong specs
python_requirements_info:
dependencies:
- ansible<
register: wrong_spec1
ignore_errors: true
- name: ensure wrong specs return error
assert:
that:
- wrong_spec1 is failed

View File

@@ -4,3 +4,4 @@ skip/freebsd
skip/osx
skip/macos
skip/docker
disabled # FIXME

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