mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-29 01:46:53 +00:00
Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
743591cedc | ||
|
|
412a348738 | ||
|
|
020fcb251f | ||
|
|
1ea0904e69 | ||
|
|
90aa3ec24d | ||
|
|
2b64eb69be | ||
|
|
9233243c13 | ||
|
|
6407d59323 | ||
|
|
25b09239f6 | ||
|
|
524aa8bab4 | ||
|
|
09bea0031d | ||
|
|
be4cf3ba4d | ||
|
|
03da9164d1 | ||
|
|
d99b778fa1 | ||
|
|
fa179e6d0c | ||
|
|
dc79f4a170 | ||
|
|
748882dfa8 | ||
|
|
6458abb9c1 | ||
|
|
09201bf49e | ||
|
|
973b5be063 | ||
|
|
449a179d8f | ||
|
|
27ca6be10a | ||
|
|
3867300eca | ||
|
|
ae05131a54 | ||
|
|
f67003cf3a | ||
|
|
2bd64a891c | ||
|
|
6e226f4588 | ||
|
|
d82bf01128 | ||
|
|
2873d439c3 | ||
|
|
956fc075ef | ||
|
|
7b82e694a2 | ||
|
|
119623952d | ||
|
|
644d362228 | ||
|
|
8def5bf46e | ||
|
|
057fd16cc0 | ||
|
|
3a56f19656 | ||
|
|
729eb996e8 | ||
|
|
3e721f9572 | ||
|
|
4d30704615 | ||
|
|
308a5d7e06 | ||
|
|
f78a44c6a3 | ||
|
|
1b4e58bbbf | ||
|
|
705ffc564d | ||
|
|
86dc3c8816 | ||
|
|
1b1746896d | ||
|
|
32c4bbea30 | ||
|
|
e278490fe7 | ||
|
|
d01187d03b | ||
|
|
3ef5b36066 | ||
|
|
150f63b36b | ||
|
|
582807ea3a | ||
|
|
bdcd10ca2c | ||
|
|
42e88c56b6 | ||
|
|
d858cfa8a8 | ||
|
|
15d5670065 | ||
|
|
e5f55149c6 | ||
|
|
50d22c9f70 | ||
|
|
671ce86565 | ||
|
|
0fc99ae2d8 | ||
|
|
dfa9f77b7a | ||
|
|
cfa712f30e | ||
|
|
c65a675a52 | ||
|
|
e757ff30b3 | ||
|
|
d74e553f4b | ||
|
|
d5a759b2e3 | ||
|
|
c8f2219fb0 | ||
|
|
8fe227d456 | ||
|
|
59fe80ef94 | ||
|
|
d9a2fa9bd9 | ||
|
|
a046ae812e | ||
|
|
953d70611b | ||
|
|
04367d8b9c | ||
|
|
e5f9516335 | ||
|
|
b4f09831b0 | ||
|
|
5f5043d4b8 | ||
|
|
ea465e21c3 | ||
|
|
f00f70f849 | ||
|
|
6020893160 | ||
|
|
1eecf281bc | ||
|
|
fa9ac2b3a9 | ||
|
|
f77d731faf | ||
|
|
56bcb0c32b | ||
|
|
83aa142331 | ||
|
|
cac85a5480 | ||
|
|
3bca7e1ad4 | ||
|
|
b41916285e | ||
|
|
1df4b3ee74 | ||
|
|
ae089aefad | ||
|
|
f92fedcfa0 | ||
|
|
9d269ee8ca | ||
|
|
66d394dc81 | ||
|
|
de180d01e0 | ||
|
|
1a1056099c | ||
|
|
300f525ff9 | ||
|
|
03a639e809 | ||
|
|
f739035d1f | ||
|
|
17e02f87c9 | ||
|
|
becbd2d80f | ||
|
|
aa352ccf45 | ||
|
|
e5b01dfc01 | ||
|
|
a5d830bbf4 | ||
|
|
02b25fb096 | ||
|
|
555d7b9038 | ||
|
|
4dfe6816a8 | ||
|
|
a12ac59223 | ||
|
|
9d7097ef4d | ||
|
|
8e4581c0e6 | ||
|
|
28b50a1e45 | ||
|
|
414f0541a5 | ||
|
|
c4da6e4202 | ||
|
|
05f3052937 | ||
|
|
919d27676c | ||
|
|
a425d16e7c | ||
|
|
12808f67d5 | ||
|
|
268b31b53d | ||
|
|
fa682e8b40 | ||
|
|
0f7d508344 | ||
|
|
ac771079db | ||
|
|
96852b7032 | ||
|
|
08bb917d59 | ||
|
|
e7e9cf97e5 | ||
|
|
deb9d63783 | ||
|
|
a882022280 | ||
|
|
f06bcabeed | ||
|
|
19462b72ca | ||
|
|
a8bd4c750b | ||
|
|
000b92a425 | ||
|
|
7784fbdf17 | ||
|
|
292bb400eb | ||
|
|
c6ddff0dad | ||
|
|
86616b1559 | ||
|
|
99ebbbdf49 | ||
|
|
c853dfb1a8 | ||
|
|
79d8c9bd6e | ||
|
|
e631648ef6 | ||
|
|
5106aa8065 | ||
|
|
25e35bdda7 | ||
|
|
74bc10b8fc | ||
|
|
7415220cad | ||
|
|
7f8bc6f99d | ||
|
|
b5846a3d05 | ||
|
|
25c475a7ef | ||
|
|
b3782a76e0 | ||
|
|
fc5de1a194 | ||
|
|
80184b6fd4 | ||
|
|
be7dc5f37d | ||
|
|
fc7bcccc9d | ||
|
|
5cb4632c15 | ||
|
|
eae5987be1 | ||
|
|
d45044790a | ||
|
|
434f7ce55b |
@@ -70,6 +70,19 @@ stages:
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_21
|
||||
displayName: Sanity 2.21
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.21/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_20
|
||||
displayName: Sanity 2.20
|
||||
dependsOn: []
|
||||
@@ -96,19 +109,6 @@ stages:
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_18
|
||||
displayName: Sanity 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.18/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
### Units
|
||||
- stage: Units_devel
|
||||
displayName: Units devel
|
||||
@@ -125,6 +125,19 @@ stages:
|
||||
- test: '3.12'
|
||||
- test: '3.13'
|
||||
- test: '3.14'
|
||||
- test: '3.15'
|
||||
- stage: Units_2_21
|
||||
displayName: Units 2.21
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.21/units/{0}/1
|
||||
targets:
|
||||
- test: 3.9
|
||||
- test: "3.12"
|
||||
- test: "3.14"
|
||||
- stage: Units_2_20
|
||||
displayName: Units 2.20
|
||||
dependsOn: []
|
||||
@@ -149,18 +162,6 @@ stages:
|
||||
- test: 3.8
|
||||
- test: "3.11"
|
||||
- test: "3.13"
|
||||
- stage: Units_2_18
|
||||
displayName: Units 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.18/units/{0}/1
|
||||
targets:
|
||||
- test: 3.8
|
||||
- test: "3.11"
|
||||
- test: "3.13"
|
||||
|
||||
## Remote
|
||||
- stage: Remote_devel_extra_vms
|
||||
@@ -173,8 +174,8 @@ stages:
|
||||
targets:
|
||||
- name: Alpine 3.23
|
||||
test: alpine/3.23
|
||||
# - name: Fedora 43
|
||||
# test: fedora/43
|
||||
# - name: Fedora 44
|
||||
# test: fedora/44
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu/22.04
|
||||
- name: Ubuntu 24.04
|
||||
@@ -189,8 +190,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: macOS 15.3
|
||||
test: macos/15.3
|
||||
- name: macOS 26.3
|
||||
test: macos/26.3
|
||||
- name: RHEL 10.1
|
||||
test: rhel/10.1
|
||||
- name: RHEL 9.7
|
||||
@@ -198,8 +199,27 @@ stages:
|
||||
# TODO: enable this ASAP!
|
||||
# - name: FreeBSD 15.0
|
||||
# test: freebsd/15.0
|
||||
- name: FreeBSD 14.3
|
||||
test: freebsd/14.3
|
||||
# TODO: enable this ASAP!
|
||||
# - name: FreeBSD 14.4
|
||||
# test: freebsd/14.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_21
|
||||
displayName: Remote 2.21
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.21/{0}
|
||||
targets:
|
||||
# - name: macOS 26.3
|
||||
# test: macos/26.3
|
||||
- name: RHEL 10.1
|
||||
test: rhel/10.1
|
||||
# - name: RHEL 9.7
|
||||
# test: rhel/9.7
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -212,6 +232,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.20/{0}
|
||||
targets:
|
||||
- name: macOS 15.3
|
||||
test: macos/15.3
|
||||
- name: RHEL 10.1
|
||||
test: rhel/10.1
|
||||
- name: FreeBSD 14.3
|
||||
@@ -236,22 +258,6 @@ stages:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_18
|
||||
displayName: Remote 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.18/{0}
|
||||
targets:
|
||||
- name: macOS 14.3
|
||||
test: macos/14.3
|
||||
- name: FreeBSD 14.1
|
||||
test: freebsd/14.1
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Docker
|
||||
- stage: Docker_devel
|
||||
@@ -262,8 +268,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 43
|
||||
test: fedora43
|
||||
- name: Fedora 44
|
||||
test: fedora44
|
||||
- name: Alpine 3.23
|
||||
test: alpine323
|
||||
- name: Ubuntu 22.04
|
||||
@@ -274,6 +280,26 @@ stages:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_21
|
||||
displayName: Docker 2.21
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.21/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 43
|
||||
test: fedora43
|
||||
# - name: Alpine 3.23
|
||||
# test: alpine323
|
||||
# - name: Ubuntu 22.04
|
||||
# test: ubuntu2204
|
||||
- name: Ubuntu 24.04
|
||||
test: ubuntu2404
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_20
|
||||
displayName: Docker 2.20
|
||||
dependsOn: []
|
||||
@@ -306,24 +332,6 @@ stages:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_18
|
||||
displayName: Docker 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.18/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 40
|
||||
test: fedora40
|
||||
- name: Alpine 3.20
|
||||
test: alpine320
|
||||
- name: Ubuntu 24.04
|
||||
test: ubuntu2404
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Community Docker
|
||||
- stage: Docker_community_devel
|
||||
@@ -359,6 +367,18 @@ stages:
|
||||
# testFormat: devel/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.9'
|
||||
# - test: '3.13'
|
||||
# - test: '3.15'
|
||||
# - stage: Generic_2_21
|
||||
# displayName: Generic 2.21
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/matrix.yml
|
||||
# parameters:
|
||||
# nameFormat: Python {0}
|
||||
# testFormat: 2.21/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.9'
|
||||
# - test: '3.12'
|
||||
# - test: '3.14'
|
||||
# - stage: Generic_2_20
|
||||
@@ -382,44 +402,33 @@ stages:
|
||||
# testFormat: 2.19/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.9'
|
||||
# - test: '3.13'
|
||||
# - stage: Generic_2_18
|
||||
# displayName: Generic 2.18
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/matrix.yml
|
||||
# parameters:
|
||||
# nameFormat: Python {0}
|
||||
# testFormat: 2.18/generic/{0}/1
|
||||
# targets:
|
||||
# - test: '3.8'
|
||||
# - test: '3.13'
|
||||
|
||||
- stage: Summary
|
||||
condition: succeededOrFailed()
|
||||
dependsOn:
|
||||
- Sanity_devel
|
||||
- Sanity_2_21
|
||||
- Sanity_2_20
|
||||
- Sanity_2_19
|
||||
- Sanity_2_18
|
||||
- Units_devel
|
||||
- Units_2_21
|
||||
- Units_2_20
|
||||
- Units_2_19
|
||||
- Units_2_18
|
||||
- Remote_devel_extra_vms
|
||||
- Remote_devel
|
||||
- Remote_2_21
|
||||
- Remote_2_20
|
||||
- Remote_2_19
|
||||
- Remote_2_18
|
||||
- Docker_devel
|
||||
- Docker_2_21
|
||||
- Docker_2_20
|
||||
- Docker_2_19
|
||||
- Docker_2_18
|
||||
- Docker_community_devel
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - Generic_devel
|
||||
# - Generic_2_21
|
||||
# - Generic_2_20
|
||||
# - Generic_2_19
|
||||
# - Generic_2_18
|
||||
jobs:
|
||||
- template: templates/coverage.yml
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"ms-python.vscode-pylance",
|
||||
"redhat.ansible",
|
||||
"redhat.vscode-yaml",
|
||||
"trond-snekvik.simple-rst",
|
||||
"trond-snekvik.simple-rst"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
set -x
|
||||
sudo chown -R vscode:vscode /workspace/
|
||||
|
||||
pip install -U pip
|
||||
|
||||
70
.github/BOTMETA.yml
vendored
70
.github/BOTMETA.yml
vendored
@@ -312,7 +312,7 @@ files:
|
||||
$lookups/lmdb_kv.py:
|
||||
maintainers: jpmens
|
||||
$lookups/merge_variables.py:
|
||||
maintainers: rlenferink m-a-r-k-e alpex8
|
||||
maintainers: rlenferink m-a-r-k-e alpex8 cfiehe
|
||||
$lookups/onepass:
|
||||
labels: onepassword
|
||||
maintainers: samdoran
|
||||
@@ -379,8 +379,13 @@ files:
|
||||
$module_utils/jenkins.py:
|
||||
labels: jenkins
|
||||
maintainers: russoz
|
||||
$module_utils/_crypt.py:
|
||||
maintainers: russoz
|
||||
$module_utils/_lxc.py:
|
||||
maintainers: russoz
|
||||
$module_utils/_lvm.py:
|
||||
labels: lvm
|
||||
maintainers: russoz
|
||||
$module_utils/manageiq.py:
|
||||
labels: manageiq
|
||||
maintainers: $team_manageiq
|
||||
@@ -642,6 +647,10 @@ files:
|
||||
maintainers: adrianmoisey
|
||||
$modules/github_repo.py:
|
||||
maintainers: atorrescogollo
|
||||
$modules/github_secrets.py:
|
||||
maintainers: konstruktoid
|
||||
$modules/github_secrets_info.py:
|
||||
maintainers: konstruktoid
|
||||
$modules/gitlab_:
|
||||
keywords: gitlab source_control
|
||||
maintainers: $team_gitlab
|
||||
@@ -657,10 +666,10 @@ files:
|
||||
maintainers: zvaraondrej
|
||||
$modules/gitlab_milestone.py:
|
||||
maintainers: gpongelli
|
||||
$modules/gitlab_project_variable.py:
|
||||
maintainers: markuman
|
||||
$modules/gitlab_instance_variable.py:
|
||||
maintainers: benibr
|
||||
$modules/gitlab_project_variable.py:
|
||||
maintainers: markuman
|
||||
$modules/gitlab_runner.py:
|
||||
maintainers: SamyCoenen
|
||||
$modules/gitlab_user.py:
|
||||
@@ -769,14 +778,14 @@ files:
|
||||
maintainers: abakanovskii
|
||||
$modules/ipa_dnsrecord.py:
|
||||
maintainers: $team_ipa jwbernin
|
||||
$modules/ipbase_info.py:
|
||||
maintainers: dominikkukacka
|
||||
$modules/ipa_pwpolicy.py:
|
||||
maintainers: adralioh
|
||||
$modules/ipa_service.py:
|
||||
maintainers: cprh
|
||||
$modules/ipa_vault.py:
|
||||
maintainers: jparrill
|
||||
$modules/ipbase_info.py:
|
||||
maintainers: dominikkukacka
|
||||
$modules/ipify_facts.py:
|
||||
maintainers: resmo
|
||||
$modules/ipinfoio_facts.py:
|
||||
@@ -836,16 +845,22 @@ files:
|
||||
maintainers: elfelip Gaetan2907
|
||||
$modules/keycloak_authentication_required_actions.py:
|
||||
maintainers: Skrekulko
|
||||
$modules/keycloak_authentication_v2.py:
|
||||
maintainers: thomasbargetz
|
||||
$modules/keycloak_authz_authorization_scope.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_authz_permission.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_authz_custom_policy.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_authz_permission.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_authz_permission_info.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_client.py:
|
||||
maintainers: koke1997
|
||||
$modules/keycloak_client_rolemapping.py:
|
||||
maintainers: Gaetan2907
|
||||
$modules/keycloak_client_rolescope.py:
|
||||
maintainers: desand01
|
||||
$modules/keycloak_clientscope.py:
|
||||
maintainers: Gaetan2907
|
||||
$modules/keycloak_clientscope_type.py:
|
||||
@@ -856,6 +871,8 @@ files:
|
||||
maintainers: fynncfchen johncant
|
||||
$modules/keycloak_component.py:
|
||||
maintainers: fivetide
|
||||
$modules/keycloak_component_info.py:
|
||||
maintainers: desand01
|
||||
$modules/keycloak_group.py:
|
||||
maintainers: adamgoossens
|
||||
$modules/keycloak_identity_provider.py:
|
||||
@@ -865,27 +882,23 @@ files:
|
||||
$modules/keycloak_realm_info.py:
|
||||
maintainers: fynncfchen
|
||||
$modules/keycloak_realm_key.py:
|
||||
maintainers: mattock
|
||||
maintainers: mattock koke1997
|
||||
$modules/keycloak_realm_localization.py:
|
||||
maintainers: danekja
|
||||
$modules/keycloak_realm_rolemapping.py:
|
||||
maintainers: agross mhuysamen Gaetan2907
|
||||
$modules/keycloak_role.py:
|
||||
maintainers: laurpaum
|
||||
$modules/keycloak_user.py:
|
||||
maintainers: elfelip
|
||||
$modules/keycloak_user_federation.py:
|
||||
maintainers: laurpaum
|
||||
$modules/keycloak_userprofile.py:
|
||||
maintainers: yeoldegrove
|
||||
$modules/keycloak_component_info.py:
|
||||
maintainers: desand01
|
||||
$modules/keycloak_client_rolescope.py:
|
||||
maintainers: desand01
|
||||
$modules/keycloak_user_rolemapping.py:
|
||||
maintainers: bratwurzt
|
||||
$modules/keycloak_realm_rolemapping.py:
|
||||
maintainers: agross mhuysamen Gaetan2907
|
||||
$modules/keycloak_user_execute_actions_email.py:
|
||||
maintainers: mariusbertram
|
||||
$modules/keycloak_user_federation.py:
|
||||
maintainers: laurpaum
|
||||
$modules/keycloak_user_rolemapping.py:
|
||||
maintainers: bratwurzt koke1997
|
||||
$modules/keycloak_userprofile.py:
|
||||
maintainers: yeoldegrove
|
||||
$modules/keyring.py:
|
||||
maintainers: ahussey-redhat
|
||||
$modules/keyring_info.py:
|
||||
@@ -928,6 +941,8 @@ files:
|
||||
labels: logentries
|
||||
$modules/logentries_msg.py:
|
||||
maintainers: jcftang
|
||||
$modules/logrotate.py:
|
||||
maintainers: a-gabidullin
|
||||
$modules/logstash_plugin.py:
|
||||
maintainers: nerzhul
|
||||
$modules/lvg.py:
|
||||
@@ -1330,8 +1345,11 @@ files:
|
||||
$modules/snap_alias.py:
|
||||
labels: snap
|
||||
maintainers: russoz
|
||||
$modules/snap_connect.py:
|
||||
labels: snap
|
||||
maintainers: russoz
|
||||
$modules/snmp_facts.py:
|
||||
maintainers: ogenstad ujwalkomarla
|
||||
maintainers: ogenstad ujwalkomarla lalten
|
||||
$modules/solaris_zone.py:
|
||||
keywords: beadm dladm illumos ipadm nexenta omnios openindiana pfexec smartos solaris sunos zfs zpool
|
||||
labels: solaris
|
||||
@@ -1506,11 +1524,11 @@ files:
|
||||
ignore: matze
|
||||
labels: zypper
|
||||
maintainers: $team_suse
|
||||
$plugin_utils/ansible_type.py:
|
||||
maintainers: vbotka
|
||||
$modules/zypper_repository_info.py:
|
||||
labels: zypper
|
||||
maintainers: $team_suse TobiasZeuch181
|
||||
$plugin_utils/ansible_type.py:
|
||||
maintainers: vbotka
|
||||
$plugin_utils/keys_filter.py:
|
||||
maintainers: vbotka
|
||||
$plugin_utils/unsafe.py:
|
||||
@@ -1562,6 +1580,8 @@ files:
|
||||
maintainers: russoz
|
||||
docs/docsite/rst/guide_deps.rst:
|
||||
maintainers: russoz
|
||||
docs/docsite/rst/guide_ee.rst:
|
||||
maintainers: russoz
|
||||
docs/docsite/rst/guide_iocage.rst:
|
||||
maintainers: russoz felixfontein
|
||||
docs/docsite/rst/guide_iocage_inventory.rst:
|
||||
@@ -1619,7 +1639,7 @@ macros:
|
||||
plugin_utils: plugins/plugin_utils
|
||||
tests: plugins/test
|
||||
team_ansible_core:
|
||||
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
||||
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister molekuul ramooncamacho wtcross
|
||||
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
||||
team_consul: sgargan apollo13 Ilgmi
|
||||
team_cyberark_conjur: jvanderhoof ryanprior
|
||||
@@ -1640,7 +1660,7 @@ macros:
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
|
||||
team_rhsm: cnsnyder ptoscano
|
||||
team_scaleway: remyleone abarbare
|
||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||
team_solaris: bcoca fishman jasperla jpdasma scathatheworm troy2914 xen0l
|
||||
team_suse: commel evrardjp lrupp AnderEnder alxgu andytom sealor
|
||||
team_virt: joshainglis karmab Thulium-Drake Ajpantuso
|
||||
team_wdc: mikemoerk
|
||||
|
||||
53
.github/workflows/ansible-test.yml
vendored
53
.github/workflows/ansible-test.yml
vendored
@@ -30,6 +30,7 @@ jobs:
|
||||
matrix:
|
||||
ansible:
|
||||
- '2.17'
|
||||
- '2.18'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Perform sanity testing
|
||||
@@ -63,6 +64,12 @@ jobs:
|
||||
python: '3.10'
|
||||
- ansible: '2.17'
|
||||
python: '3.12'
|
||||
- ansible: '2.18'
|
||||
python: '3.8'
|
||||
- ansible: '2.18'
|
||||
python: '3.11'
|
||||
- ansible: '2.18'
|
||||
python: '3.13'
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
@@ -144,6 +151,52 @@ jobs:
|
||||
# docker: default
|
||||
# python: '3.12'
|
||||
# target: azp/generic/1/
|
||||
# 2.18
|
||||
- ansible: '2.18'
|
||||
docker: fedora40
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.18'
|
||||
docker: fedora40
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.18'
|
||||
docker: fedora40
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.18'
|
||||
docker: ubuntu2404
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.18'
|
||||
docker: ubuntu2404
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.18'
|
||||
docker: ubuntu2404
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.18'
|
||||
docker: alpine320
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.18'
|
||||
docker: alpine320
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.18'
|
||||
docker: alpine320
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - ansible: '2.18'
|
||||
# docker: default
|
||||
# python: '3.8'
|
||||
# target: azp/generic/1/
|
||||
# - ansible: '2.18'
|
||||
# docker: default
|
||||
# python: '3.13'
|
||||
# target: azp/generic/1/
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.14.10
|
||||
rev: v0.15.9
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
|
||||
358
CHANGELOG.md
358
CHANGELOG.md
File diff suppressed because one or more lines are too long
257
CHANGELOG.rst
257
CHANGELOG.rst
@@ -6,6 +6,263 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 11.0.0.
|
||||
|
||||
v12.6.0
|
||||
=======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- cobbler_sync - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- cobbler_system - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- composer - add ``force`` parameter; when ``command=create-project``, the module now checks whether a ``composer.json`` already exists in ``working_dir`` and skips the command if so, making the task idempotent. Set ``force=true`` to always run the command regardless (https://github.com/ansible-collections/community.general/issues/725, https://github.com/ansible-collections/community.general/pull/11689).
|
||||
- consul_kv - add ``ca_path`` option to specify a CA bundle for HTTPS connections (https://github.com/ansible-collections/community.general/pull/11817).
|
||||
- consul_kv lookup plugin - add ``ca_path`` option to specify a CA bundle for HTTPS connections (https://github.com/ansible-collections/community.general/issues/2876, https://github.com/ansible-collections/community.general/pull/11817).
|
||||
- dconf - add support for C(dbus-broker) (https://github.com/ansible-collections/community.general/issues/495, https://github.com/ansible-collections/community.general/pull/11772).
|
||||
- filesystem - migrate ``LVM.get_fs_size()`` to use ``CmdRunner``, ensuring locale-independent output parsing (https://github.com/ansible-collections/community.general/pull/11888).
|
||||
- flatpak - add new parameter ``from_url`` to install a flatpak from a ``.flatpakref`` URL (https://github.com/ansible-collections/community.general/issues/4000, https://github.com/ansible-collections/community.general/pull/11748).
|
||||
- gem - refactor module to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11733).
|
||||
- homebrew_services - remove various redundancies including dead state validation, unused return values, and unnecessary locale environment variables (https://github.com/ansible-collections/community.general/pull/11839).
|
||||
- homebrew_tap - avoid redundant ``brew tap`` calls when processing multiple taps by fetching the tap list once upfront (https://github.com/ansible-collections/community.general/pull/11848).
|
||||
- ipa_dnsrecord - add ``exclusive`` parameter to allow appending values to existing records without replacing them (https://github.com/ansible-collections/community.general/issues/682, https://github.com/ansible-collections/community.general/pull/11694).
|
||||
- java_cert - support proxy authentication when ``https_proxy`` environment variable includes credentials (https://github.com/ansible-collections/community.general/issues/4126, https://github.com/ansible-collections/community.general/pull/11753).
|
||||
- jira - add ``cloud`` option to support Jira Cloud's new search endpoint ``/rest/api/2/search/jql``, since the legacy ``/rest/api/2/search`` endpoint has been removed on Jira Cloud (https://github.com/ansible-collections/community.general/issues/10786, https://github.com/ansible-collections/community.general/pull/11701).
|
||||
- jira - when ``cloud=true``, user-type fields (``assignee``, ``reporter``, and any listed in the new ``custom_user_fields`` parameter) containing an email address are automatically resolved to Jira Cloud account IDs (https://github.com/ansible-collections/community.general/issues/11734, https://github.com/ansible-collections/community.general/pull/11735).
|
||||
- logrotate - adds optional ``backup`` parameter to create a backup of the existing configuration file before writing changes (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- lvg - migrate to ``CmdRunner``, removing direct ``run_command`` calls and ``run_command_environ_update`` (https://github.com/ansible-collections/community.general/pull/11835).
|
||||
- lvm_pv - migrate to ``CmdRunner`` using shared runners from ``module_utils/_lvm`` (https://github.com/ansible-collections/community.general/pull/11811).
|
||||
- lvol - migrate to ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11887).
|
||||
- manageiq module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- manageiq_alert_profiles - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- manageiq_alerts - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- oneview module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- oneview_san_manager - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- opendj_backendprop - refactor to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11728).
|
||||
- packet_device - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- packet_ip_subnet - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- pacman - add ``root``, ``cachedir``, and ``config`` options to support installing packages into an alternative root directory (https://github.com/ansible-collections/community.general/issues/438, https://github.com/ansible-collections/community.general/pull/11681).
|
||||
- parted - add ``unit_preserve_case`` option to control the case of the ``unit`` field in the return value, fixing the round-trip use case where the returned unit is fed back as input (https://github.com/ansible-collections/community.general/issues/1860, https://github.com/ansible-collections/community.general/pull/11813).
|
||||
- pubnub_blocks - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- terraform - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- xenserver_guest - use ``enumerate()`` instead of manual index variable in ``for`` loop (https://github.com/ansible-collections/community.general/pull/11721).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- alternatives - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- apache2_module - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- apk - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- apt_repo - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- apt_rpm - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- awall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- beadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- bower - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- btrfs module_utils - set ``LANGUAGE`` and ``LC_ALL`` environment variables to ``C`` in all ``run_command()`` calls (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11787).
|
||||
- bundler - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- bzr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- capabilities - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- cargo - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- composer - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- cronvar - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- dconf - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- dnf_versionlock - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- dpkg_divert - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- easy_install - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- etcd3 lookup plugin - improve HTTPS endpoint handling by stripping URL schemes from the ``host`` option and warning when ``ca_cert`` is not provided for HTTPS endpoints (https://github.com/ansible-collections/community.general/issues/1664, https://github.com/ansible-collections/community.general/pull/11861).
|
||||
- facter_facts - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- filesystem - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- flatpak - fix removal of runtimes, which was broken because the module was filtering the installed flatpak list to apps only, so runtimes could never be matched for uninstallation (https://github.com/ansible-collections/community.general/issues/553, https://github.com/ansible-collections/community.general/pull/11688).
|
||||
- flatpak - support new output message when an update resulted in no action that appears on Fedora 44 (https://github.com/ansible-collections/community.general/pull/11836).
|
||||
- flatpak_remote - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- git_config - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- git_config_info - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- gitlab_project_members - fail with a clear error when multiple projects match the given name, instead of silently operating on the first result (https://github.com/ansible-collections/community.general/issues/2767, https://github.com/ansible-collections/community.general/pull/11851).
|
||||
- gitlab_project_variable - use ``find_project()`` from module utils for project lookup, consistent with all other GitLab modules in the collection (https://github.com/ansible-collections/community.general/issues/3157, https://github.com/ansible-collections/community.general/pull/11878).
|
||||
- hg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- homebrew - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- homebrew_cask - fix ``sudo_password`` failing when the password contains single quotes or other special shell characters (https://github.com/ansible-collections/community.general/issues/4957, https://github.com/ansible-collections/community.general/pull/11850).
|
||||
- homebrew_cask - fix failure when ``brew --version`` returns a placeholder version string (https://github.com/ansible-collections/community.general/issues/4708, https://github.com/ansible-collections/community.general/pull/11849).
|
||||
- homebrew_cask - fix false task failure when upgrading casks with ``version=latest``; the post-upgrade check incorrectly re-ran ``brew outdated`` (which always lists ``latest`` casks as outdated under ``--greedy``), now uses the command exit code instead (https://github.com/ansible-collections/community.general/issues/1647, https://github.com/ansible-collections/community.general/pull/11838).
|
||||
- homebrew_cask - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- homebrew_tap - fix ``None`` being passed as a command argument when adding a tap without a URL (https://github.com/ansible-collections/community.general/pull/11848).
|
||||
- homectl - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/pull/11860).
|
||||
- homectl - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- icinga2_feature - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- imgadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- incus connection plugin - work when the active become plugin sets ``require_tty`` instead of failing silently (https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- ip_netns - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- ipa module utils - fix failure to detect errors reported in the ``failed`` field of the IPA API response, which is returned with HTTP 200 on partial or full failures in member add/remove operations (https://github.com/ansible-collections/community.general/issues/1239, https://github.com/ansible-collections/community.general/pull/11698).
|
||||
- ipa_dnsrecord - fix errors when module is used with existing record with default TTL (https://github.com/ansible-collections/community.general/pull/11717).
|
||||
- ipa_host - fix logic to disable existing hosts (https://github.com/ansible-collections/community.general/issues/11483, https://github.com/ansible-collections/community.general/pull/11487).
|
||||
- iptables_state - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- iso_extract - retry ``umount`` up to 5 times preventing ``OSError`` on cleanup (https://github.com/ansible-collections/community.general/issues/5333, https://github.com/ansible-collections/community.general/pull/11837).
|
||||
- iso_extract - strip leading path separator from file entries so files with a leading ``/`` are extracted correctly (https://github.com/ansible-collections/community.general/issues/5283, https://github.com/ansible-collections/community.general/pull/11825).
|
||||
- java_cert - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- java_keystore - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- keyring - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- keyring_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- kibana_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- known_hosts module utils - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- launchd - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- lbu - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- listen_ports_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- lldp - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- locale_gen - add missing locale entries to ``/etc/locale.gen`` when not already present (https://github.com/ansible-collections/community.general/issues/2399, https://github.com/ansible-collections/community.general/pull/11824).
|
||||
- logrotate - adds missing default values for ``state`` and ``config_dir`` parameters, and adds ``required_by`` declarations for shred and compression parameters (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logrotate - fixes ``TypeError`` when ``shred_cycles`` is ``None`` and corrects ``enabled=None`` handling in ``get_config_path()`` (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logrotate - writes configuration files to a temporary file first and validates before atomically moving to the destination, and properly wraps all ``os.remove()`` and ``atomic_move()`` calls in error handling (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logstash_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- lvg - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- lvol - fix LVM version parsing (https://github.com/ansible-collections/community.general/issues/5445, https://github.com/ansible-collections/community.general/pull/11823).
|
||||
- lvol - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- lxc_container - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- machinectl become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- macports - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- mas - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- modprobe - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- monit - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- mssql_db - fail with a clear error message when a named instance (``server\instance`` format) is used together with ``login_port``, since these are mutually exclusive connection methods (https://github.com/ansible-collections/community.general/issues/5693, https://github.com/ansible-collections/community.general/pull/11664).
|
||||
- mssql_script - fail with a clear error message when a named instance (``server\instance`` format) is used together with ``login_port``, since these are mutually exclusive connection methods (https://github.com/ansible-collections/community.general/issues/5693, https://github.com/ansible-collections/community.general/pull/11664).
|
||||
- mssql_script - only passes ``params`` to ``cursor.execute()`` when the user actually provides them (https://github.com/ansible-collections/community.general/issues/11699, https://github.com/ansible-collections/community.general/pull/11754).
|
||||
- nmcli - use ``get_best_parsable_locale()`` to set locale environment for ``run_command()`` calls, fixing UTF-8 connection names being corrupted to ``????`` under ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/10384, https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11742).
|
||||
- nsupdate - fix GSS-TSIG support (accidentally broken by https://github.com/ansible-collections/community.general/pull/11461, https://github.com/ansible-collections/community.general/pull/11712)
|
||||
- ohai - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- onepassword_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- open_iscsi - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- openbsd_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11767).
|
||||
- openwrt_init - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- osx_defaults - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- pacemaker_resource, pacemaker_stonith - fix resource and stonith creation race condition by polling PCS status (https://github.com/ansible-collections/community.general/issues/11574, https://github.com/ansible-collections/community.general/pull/11750).
|
||||
- pacman - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- pacman_key - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- parted - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- pear - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- pip_package_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- pkg5 - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- pkg5_publisher - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- pkgin - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- pkgng - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- pkgutil - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- pnpm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- portage - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- portinstall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- redhat_subscription - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- rhsm_release - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- rhsm_repository - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- riak - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- rpm_ostree_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- run0 become plugin - mark the plugin as incompatible with connection pipelining (see https://github.com/ansible/ansible/issues/81254, https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- run0 become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- runit - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- sefcontext - flush the in-process ``matchpathcon`` cache after applying changes, so subsequent tasks running in the same process (for example via the Mitogen connection plugin) see the updated SELinux file context rules instead of stale cached data (https://github.com/ansible-collections/community.general/issues/888, https://github.com/ansible-collections/community.general/pull/11812).
|
||||
- smartos_image_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- snmp_facts - the module now also supports pysnmp >= 7.1 (https://github.com/ansible-collections/community.general/issues/8852, https://github.com/ansible-collections/community.general/pull/11683).
|
||||
- sorcery - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11767).
|
||||
- supervisorctl - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- svc - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- swdepot - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- syspatch - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- sysrc - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- sysupgrade - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- terraform - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- timezone - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- udm_user - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/issues/4690, https://github.com/ansible-collections/community.general/pull/11860).
|
||||
- udm_user - fix alias-to-canonical parameter name mismatch that caused all camelCase-aliased parameters such as ``display_name`` and ``primary_group`` to be silently ignored (https://github.com/ansible-collections/community.general/issues/2950, https://github.com/ansible-collections/community.general/issues/3691, https://github.com/ansible-collections/community.general/pull/11859).
|
||||
- ufw - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- xattr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- xbps - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- xenserver_guest - fix an issue where booting from ISO is not possible because CD-ROM device is placed in position above number 3. Position number 3 is now reserved for CD-ROM device and cannot be occupied by a disk (https://github.com/ansible-collections/community.general/issues/11624, https://github.com/ansible-collections/community.general/pull/11702).
|
||||
- yarn - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- yum_versionlock - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11777).
|
||||
- zfs - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zfs_delegate_admin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zfs_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zpool_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zypper - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- zypper_repository - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11777).
|
||||
- zypper_repository_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11782).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- community.general.snap_connect - Manages snap interface connections.
|
||||
|
||||
v12.5.0
|
||||
=======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- ansible_galaxy_install - add parameter ``executable`` (https://github.com/ansible-collections/community.general/issues/7261, https://github.com/ansible-collections/community.general/pull/11646).
|
||||
- api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- bitbucket module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- consul module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- doas become plugin - add new option ``allow_pipelining`` to explicitly allow the use of pipelining with this plugin. This should only be set to ``true`` with ansible-core 2.19+ when ``doas`` does not require a password (https://github.com/ansible-collections/community.general/issues/11411, https://github.com/ansible-collections/community.general/pull/11481).
|
||||
- gandi_livedns_api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- github_app_access_token lookup plugin - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- hwc_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- icinga2 inventory plugin - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- incus inventory plugin - add support for constructing project-independent FQDNs (https://github.com/ansible-collections/community.general/pull/11555).
|
||||
- ipa module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- keycloak module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- keycloak_realm - add ``first_broker_login_flow`` parameter (https://github.com/ansible-collections/community.general/pull/11622).
|
||||
- ldap_attrs - add ``binary_attributes`` and ``honor_binary`` parameters to handle binary attribute values (https://github.com/ansible-collections/community.general/pull/11558).
|
||||
- ldap_entry - add ``binary_attributes`` and ``honor_binary`` parameters to handle creating objects with attributes set to binary values (https://github.com/ansible-collections/community.general/pull/11558).
|
||||
- lookup plugin passwordstore - modernize internal ``check_output2()`` helper using ``subprocess.run()`` and rename it to ``run_backend_cmd()`` (https://github.com/ansible-collections/community.general/pull/11655).
|
||||
- memset module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- merge_variables lookup plugin - extended merging capabilities added (https://github.com/ansible-collections/community.general/pull/11536).
|
||||
- nmcli - fix idempotency for MAC VLAN interfaces when using ``macvlan.tap`` (https://github.com/ansible-collections/community.general/pull/11551).
|
||||
- nsupdate - replace ``list(map(...))`` constructs with Python comprehensions (https://github.com/ansible-collections/community.general/pull/11590).
|
||||
- ocapi_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- oci_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- online module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- osx_defaults - add support for ``dict`` type values, including ``dict_mode`` option to merge keys into an existing dictionary (https://github.com/ansible-collections/community.general/issues/238, https://github.com/ansible-collections/community.general/pull/11659).
|
||||
- redfish_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- rundeck module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- scaleway module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- supervisorctl - added an additional condition for generating the error 'no such process' (https://github.com/ansible-collections/community.general/issues/11621, https://github.com/ansible-collections/community.general/pull/11632).
|
||||
- timezone - replace ``list(map(...))`` constructs with Python comprehensions (https://github.com/ansible-collections/community.general/pull/11590).
|
||||
- utm_utils module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
- aix_devices - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_filesystem - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_inittab - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_lvg - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_lvol - module is superseded by equivalent in ``ibm.power_aix`` collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290, https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- monit - support for Monit version 5.18 or older is deprecated and will be removed in community.general 14.0.0 (https://github.com/ansible-collections/community.general/pull/11254).
|
||||
- puppet - the ``timeout`` parameter is deprecated and will be removed in community.general 14.0.0. (https://github.com/ansible-collections/community.general/pull/11658).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- counter_enabled callback plugin - fix plugin not observing ``display_ok_hosts`` option (https://github.com/ansible-collections/community.general/issues/3978, https://github.com/ansible-collections/community.general/pull/11656).
|
||||
- ipa_dnsrecord - fix idempotency bug when using ``dnsttl`` due to wrong Python types (https://github.com/ansible-collections/community.general/pull/11559).
|
||||
- keycloak_authentication - fix ``TypeError`` crash when a flow is defined without ``authenticationExecutions`` (https://github.com/ansible-collections/community.general/issues/11547, https://github.com/ansible-collections/community.general/pull/11548).
|
||||
- nictagadm - add a condition to the if statement so that ``is_valid_mac()`` does not get called if ``etherstub`` is false (https://github.com/ansible-collections/community.general/pull/11589).
|
||||
- nmcli - add missing ``ipv6.routing-rules`` to ``settings_type()`` list type, preventing ``routing_rules6`` list from being corrupted (https://github.com/ansible-collections/community.general/issues/11630, https://github.com/ansible-collections/community.general/pull/11635).
|
||||
- open_iscsi - fix IPv6 portal address formatting; iscsiadm requires bracket notation for IPv6 addresses but the module was producing an incorrect format (https://github.com/ansible-collections/community.general/issues/4467, https://github.com/ansible-collections/community.general/pull/11657).
|
||||
- xfconf - representation of boolean properties was not consistent between Python and ``xfconf-query``, leading to broken idempotency (https://github.com/ansible-collections/community.general/pull/11645).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- community.general.github_secrets - Manage GitHub repository or organization secrets.
|
||||
- community.general.github_secrets_info - List GitHub repository or organization secrets.
|
||||
- community.general.keycloak_authentication_v2 - Configure authentication flows in Keycloak in an idempotent and safe manner.
|
||||
- community.general.logrotate - Manage logrotate configurations.
|
||||
|
||||
v12.4.0
|
||||
=======
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ The easiest way to format the code, and to run sanity and unit tests locally is
|
||||
|
||||
### Format code
|
||||
|
||||
The following commands show how to run ansible-test sanity tests:
|
||||
The following commands show how to run ruff format:
|
||||
|
||||
```.bash
|
||||
# Run all configured formatters:
|
||||
|
||||
@@ -39,7 +39,7 @@ For more information about communication, see the [Ansible communication guide](
|
||||
|
||||
## Tested with Ansible
|
||||
|
||||
Tested with the current ansible-core 2.17, ansible-core 2.18, ansible-core 2.19, ansible-core 2.20 releases and the current development version of ansible-core. Ansible-core versions before 2.17.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
Tested with the current ansible-core 2.17, ansible-core 2.18, ansible-core 2.19, ansible-core 2.20, ansible-core 2.21 releases and the current development version of ansible-core. Ansible-core versions before 2.17.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
|
||||
## External requirements
|
||||
|
||||
|
||||
@@ -1886,3 +1886,682 @@ releases:
|
||||
name: loganalytics_ingestion
|
||||
namespace: null
|
||||
release_date: '2026-02-23'
|
||||
12.5.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- counter_enabled callback plugin - fix plugin not observing ``display_ok_hosts``
|
||||
option (https://github.com/ansible-collections/community.general/issues/3978,
|
||||
https://github.com/ansible-collections/community.general/pull/11656).
|
||||
- ipa_dnsrecord - fix idempotency bug when using ``dnsttl`` due to wrong Python
|
||||
types (https://github.com/ansible-collections/community.general/pull/11559).
|
||||
- keycloak_authentication - fix ``TypeError`` crash when a flow is defined
|
||||
without ``authenticationExecutions`` (https://github.com/ansible-collections/community.general/issues/11547,
|
||||
https://github.com/ansible-collections/community.general/pull/11548).
|
||||
- nictagadm - add a condition to the if statement so that ``is_valid_mac()``
|
||||
does not get called if ``etherstub`` is false (https://github.com/ansible-collections/community.general/pull/11589).
|
||||
- nmcli - add missing ``ipv6.routing-rules`` to ``settings_type()`` list type,
|
||||
preventing ``routing_rules6`` list from being corrupted (https://github.com/ansible-collections/community.general/issues/11630,
|
||||
https://github.com/ansible-collections/community.general/pull/11635).
|
||||
- open_iscsi - fix IPv6 portal address formatting; iscsiadm requires bracket
|
||||
notation for IPv6 addresses but the module was producing an incorrect format
|
||||
(https://github.com/ansible-collections/community.general/issues/4467, https://github.com/ansible-collections/community.general/pull/11657).
|
||||
- xfconf - representation of boolean properties was not consistent between
|
||||
Python and ``xfconf-query``, leading to broken idempotency (https://github.com/ansible-collections/community.general/pull/11645).
|
||||
deprecated_features:
|
||||
- aix_devices - module is superseded by equivalent in ``ibm.power_aix`` collection.
|
||||
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
|
||||
https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_filesystem - module is superseded by equivalent in ``ibm.power_aix``
|
||||
collection. It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
|
||||
https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_inittab - module is superseded by equivalent in ``ibm.power_aix`` collection.
|
||||
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
|
||||
https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_lvg - module is superseded by equivalent in ``ibm.power_aix`` collection.
|
||||
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
|
||||
https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- aix_lvol - module is superseded by equivalent in ``ibm.power_aix`` collection.
|
||||
It will be removed from community.general 15.0.0 (https://github.com/ansible-collections/community.general/issues/11290,
|
||||
https://github.com/ansible-collections/community.general/pull/11540).
|
||||
- monit - support for Monit version 5.18 or older is deprecated and will be
|
||||
removed in community.general 14.0.0 (https://github.com/ansible-collections/community.general/pull/11254).
|
||||
- puppet - the ``timeout`` parameter is deprecated and will be removed in
|
||||
community.general 14.0.0. (https://github.com/ansible-collections/community.general/pull/11658).
|
||||
minor_changes:
|
||||
- ansible_galaxy_install - add parameter ``executable`` (https://github.com/ansible-collections/community.general/issues/7261,
|
||||
https://github.com/ansible-collections/community.general/pull/11646).
|
||||
- api module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- bitbucket module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- consul module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- doas become plugin - add new option ``allow_pipelining`` to explicitly allow
|
||||
the use of pipelining with this plugin. This should only be set to ``true``
|
||||
with ansible-core 2.19+ when ``doas`` does not require a password (https://github.com/ansible-collections/community.general/issues/11411,
|
||||
https://github.com/ansible-collections/community.general/pull/11481).
|
||||
- gandi_livedns_api module utils - use Python-defined constants for HTTP return
|
||||
codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- github_app_access_token lookup plugin - use Python-defined constants for
|
||||
HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- hwc_utils module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- icinga2 inventory plugin - use Python-defined constants for HTTP return
|
||||
codes (https://github.com/ansible-collections/community.general/pull/11561,
|
||||
https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- incus inventory plugin - add support for constructing project-independent
|
||||
FQDNs (https://github.com/ansible-collections/community.general/pull/11555).
|
||||
- ipa module utils - use Python-defined constants for HTTP return codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- keycloak module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- keycloak_realm - add ``first_broker_login_flow`` parameter (https://github.com/ansible-collections/community.general/pull/11622).
|
||||
- ldap_attrs - add ``binary_attributes`` and ``honor_binary`` parameters to
|
||||
handle binary attribute values (https://github.com/ansible-collections/community.general/pull/11558).
|
||||
- ldap_entry - add ``binary_attributes`` and ``honor_binary`` parameters to
|
||||
handle creating objects with attributes set to binary values (https://github.com/ansible-collections/community.general/pull/11558).
|
||||
- lookup plugin passwordstore - modernize internal ``check_output2()`` helper
|
||||
using ``subprocess.run()`` and rename it to ``run_backend_cmd()`` (https://github.com/ansible-collections/community.general/pull/11655).
|
||||
- memset module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- merge_variables lookup plugin - extended merging capabilities added (https://github.com/ansible-collections/community.general/pull/11536).
|
||||
- nmcli - fix idempotency for MAC VLAN interfaces when using ``macvlan.tap``
|
||||
(https://github.com/ansible-collections/community.general/pull/11551).
|
||||
- nsupdate - replace ``list(map(...))`` constructs with Python comprehensions
|
||||
(https://github.com/ansible-collections/community.general/pull/11590).
|
||||
- ocapi_utils module utils - use Python-defined constants for HTTP return
|
||||
codes (https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- oci_utils module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- online module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- osx_defaults - add support for ``dict`` type values, including ``dict_mode``
|
||||
option to merge keys into an existing dictionary (https://github.com/ansible-collections/community.general/issues/238,
|
||||
https://github.com/ansible-collections/community.general/pull/11659).
|
||||
- redfish_utils module utils - use Python-defined constants for HTTP return
|
||||
codes (https://github.com/ansible-collections/community.general/pull/11561,
|
||||
https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- rundeck module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
- scaleway module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561).
|
||||
- supervisorctl - added an additional condition for generating the error 'no
|
||||
such process' (https://github.com/ansible-collections/community.general/issues/11621,
|
||||
https://github.com/ansible-collections/community.general/pull/11632).
|
||||
- timezone - replace ``list(map(...))`` constructs with Python comprehensions
|
||||
(https://github.com/ansible-collections/community.general/pull/11590).
|
||||
- utm_utils module utils - use Python-defined constants for HTTP return codes
|
||||
(https://github.com/ansible-collections/community.general/pull/11561, https://github.com/ansible-collections/community.general/pull/11573).
|
||||
release_summary: Bugfix and feature release.
|
||||
fragments:
|
||||
- 11254-monit-deprecate-old.yml
|
||||
- 11481-doas-pipelining.yml
|
||||
- 11536-merge-variables-extended-merging-capabilities.yml
|
||||
- 11540-deprecate-aix.yml
|
||||
- 11551-fix-nmcli-idempotency-for-macvlan.yml
|
||||
- 11555-incus-domain-name.yml
|
||||
- 11558-binary-ldap-attributes.yml
|
||||
- 11559-fix-ipa_dnsrecord-fail-when-no-change.yaml
|
||||
- 11561-use-httpstatus-1.yml
|
||||
- 11584-keycloak-first-roker-login-parameter.yml
|
||||
- 11590-list-map.yml
|
||||
- 11621-skip-no_such_process-for-name-all.yml
|
||||
- 11630-nmcli-ipv6-routing-rules.yml
|
||||
- 11645-xfconf-bool.yml
|
||||
- 11646-galaxy-executable.yml
|
||||
- 11655-passwordstore-cleanup.yml
|
||||
- 11656-counter_enabled-display_ok_hosts.yml
|
||||
- 11657-open-iscsi-ipv6.yml
|
||||
- 11658-puppet-timeout-deprecation.yml
|
||||
- 11659-osx-defaults-dict.yml
|
||||
- 12.5.0.yml
|
||||
- keycloak-authentication-none-executions.yml
|
||||
- nictagadm-etherstub-nonetype-bugfix.yml
|
||||
modules:
|
||||
- description: Manage GitHub repository or organization secrets.
|
||||
name: github_secrets
|
||||
namespace: ''
|
||||
- description: List GitHub repository or organization secrets.
|
||||
name: github_secrets_info
|
||||
namespace: ''
|
||||
- description: Configure authentication flows in Keycloak in an idempotent and
|
||||
safe manner.
|
||||
name: keycloak_authentication_v2
|
||||
namespace: ''
|
||||
- description: Manage logrotate configurations.
|
||||
name: logrotate
|
||||
namespace: ''
|
||||
release_date: '2026-03-23'
|
||||
12.6.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- alternatives - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- apache2_module - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- apk - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- apt_repo - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- apt_rpm - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- awall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- beadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- bower - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- btrfs module_utils - set ``LANGUAGE`` and ``LC_ALL`` environment variables
|
||||
to ``C`` in all ``run_command()`` calls (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11787).
|
||||
- bundler - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- bzr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- capabilities - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- cargo - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- composer - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- cronvar - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- dconf - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- dnf_versionlock - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- dpkg_divert - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- easy_install - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- etcd3 lookup plugin - improve HTTPS endpoint handling by stripping URL schemes
|
||||
from the ``host`` option and warning when ``ca_cert`` is not provided for
|
||||
HTTPS endpoints (https://github.com/ansible-collections/community.general/issues/1664,
|
||||
https://github.com/ansible-collections/community.general/pull/11861).
|
||||
- facter_facts - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- filesystem - normalize locale environment for ``run_command()`` calls to
|
||||
``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- flatpak - fix removal of runtimes, which was broken because the module was
|
||||
filtering the installed flatpak list to apps only, so runtimes could never
|
||||
be matched for uninstallation (https://github.com/ansible-collections/community.general/issues/553,
|
||||
https://github.com/ansible-collections/community.general/pull/11688).
|
||||
- flatpak - support new output message when an update resulted in no action
|
||||
that appears on Fedora 44 (https://github.com/ansible-collections/community.general/pull/11836).
|
||||
- flatpak_remote - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- git_config - normalize locale environment for ``run_command()`` calls to
|
||||
``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- git_config_info - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11738).
|
||||
- gitlab_project_members - fail with a clear error when multiple projects
|
||||
match the given name, instead of silently operating on the first result
|
||||
(https://github.com/ansible-collections/community.general/issues/2767, https://github.com/ansible-collections/community.general/pull/11851).
|
||||
- gitlab_project_variable - use ``find_project()`` from module utils for project
|
||||
lookup, consistent with all other GitLab modules in the collection (https://github.com/ansible-collections/community.general/issues/3157,
|
||||
https://github.com/ansible-collections/community.general/pull/11878).
|
||||
- hg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11773).
|
||||
- homebrew - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- homebrew_cask - fix ``sudo_password`` failing when the password contains
|
||||
single quotes or other special shell characters (https://github.com/ansible-collections/community.general/issues/4957,
|
||||
https://github.com/ansible-collections/community.general/pull/11850).
|
||||
- homebrew_cask - fix failure when ``brew --version`` returns a placeholder
|
||||
version string (https://github.com/ansible-collections/community.general/issues/4708,
|
||||
https://github.com/ansible-collections/community.general/pull/11849).
|
||||
- homebrew_cask - fix false task failure when upgrading casks with ``version=latest``;
|
||||
the post-upgrade check incorrectly re-ran ``brew outdated`` (which always
|
||||
lists ``latest`` casks as outdated under ``--greedy``), now uses the command
|
||||
exit code instead (https://github.com/ansible-collections/community.general/issues/1647,
|
||||
https://github.com/ansible-collections/community.general/pull/11838).
|
||||
- homebrew_cask - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- homebrew_tap - fix ``None`` being passed as a command argument when adding
|
||||
a tap without a URL (https://github.com/ansible-collections/community.general/pull/11848).
|
||||
- homectl - allow to use passlib instead of legacycrypt for Python 3.13+ (https://github.com/ansible-collections/community.general/pull/11860).
|
||||
- homectl - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- icinga2_feature - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- imgadm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- incus connection plugin - work when the active become plugin sets ``require_tty``
|
||||
instead of failing silently (https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- ip_netns - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- ipa module utils - fix failure to detect errors reported in the ``failed``
|
||||
field of the IPA API response, which is returned with HTTP 200 on partial
|
||||
or full failures in member add/remove operations (https://github.com/ansible-collections/community.general/issues/1239,
|
||||
https://github.com/ansible-collections/community.general/pull/11698).
|
||||
- ipa_dnsrecord - fix errors when module is used with existing record with
|
||||
default TTL (https://github.com/ansible-collections/community.general/pull/11717).
|
||||
- ipa_host - fix logic to disable existing hosts (https://github.com/ansible-collections/community.general/issues/11483,
|
||||
https://github.com/ansible-collections/community.general/pull/11487).
|
||||
- iptables_state - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- iso_extract - retry ``umount`` up to 5 times preventing ``OSError`` on cleanup
|
||||
(https://github.com/ansible-collections/community.general/issues/5333, https://github.com/ansible-collections/community.general/pull/11837).
|
||||
- iso_extract - strip leading path separator from file entries so files with
|
||||
a leading ``/`` are extracted correctly (https://github.com/ansible-collections/community.general/issues/5283,
|
||||
https://github.com/ansible-collections/community.general/pull/11825).
|
||||
- java_cert - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- java_keystore - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- keyring - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- keyring_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- kibana_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11783).
|
||||
- known_hosts module utils - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set
|
||||
when running commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- launchd - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- lbu - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- listen_ports_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11774).
|
||||
- lldp - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- locale_gen - add missing locale entries to ``/etc/locale.gen`` when not
|
||||
already present (https://github.com/ansible-collections/community.general/issues/2399,
|
||||
https://github.com/ansible-collections/community.general/pull/11824).
|
||||
- logrotate - adds missing default values for ``state`` and ``config_dir``
|
||||
parameters, and adds ``required_by`` declarations for shred and compression
|
||||
parameters (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logrotate - fixes ``TypeError`` when ``shred_cycles`` is ``None`` and corrects
|
||||
``enabled=None`` handling in ``get_config_path()`` (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logrotate - writes configuration files to a temporary file first and validates
|
||||
before atomically moving to the destination, and properly wraps all ``os.remove()``
|
||||
and ``atomic_move()`` calls in error handling (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- logstash_plugin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- lvg - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- lvol - fix LVM version parsing (https://github.com/ansible-collections/community.general/issues/5445,
|
||||
https://github.com/ansible-collections/community.general/pull/11823).
|
||||
- lvol - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- lxc_container - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11779).
|
||||
- machinectl become plugin - prevent printing ANSI terminal color sequences
|
||||
(https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- macports - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- mas - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- modprobe - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- monit - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- mssql_db - fail with a clear error message when a named instance (``server\instance``
|
||||
format) is used together with ``login_port``, since these are mutually exclusive
|
||||
connection methods (https://github.com/ansible-collections/community.general/issues/5693,
|
||||
https://github.com/ansible-collections/community.general/pull/11664).
|
||||
- mssql_script - fail with a clear error message when a named instance (``server\instance``
|
||||
format) is used together with ``login_port``, since these are mutually exclusive
|
||||
connection methods (https://github.com/ansible-collections/community.general/issues/5693,
|
||||
https://github.com/ansible-collections/community.general/pull/11664).
|
||||
- mssql_script - only passes ``params`` to ``cursor.execute()`` when the user
|
||||
actually provides them (https://github.com/ansible-collections/community.general/issues/11699,
|
||||
https://github.com/ansible-collections/community.general/pull/11754).
|
||||
- nmcli - use ``get_best_parsable_locale()`` to set locale environment for
|
||||
``run_command()`` calls, fixing UTF-8 connection names being corrupted to
|
||||
``????`` under ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/10384,
|
||||
https://github.com/ansible-collections/community.general/issues/11737, https://github.com/ansible-collections/community.general/pull/11742).
|
||||
- nsupdate - fix GSS-TSIG support (accidentally broken by https://github.com/ansible-collections/community.general/pull/11461,
|
||||
https://github.com/ansible-collections/community.general/pull/11712)
|
||||
- ohai - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11785).
|
||||
- onepassword_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- open_iscsi - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- openbsd_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11767).
|
||||
- openwrt_init - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- osx_defaults - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- pacemaker_resource, pacemaker_stonith - fix resource and stonith creation
|
||||
race condition by polling PCS status (https://github.com/ansible-collections/community.general/issues/11574,
|
||||
https://github.com/ansible-collections/community.general/pull/11750).
|
||||
- pacman - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- pacman_key - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- parted - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11740).
|
||||
- pear - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11782).
|
||||
- pip_package_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11784).
|
||||
- pkg5 - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- pkg5_publisher - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- pkgin - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- pkgng - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- pkgutil - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11775).
|
||||
- pnpm - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- portage - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- portinstall - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- redhat_subscription - normalize locale environment for ``run_command()``
|
||||
calls to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- rhsm_release - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- rhsm_repository - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- riak - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11786).
|
||||
- rpm_ostree_pkg - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- run0 become plugin - mark the plugin as incompatible with connection pipelining
|
||||
(see https://github.com/ansible/ansible/issues/81254, https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- run0 become plugin - prevent printing ANSI terminal color sequences (https://github.com/ansible-collections/community.general/pull/11771).
|
||||
- runit - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- sefcontext - flush the in-process ``matchpathcon`` cache after applying
|
||||
changes, so subsequent tasks running in the same process (for example via
|
||||
the Mitogen connection plugin) see the updated SELinux file context rules
|
||||
instead of stale cached data (https://github.com/ansible-collections/community.general/issues/888,
|
||||
https://github.com/ansible-collections/community.general/pull/11812).
|
||||
- smartos_image_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- snmp_facts - the module now also supports pysnmp >= 7.1 (https://github.com/ansible-collections/community.general/issues/8852,
|
||||
https://github.com/ansible-collections/community.general/pull/11683).
|
||||
- sorcery - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running commands
|
||||
that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11767).
|
||||
- supervisorctl - normalize locale environment for ``run_command()`` calls
|
||||
to ``LANGUAGE=C``, ``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- svc - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- swdepot - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11780).
|
||||
- syspatch - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- sysrc - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- sysupgrade - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11768).
|
||||
- terraform - ensure ``LANGUAGE=C`` and ``LC_ALL=C`` are set when running
|
||||
commands that parse output (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11765).
|
||||
- timezone - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- udm_user - allow to use passlib instead of legacycrypt for Python 3.13+
|
||||
(https://github.com/ansible-collections/community.general/issues/4690, https://github.com/ansible-collections/community.general/pull/11860).
|
||||
- udm_user - fix alias-to-canonical parameter name mismatch that caused all
|
||||
camelCase-aliased parameters such as ``display_name`` and ``primary_group``
|
||||
to be silently ignored (https://github.com/ansible-collections/community.general/issues/2950,
|
||||
https://github.com/ansible-collections/community.general/issues/3691, https://github.com/ansible-collections/community.general/pull/11859).
|
||||
- ufw - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- xattr - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- xbps - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11781).
|
||||
- xenserver_guest - fix an issue where booting from ISO is not possible because
|
||||
CD-ROM device is placed in position above number 3. Position number 3 is
|
||||
now reserved for CD-ROM device and cannot be occupied by a disk (https://github.com/ansible-collections/community.general/issues/11624,
|
||||
https://github.com/ansible-collections/community.general/pull/11702).
|
||||
- yarn - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11776).
|
||||
- yum_versionlock - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11777).
|
||||
- zfs - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()`` calls
|
||||
to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zfs_delegate_admin - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zfs_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zpool_facts - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11778).
|
||||
- zypper - normalize locale environment for ``run_command()`` calls to ``LANGUAGE=C``,
|
||||
``LC_ALL=C`` (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11741).
|
||||
- zypper_repository - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11777).
|
||||
- zypper_repository_info - set ``LANGUAGE`` and ``LC_ALL`` to ``C`` in ``run_command()``
|
||||
calls to ensure locale-independent output parsing (https://github.com/ansible-collections/community.general/issues/11737,
|
||||
https://github.com/ansible-collections/community.general/pull/11782).
|
||||
minor_changes:
|
||||
- cobbler_sync - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- cobbler_system - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- composer - add ``force`` parameter; when ``command=create-project``, the
|
||||
module now checks whether a ``composer.json`` already exists in ``working_dir``
|
||||
and skips the command if so, making the task idempotent. Set ``force=true``
|
||||
to always run the command regardless (https://github.com/ansible-collections/community.general/issues/725,
|
||||
https://github.com/ansible-collections/community.general/pull/11689).
|
||||
- consul_kv - add ``ca_path`` option to specify a CA bundle for HTTPS connections
|
||||
(https://github.com/ansible-collections/community.general/pull/11817).
|
||||
- consul_kv lookup plugin - add ``ca_path`` option to specify a CA bundle
|
||||
for HTTPS connections (https://github.com/ansible-collections/community.general/issues/2876,
|
||||
https://github.com/ansible-collections/community.general/pull/11817).
|
||||
- dconf - add support for C(dbus-broker) (https://github.com/ansible-collections/community.general/issues/495,
|
||||
https://github.com/ansible-collections/community.general/pull/11772).
|
||||
- filesystem - migrate ``LVM.get_fs_size()`` to use ``CmdRunner``, ensuring
|
||||
locale-independent output parsing (https://github.com/ansible-collections/community.general/pull/11888).
|
||||
- flatpak - add new parameter ``from_url`` to install a flatpak from a ``.flatpakref``
|
||||
URL (https://github.com/ansible-collections/community.general/issues/4000,
|
||||
https://github.com/ansible-collections/community.general/pull/11748).
|
||||
- gem - refactor module to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11733).
|
||||
- homebrew_services - remove various redundancies including dead state validation,
|
||||
unused return values, and unnecessary locale environment variables (https://github.com/ansible-collections/community.general/pull/11839).
|
||||
- homebrew_tap - avoid redundant ``brew tap`` calls when processing multiple
|
||||
taps by fetching the tap list once upfront (https://github.com/ansible-collections/community.general/pull/11848).
|
||||
- ipa_dnsrecord - add ``exclusive`` parameter to allow appending values to
|
||||
existing records without replacing them (https://github.com/ansible-collections/community.general/issues/682,
|
||||
https://github.com/ansible-collections/community.general/pull/11694).
|
||||
- java_cert - support proxy authentication when ``https_proxy`` environment
|
||||
variable includes credentials (https://github.com/ansible-collections/community.general/issues/4126,
|
||||
https://github.com/ansible-collections/community.general/pull/11753).
|
||||
- jira - add ``cloud`` option to support Jira Cloud's new search endpoint
|
||||
``/rest/api/2/search/jql``, since the legacy ``/rest/api/2/search`` endpoint
|
||||
has been removed on Jira Cloud (https://github.com/ansible-collections/community.general/issues/10786,
|
||||
https://github.com/ansible-collections/community.general/pull/11701).
|
||||
- jira - when ``cloud=true``, user-type fields (``assignee``, ``reporter``,
|
||||
and any listed in the new ``custom_user_fields`` parameter) containing an
|
||||
email address are automatically resolved to Jira Cloud account IDs (https://github.com/ansible-collections/community.general/issues/11734,
|
||||
https://github.com/ansible-collections/community.general/pull/11735).
|
||||
- logrotate - adds optional ``backup`` parameter to create a backup of the
|
||||
existing configuration file before writing changes (https://github.com/ansible-collections/community.general/pull/11764).
|
||||
- lvg - migrate to ``CmdRunner``, removing direct ``run_command`` calls and
|
||||
``run_command_environ_update`` (https://github.com/ansible-collections/community.general/pull/11835).
|
||||
- lvm_pv - migrate to ``CmdRunner`` using shared runners from ``module_utils/_lvm``
|
||||
(https://github.com/ansible-collections/community.general/pull/11811).
|
||||
- lvol - migrate to ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11887).
|
||||
- manageiq module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- manageiq_alert_profiles - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- manageiq_alerts - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- oneview module utils - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- oneview_san_manager - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- opendj_backendprop - refactor to use ``CmdRunner`` (https://github.com/ansible-collections/community.general/pull/11728).
|
||||
- packet_device - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- packet_ip_subnet - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- pacman - add ``root``, ``cachedir``, and ``config`` options to support installing
|
||||
packages into an alternative root directory (https://github.com/ansible-collections/community.general/issues/438,
|
||||
https://github.com/ansible-collections/community.general/pull/11681).
|
||||
- parted - add ``unit_preserve_case`` option to control the case of the ``unit``
|
||||
field in the return value, fixing the round-trip use case where the returned
|
||||
unit is fed back as input (https://github.com/ansible-collections/community.general/issues/1860,
|
||||
https://github.com/ansible-collections/community.general/pull/11813).
|
||||
- pubnub_blocks - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- terraform - minor code cleanup (https://github.com/ansible-collections/community.general/pull/11879).
|
||||
- xenserver_guest - use ``enumerate()`` instead of manual index variable in
|
||||
``for`` loop (https://github.com/ansible-collections/community.general/pull/11721).
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 10786-jira-cloud-search.yml
|
||||
- 11487-ipa-host-fix-disable.yml
|
||||
- 11664-mssql-named-instance-port.yml
|
||||
- 11681-pacman-root-cachedir-config.yml
|
||||
- 11688-flatpak-fix-runtime-removal.yml
|
||||
- 11689-composer-create-project-idempotent.yml
|
||||
- 11698-ipa-failed-response.yml
|
||||
- 11702-xenserver_guest-cdrom-handling-fix.yml
|
||||
- 11717-fix-error-dnsttl.yml
|
||||
- 11721-xenserver-guest-codeqa.yml
|
||||
- 11728-opendj_backendprop-cmdrunner.yml
|
||||
- 11733-gem-cmd-runner.yml
|
||||
- 11734-jira-cloud-assignee-email-resolution.yml
|
||||
- 11738-run-command-locale-group3-batch1.yml
|
||||
- 11740-run-command-locale-group3-batch2.yml
|
||||
- 11741-run-command-locale-group3-batch3.yml
|
||||
- 11742-run-command-locale-nmcli.yml
|
||||
- 11748-flatpak-from-url.yml
|
||||
- 11750-pacemaker-wait-race-condition.yml
|
||||
- 11753-java-cert-proxy-auth.yml
|
||||
- 11754-mssql-script-params-substitution.yml
|
||||
- 11764-logrotate-fixes.yml
|
||||
- 11765-group4-locale.yml
|
||||
- 11767-group4-batch2-locale.yml
|
||||
- 11768-group5-batch1-locale.yml
|
||||
- 11771-incus-machinectl-run0-become-pty.yml
|
||||
- 11772-dconf-dbus-broker.yml
|
||||
- 11773-group5-batch2-locale.yml
|
||||
- 11774-group5-batch3-locale.yml
|
||||
- 11775-group5-batch4-locale.yml
|
||||
- 11776-group5-batch5-locale.yml
|
||||
- 11777-group5-batch6-locale.yml
|
||||
- 11778-group5-batch7-locale.yml
|
||||
- 11779-group5-batch8-locale.yml
|
||||
- 11780-group5-batch9-locale.yml
|
||||
- 11781-group5-batch10-locale.yml
|
||||
- 11782-group5-batch11-locale.yml
|
||||
- 11783-group5-batch12-locale.yml
|
||||
- 11784-group5-batch13-locale.yml
|
||||
- 11785-group5-batch14-locale.yml
|
||||
- 11786-group5-batch15-locale.yml
|
||||
- 11787-group5-batch16-locale.yml
|
||||
- 11811-lvm_pv-use-cmdrunner.yml
|
||||
- 11812-sefcontext-matchpathcon-cache-flush.yml
|
||||
- 11813-parted-unit-preserve-case.yml
|
||||
- 11817-consul-kv-ca-path.yml
|
||||
- 11823-lvol-lvm-version-regex.yml
|
||||
- 11824-locale-gen-gentoo.yml
|
||||
- 11825-iso-extract-leading-slash.yml
|
||||
- 11835-lvg-use-cmdrunner.yml
|
||||
- 11836-fixes.yml
|
||||
- 11837-iso-extract-umount-retry.yml
|
||||
- 11838-homebrew-cask-upgrade-latest.yml
|
||||
- 11839-homebrew-services-cleanup.yml
|
||||
- 11848-homebrew-tap-fixes.yml
|
||||
- 11849-homebrew-cask-brew-version.yml
|
||||
- 11850-homebrew-cask-sudo-password.yml
|
||||
- 11851-gitlab-project-members-ambiguous.yml
|
||||
- 11859-udm_user-param-name-fix.yml
|
||||
- 11860-udm_user-replace-crypt.yml
|
||||
- 11861-etcd3-lookup-https.yml
|
||||
- 11878-gitlab_project_variable-find_project.yml
|
||||
- 11879-convert-format-to-fstrings.yml
|
||||
- 11887-lvol-use-cmdrunner.yml
|
||||
- 11888-filesystem-use-cmdrunner.yml
|
||||
- 12.6.0.yml
|
||||
- 682-ipa-dnsrecord-solo.yml
|
||||
- 8852-snmp-facts-pysnmp7.yml
|
||||
- fix-nsupdate-gss-tsig.yml
|
||||
modules:
|
||||
- description: Manages snap interface connections.
|
||||
name: snap_connect
|
||||
namespace: ''
|
||||
release_date: '2026-04-20'
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
bugfixes:
|
||||
- scaleway_image_info, scaleway_ip_info, scaleway_organization_info, scaleway_security_group_info, scaleway_server_info, scaleway_snapshot_info, scaleway_volume_info - fix ``NoneType`` error when the Scaleway API returns an empty or non-JSON response body (https://github.com/ansible-collections/community.general/issues/11361, https://github.com/ansible-collections/community.general/pull/11918).
|
||||
2
changelogs/fragments/11909-fix-favicon-url.yml
Normal file
2
changelogs/fragments/11909-fix-favicon-url.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
minor_changes:
|
||||
- "mattermost, rocketchat, slack - update default ``icon_url`` to ansible favicon (https://github.com/ansible-collections/community.general/pull/11909)."
|
||||
@@ -0,0 +1,2 @@
|
||||
bugfixes:
|
||||
- crypttab - fix parsing of options whose value contains an equal sign (https://github.com/ansible-collections/community.general/issues/4963, https://github.com/ansible-collections/community.general/pull/11926).
|
||||
1
changelogs/fragments/12.6.1.yml
Normal file
1
changelogs/fragments/12.6.1.yml
Normal file
@@ -0,0 +1 @@
|
||||
release_summary: Regular bugfix release.
|
||||
@@ -8,6 +8,9 @@ sections:
|
||||
toctree:
|
||||
- filter_guide
|
||||
- test_guide
|
||||
- title: Deployment Guides
|
||||
toctree:
|
||||
- guide_ee
|
||||
- title: Technology Guides
|
||||
toctree:
|
||||
- guide_alicloud
|
||||
|
||||
114
docs/docsite/rst/guide_ee.rst
Normal file
114
docs/docsite/rst/guide_ee.rst
Normal file
@@ -0,0 +1,114 @@
|
||||
..
|
||||
Copyright (c) Ansible Project
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_ee:
|
||||
|
||||
Execution Environment Guide
|
||||
===========================
|
||||
|
||||
`Ansible Execution Environments <https://docs.ansible.com/projects/ansible/latest/getting_started_ee/index.html>`_
|
||||
(EEs) are container images that bundle ansible-core, collections, and their Python and system dependencies.
|
||||
They are the standard runtime for Red Hat Ansible Automation Platform and AWX, replacing the older virtualenv model.
|
||||
They can also be used outside of RHAAP and AWX by using `ansible-navigator <https://docs.ansible.com/projects/navigator/>`__, or by using ansible-runner directly.
|
||||
|
||||
What runs in the EE
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Only **controller-side plugins** run inside the EE. Their Python and system dependencies must be installed there.
|
||||
This includes: lookup plugins, inventory plugins, callback plugins, connection plugins, become plugins, and filter plugins.
|
||||
|
||||
Modules run on the managed nodes and are transferred there at runtime — their dependencies must be present on the
|
||||
target, not in the EE.
|
||||
|
||||
.. note::
|
||||
|
||||
Modules delegated to ``localhost`` (for example, those that interact with a remote API) are an exception:
|
||||
they run on the controller and their dependencies must therefore be available in the EE.
|
||||
|
||||
Why community.general does not provide EE metadata
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``community.general`` ships dozens of controller-side plugins covering a very broad range of technologies.
|
||||
Bundling the dependencies for all of them into a single EE image would almost certainly create irreconcilable
|
||||
conflicts — both within the collection and with other collections or tools (such as ``ansible-lint``) that
|
||||
share the same image.
|
||||
|
||||
For that reason, ``community.general`` does **not** provide Python or system package dependency metadata.
|
||||
Users are expected to build purpose-built, minimal EEs containing only the dependencies
|
||||
required by the specific plugins they actually use.
|
||||
|
||||
Finding the dependencies you need
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Every plugin that has external dependencies documents them in its ``requirements`` field.
|
||||
You can inspect those with ``ansible-doc``:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ansible-doc -t lookup community.general.some_lookup | grep -A 10 "REQUIREMENTS"
|
||||
|
||||
Or browse the plugin's documentation page on `docs.ansible.com <https://docs.ansible.com/ansible/latest/collections/community/general/>`_.
|
||||
|
||||
For example, a lookup plugin that wraps an external service might list:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
requirements:
|
||||
- some-python-library >= 1.2
|
||||
|
||||
An inventory plugin backed by a REST API might list:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
requirements:
|
||||
- requests
|
||||
- some-sdk
|
||||
|
||||
These are the packages you need to add to your EE.
|
||||
|
||||
Building a minimal EE with ansible-builder
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
`ansible-builder <https://docs.ansible.com/projects/builder/en/latest/>`_ is the standard tool for creating EEs.
|
||||
|
||||
Install it with:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ pip install ansible-builder
|
||||
|
||||
Create an ``execution-environment.yml`` **in your own project** — not inside ``community.general`` —
|
||||
that includes only the dependencies needed for the plugins you use:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
version: 3
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
python:
|
||||
- some-python-library>=1.2
|
||||
- requests
|
||||
system:
|
||||
- libxml2-devel [platform:rpm]
|
||||
|
||||
images:
|
||||
base_image:
|
||||
name: ghcr.io/ansible/community-ee-base:latest
|
||||
|
||||
Then build the image:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ansible-builder build -t my-custom-ee:latest
|
||||
|
||||
.. seealso::
|
||||
|
||||
- `ansible-builder documentation <https://docs.ansible.com/projects/builder/en/latest/>`_
|
||||
- `Building EEs with ansible-builder <https://ansible-builder.readthedocs.io/en/latest/definition/>`_
|
||||
- `Issue #2968 — original request for EE requirements support <https://github.com/ansible-collections/community.general/issues/2968>`_
|
||||
- `Issue #4512 — design discussion for EE support in community.general <https://github.com/ansible-collections/community.general/issues/4512>`_
|
||||
@@ -12,7 +12,7 @@ The inventory plugin :ansplugin:`community.general.iocage#inventory` gets the in
|
||||
|
||||
See:
|
||||
|
||||
* `iocage - A FreeBSD Jail Manager <https://iocage.readthedocs.io/en/latest>`_
|
||||
* `iocage - A FreeBSD Jail Manager <https://freebsd.github.io/iocage/>`_
|
||||
* `man iocage <https://man.freebsd.org/cgi/man.cgi?query=iocage>`_
|
||||
* `Jails and Containers <https://docs.freebsd.org/en/books/handbook/jails>`_
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ As root at the iocage host, create three VNET jails with a DHCP interface from t
|
||||
shell> iocage create --template ansible_client --name srv_3 bpf=1 dhcp=1 vnet=1
|
||||
srv_3 successfully created!
|
||||
|
||||
See: `Configuring a VNET Jail <https://iocage.readthedocs.io/en/latest/networking.html#configuring-a-vnet-jail>`_.
|
||||
See: `Configuring VNET <https://freebsd.github.io/iocage/networking.html#vimage-vnet>`_.
|
||||
|
||||
As admin at the controller, list the jails:
|
||||
|
||||
@@ -115,7 +115,7 @@ Optionally, create shared IP jails:
|
||||
| None | srv_3 | off | down | jail | 14.2-RELEASE-p3 | em0|10.1.0.103/24 | - | ansible_client | no |
|
||||
+------+-------+------+-------+------+-----------------+-------------------+-----+----------------+----------+
|
||||
|
||||
See: `Configuring a Shared IP Jail <https://iocage.readthedocs.io/en/latest/networking.html#configuring-a-shared-ip-jail>`_
|
||||
See: `Configuring a Shared IP Jail <https://freebsd.github.io/iocage/networking.html#shared-ip>`_
|
||||
|
||||
If iocage needs environment variable(s), use the option :ansopt:`community.general.iocage#inventory:env`. For example,
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 12.4.0
|
||||
version: 12.6.1
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -21,6 +21,7 @@ action_groups:
|
||||
keycloak:
|
||||
- keycloak_authentication
|
||||
- keycloak_authentication_required_actions
|
||||
- keycloak_authentication_v2
|
||||
- keycloak_authz_authorization_scope
|
||||
- keycloak_authz_custom_policy
|
||||
- keycloak_authz_permission
|
||||
@@ -371,6 +372,26 @@ plugin_routing:
|
||||
tombstone:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.hpilo_info instead.
|
||||
aix_devices:
|
||||
deprecation:
|
||||
removal_version: 15.0.0
|
||||
warning_text: Use ibm.power_aix.devices instead. The C(ibm.power_aix) collection is actively maintained by IBM.
|
||||
aix_filesystem:
|
||||
deprecation:
|
||||
removal_version: 15.0.0
|
||||
warning_text: Use ibm.power_aix.filesystem instead. The C(ibm.power_aix) collection is actively maintained by IBM.
|
||||
aix_inittab:
|
||||
deprecation:
|
||||
removal_version: 15.0.0
|
||||
warning_text: Use ibm.power_aix.inittab instead. The C(ibm.power_aix) collection is actively maintained by IBM.
|
||||
aix_lvg:
|
||||
deprecation:
|
||||
removal_version: 15.0.0
|
||||
warning_text: Use ibm.power_aix.lvg instead. The C(ibm.power_aix) collection is actively maintained by IBM.
|
||||
aix_lvol:
|
||||
deprecation:
|
||||
removal_version: 15.0.0
|
||||
warning_text: Use ibm.power_aix.lvol instead. The C(ibm.power_aix) collection is actively maintained by IBM.
|
||||
idrac_firmware:
|
||||
redirect: dellemc.openmanage.idrac_firmware
|
||||
idrac_redfish_facts:
|
||||
|
||||
@@ -82,9 +82,26 @@ options:
|
||||
- name: ansible_doas_prompt_l10n
|
||||
env:
|
||||
- name: ANSIBLE_DOAS_PROMPT_L10N
|
||||
allow_pipelining:
|
||||
description:
|
||||
- When set to V(true), do allow pipelining with ansible-core 2.19+.
|
||||
- This should only be used when doas is configured to not ask for a password (C(nopass)).
|
||||
type: boolean
|
||||
default: false
|
||||
version_added: 12.4.0
|
||||
ini:
|
||||
- section: doas_become_plugin
|
||||
key: allow_pipelining
|
||||
vars:
|
||||
- name: ansible_doas_allow_pipelining
|
||||
env:
|
||||
- name: ANSIBLE_DOAS_ALLOW_PIPELINING
|
||||
notes:
|
||||
- This become plugin does not work when connection pipelining is enabled. With ansible-core 2.19+, using it automatically
|
||||
disables pipelining. On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
|
||||
- This become plugin does not work when connection pipelining is enabled
|
||||
and doas requests a password.
|
||||
With ansible-core 2.19+, using this plugin automatically disables pipelining,
|
||||
unless O(allow_pipelining=true) is explicitly set by the user.
|
||||
On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
|
||||
"""
|
||||
|
||||
import re
|
||||
@@ -101,8 +118,11 @@ class BecomeModule(BecomeBase):
|
||||
missing = ("Authorization required",)
|
||||
|
||||
# See https://github.com/ansible-collections/community.general/issues/9977,
|
||||
# https://github.com/ansible/ansible/pull/78111
|
||||
pipelining = False
|
||||
# https://github.com/ansible/ansible/pull/78111,
|
||||
# https://github.com/ansible-collections/community.general/issues/11411
|
||||
@property
|
||||
def pipelining(self) -> bool: # type: ignore[override]
|
||||
return self.get_option("allow_pipelining")
|
||||
|
||||
def check_password_prompt(self, b_output):
|
||||
"""checks if the expected password prompt exists in b_output"""
|
||||
|
||||
@@ -124,7 +124,10 @@ class BecomeModule(BecomeBase):
|
||||
|
||||
flags = self.get_option("become_flags")
|
||||
user = self.get_option("become_user")
|
||||
return f"{become} -q shell {flags} {user}@ {self._build_success_command(cmd, shell)}"
|
||||
# SYSTEMD_COLORS=0 stops machinectl from appending ANSI reset
|
||||
# sequences (ESC[0m, ESC[J) after the child exits, which would
|
||||
# otherwise land after the module JSON and break result parsing.
|
||||
return f"SYSTEMD_COLORS=0 {become} -q shell {flags} {user}@ {self._build_success_command(cmd, shell)}"
|
||||
|
||||
def check_success(self, b_output):
|
||||
b_output = self.remove_ansi_codes(b_output)
|
||||
|
||||
@@ -60,6 +60,8 @@ options:
|
||||
type: string
|
||||
notes:
|
||||
- This plugin only works when a C(polkit) rule is in place.
|
||||
- This become plugin does not work when connection pipelining is enabled. With ansible-core 2.19+, using it automatically
|
||||
disables pipelining. On ansible-core 2.18 and before, pipelining must explicitly be disabled by the user.
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
@@ -91,6 +93,10 @@ class BecomeModule(BecomeBase):
|
||||
success = ("==== AUTHENTICATION COMPLETE ====",)
|
||||
require_tty = True # see https://github.com/ansible-collections/community.general/issues/6932
|
||||
|
||||
# See https://github.com/ansible/ansible/issues/81254,
|
||||
# https://github.com/ansible/ansible/pull/78111
|
||||
pipelining = False
|
||||
|
||||
@staticmethod
|
||||
def remove_ansi_codes(line):
|
||||
return ansi_color_codes.sub(b"", line)
|
||||
@@ -105,7 +111,11 @@ class BecomeModule(BecomeBase):
|
||||
flags = self.get_option("become_flags")
|
||||
user = self.get_option("become_user")
|
||||
|
||||
return f"{become} --user={user} {flags} {self._build_success_command(cmd, shell)}"
|
||||
# SYSTEMD_COLORS=0 stops run0 from emitting terminal control
|
||||
# sequences (window title OSC, ANSI reset) around the child
|
||||
# command, which would otherwise corrupt the module JSON and
|
||||
# break result parsing.
|
||||
return f"SYSTEMD_COLORS=0 {become} --user={user} {flags} {self._build_success_command(cmd, shell)}"
|
||||
|
||||
def check_success(self, b_output):
|
||||
b_output = self.remove_ansi_codes(b_output)
|
||||
|
||||
@@ -157,6 +157,8 @@ class CallbackModule(CallbackBase):
|
||||
msg = f"changed: {self._host_counter}/{self._host_total} [{result._host.get_name()}]"
|
||||
color = C.COLOR_CHANGED
|
||||
else:
|
||||
if not self._plugin_options.get("display_ok_hosts", True):
|
||||
return
|
||||
if delegated_vars:
|
||||
msg = f"ok: {self._host_counter}/{self._host_total} [{result._host.get_name()} -> {delegated_vars['ansible_host']}]"
|
||||
else:
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = """
|
||||
name: loganalytics_ingestion
|
||||
type: notification
|
||||
|
||||
@@ -131,12 +131,18 @@ class Connection(ConnectionBase):
|
||||
def _build_command(self, cmd) -> list[str]:
|
||||
"""build the command to execute on the incus host"""
|
||||
|
||||
# Force pseudo-terminal allocation if the active become plugin
|
||||
# requires one (e.g. community.general.machinectl), otherwise the
|
||||
# become helper runs without a controlling tty and silently fails.
|
||||
require_tty = self.become is not None and getattr(self.become, "require_tty", False)
|
||||
|
||||
exec_cmd: list[str] = [
|
||||
self._incus_cmd,
|
||||
"--project",
|
||||
self.get_option("project"),
|
||||
"exec",
|
||||
*(["-T"] if getattr(self._shell, "_IS_WINDOWS", False) else []),
|
||||
*(["-t"] if require_tty and not getattr(self._shell, "_IS_WINDOWS", False) else []),
|
||||
f"{self.get_option('remote')}:{self._instance()}",
|
||||
"--",
|
||||
]
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
name: accumulate
|
||||
short_description: Produce a list of accumulated sums of the input list contents
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
DOCUMENTATION:
|
||||
name: to_toml
|
||||
author:
|
||||
- Matt Williaks (@milliams)
|
||||
- Matt Williams (@milliams)
|
||||
version_added: 12.3.0
|
||||
short_description: Convert variable to TOML string
|
||||
description:
|
||||
|
||||
@@ -93,6 +93,7 @@ compose:
|
||||
"""
|
||||
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
from urllib.error import HTTPError
|
||||
|
||||
from ansible.errors import AnsibleParserError
|
||||
@@ -164,7 +165,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
self.display.vvv(f"Error returned: {error_body}")
|
||||
except Exception:
|
||||
error_body = {"status": None}
|
||||
if e.code == 404 and error_body.get("status") == "No objects found.":
|
||||
if e.code == HTTPStatus.NOT_FOUND and error_body.get("status") == "No objects found.":
|
||||
raise AnsibleParserError(
|
||||
"Host filter returned no data. Please confirm your host_filter value is valid"
|
||||
) from e
|
||||
@@ -173,15 +174,15 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
response_body = response.read()
|
||||
json_data = json.loads(response_body.decode("utf-8"))
|
||||
self.display.vvv(f"Returned Data: {json.dumps(json_data, indent=4, sort_keys=True)}")
|
||||
if 200 <= response.status <= 299:
|
||||
if HTTPStatus.OK <= response.status < HTTPStatus.MULTIPLE_CHOICES: # 2xx codes
|
||||
return json_data
|
||||
if response.status == 404 and json_data["status"] == "No objects found.":
|
||||
if response.status == HTTPStatus.NOT_FOUND and json_data["status"] == "No objects found.":
|
||||
raise AnsibleParserError(f"API returned no data -- Response: {response.status} - {json_data['status']}")
|
||||
if response.status == 401:
|
||||
if response.status == HTTPStatus.UNAUTHORIZED:
|
||||
raise AnsibleParserError(
|
||||
f"API was unable to complete query -- Response: {response.status} - {json_data['status']}"
|
||||
)
|
||||
if response.status == 500:
|
||||
if response.status == HTTPStatus.INTERNAL_SERVER_ERROR:
|
||||
raise AnsibleParserError(f"API Response - {json_data['status']} - {json_data['errors']}")
|
||||
raise AnsibleParserError(f"Unexpected data returned - {json_data['status']} - {json_data['errors']}")
|
||||
|
||||
|
||||
@@ -34,7 +34,8 @@ options:
|
||||
default: []
|
||||
host_domain:
|
||||
description:
|
||||
- Domain to append to the host FQDN.
|
||||
- Domain to append to the host.
|
||||
- This is also used when O(host_fqdn) is not set since community.general 12.5.0.
|
||||
type: string
|
||||
host_fqdn:
|
||||
description:
|
||||
@@ -170,9 +171,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
if self.get_option("host_fqdn"):
|
||||
host_name = f"{host_name}.{project}.{remote_name}"
|
||||
|
||||
domain = self.get_option("host_domain")
|
||||
if domain:
|
||||
host_name = f"{host_name}.{domain}"
|
||||
domain = self.get_option("host_domain")
|
||||
if domain:
|
||||
host_name = f"{host_name}.{domain}"
|
||||
|
||||
# Add some extra variables.
|
||||
host_vars = {}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
name: binary_file
|
||||
author: Felix Fontein (@felixfontein)
|
||||
|
||||
@@ -57,13 +57,24 @@ options:
|
||||
- If you use E(ANSIBLE_CONSUL_URL) this value is used from there.
|
||||
validate_certs:
|
||||
default: true
|
||||
description: Whether to verify the TLS connection or not.
|
||||
description:
|
||||
- Whether to verify the TLS connection or not.
|
||||
- Instead of setting this to V(false), please consider using O(ca_path) instead.
|
||||
type: bool
|
||||
env:
|
||||
- name: ANSIBLE_CONSUL_VALIDATE_CERTS
|
||||
ini:
|
||||
- section: lookup_consul
|
||||
key: validate_certs
|
||||
ca_path:
|
||||
description: The CA bundle to use for HTTPS connections.
|
||||
type: str
|
||||
version_added: "12.6.0"
|
||||
env:
|
||||
- name: ANSIBLE_CONSUL_CA_PATH
|
||||
ini:
|
||||
- section: lookup_consul
|
||||
key: ca_path
|
||||
client_cert:
|
||||
description: The client cert to verify the TLS connection.
|
||||
type: str
|
||||
@@ -146,13 +157,16 @@ class LookupModule(LookupBase):
|
||||
port = u.port
|
||||
|
||||
validate_certs = self.get_option("validate_certs")
|
||||
ca_path = self.get_option("ca_path")
|
||||
client_cert = self.get_option("client_cert")
|
||||
|
||||
verify = (ca_path or validate_certs) if validate_certs else False
|
||||
|
||||
values = []
|
||||
try:
|
||||
for term in terms:
|
||||
params = self.parse_params(term)
|
||||
consul_api = consul.Consul(host=host, port=port, scheme=scheme, verify=validate_certs, cert=client_cert)
|
||||
consul_api = consul.Consul(host=host, port=port, scheme=scheme, verify=verify, cert=client_cert)
|
||||
|
||||
results = consul_api.kv.get(
|
||||
params["key"],
|
||||
|
||||
@@ -34,6 +34,8 @@ options:
|
||||
V(https://hostname:2379), or V(<host>:<port>) form.
|
||||
- The V(host) part is overwritten by O(host) option, if defined.
|
||||
- The V(port) part is overwritten by O(port) option, if defined.
|
||||
- Note that specifying V(https://) in the endpoint URL does not by itself enable TLS. To connect to an HTTPS etcd3
|
||||
endpoint, you must provide O(ca_cert) (and optionally O(cert_cert) and O(cert_key)).
|
||||
env:
|
||||
- name: ETCDCTL_ENDPOINTS
|
||||
default: '127.0.0.1:2379'
|
||||
@@ -42,6 +44,8 @@ options:
|
||||
description:
|
||||
- Etcd3 listening client host.
|
||||
- Takes precedence over O(endpoints).
|
||||
- Must be a bare hostname or IP address without a URL scheme. If a V(https://) or V(http://) prefix is present,
|
||||
it will be stripped automatically.
|
||||
type: str
|
||||
port:
|
||||
description:
|
||||
@@ -51,6 +55,7 @@ options:
|
||||
ca_cert:
|
||||
description:
|
||||
- Etcd3 CA authority.
|
||||
- Required to enable TLS when connecting to an HTTPS etcd3 endpoint.
|
||||
env:
|
||||
- name: ETCDCTL_CACERT
|
||||
type: str
|
||||
@@ -87,9 +92,11 @@ options:
|
||||
type: str
|
||||
|
||||
notes:
|
||||
- O(host) and O(port) options take precedence over (endpoints) option.
|
||||
- O(host) and O(port) options take precedence over O(endpoints) option.
|
||||
- The recommended way to connect to etcd3 server is using E(ETCDCTL_ENDPOINT) environment variable and keep O(endpoints),
|
||||
O(host), and O(port) unused.
|
||||
- To connect to an HTTPS etcd3 endpoint, the O(ca_cert) option must be provided. Merely specifying V(https://) in
|
||||
O(endpoints) is not sufficient to enable TLS.
|
||||
seealso:
|
||||
- module: community.general.etcd3
|
||||
- plugin: community.general.etcd
|
||||
@@ -115,6 +122,10 @@ EXAMPLES = r"""
|
||||
- name: "connect to etcd3 with a client certificate"
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ lookup('community.general.etcd3', 'foo/bar', cert_cert='/etc/ssl/etcd/client.pem', cert_key='/etc/ssl/etcd/client.key') }}"
|
||||
|
||||
- name: "connect to etcd3 over HTTPS"
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ lookup('community.general.etcd3', 'foo/bar', endpoints='https://etcd.example.com:2379', ca_cert='/etc/ssl/etcd/ca.pem') }}"
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
@@ -185,19 +196,42 @@ class LookupModule(LookupBase):
|
||||
# etcd3 class expects host and port as connection parameters, so endpoints
|
||||
# must be mangled a bit to fit in this scheme.
|
||||
# so here we use a regex to extract server and port
|
||||
is_https = False
|
||||
match = re.compile(
|
||||
r"^(https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$"
|
||||
r"^(?P<scheme>https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$"
|
||||
).match(self.get_option("endpoints"))
|
||||
if match:
|
||||
if match.group("host"):
|
||||
client_params["host"] = match.group("host")
|
||||
if match.group("port"):
|
||||
client_params["port"] = match.group("port")
|
||||
if match.group("scheme") and match.group("scheme").startswith("https"):
|
||||
is_https = True
|
||||
|
||||
for opt in etcd3_cnx_opts:
|
||||
if self.get_option(opt):
|
||||
client_params[opt] = self.get_option(opt)
|
||||
|
||||
# strip URL scheme from host if present
|
||||
if "host" in client_params:
|
||||
host_match = re.match(r"^(?P<scheme>https?://)(?P<host>.+)$", client_params["host"])
|
||||
if host_match:
|
||||
display.warning(
|
||||
f"The host option contained a URL scheme '{host_match.group('scheme')}' which has been removed. "
|
||||
"Use a bare hostname or IP address for the host option. "
|
||||
"To enable TLS, provide the ca_cert option."
|
||||
)
|
||||
client_params["host"] = host_match.group("host")
|
||||
if host_match.group("scheme").startswith("https"):
|
||||
is_https = True
|
||||
|
||||
if is_https and not self.get_option("ca_cert"):
|
||||
display.warning(
|
||||
"An HTTPS endpoint was specified but ca_cert was not provided. "
|
||||
"The connection will be attempted without TLS. "
|
||||
"To enable TLS, provide the ca_cert option."
|
||||
)
|
||||
|
||||
cnx_log = dict(client_params)
|
||||
if "password" in cnx_log:
|
||||
cnx_log["password"] = "<redacted>"
|
||||
|
||||
@@ -97,6 +97,7 @@ except ImportError:
|
||||
|
||||
import json
|
||||
import time
|
||||
from http import HTTPStatus
|
||||
from urllib.error import HTTPError
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||
@@ -177,9 +178,9 @@ def post_request(generated_jwt, installation_id, api_base):
|
||||
display.vvv(f"Error returned: {error_body}")
|
||||
except Exception:
|
||||
error_body = {}
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
raise AnsibleError("Github return error. Please confirm your installation_id value is valid") from e
|
||||
elif e.code == 401:
|
||||
elif e.code == HTTPStatus.UNAUTHORIZED:
|
||||
raise AnsibleError("Github return error. Please confirm your private key is valid") from e
|
||||
raise AnsibleError(f"Unexpected data returned: {e} -- {error_body}") from e
|
||||
response_body = response.read()
|
||||
|
||||
@@ -9,6 +9,7 @@ author:
|
||||
- Roy Lenferink (@rlenferink)
|
||||
- Mark Ettema (@m-a-r-k-e)
|
||||
- Alexander Petrenz (@alpex8)
|
||||
- Christoph Fiehe (@cfiehe)
|
||||
name: merge_variables
|
||||
short_description: Merge variables whose names match a given pattern
|
||||
description:
|
||||
@@ -66,6 +67,81 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
version_added: 8.5.0
|
||||
dict_merge:
|
||||
description:
|
||||
- Behavior when encountering dictionary values.
|
||||
type: str
|
||||
default: deep
|
||||
choices:
|
||||
deep: Merge dictionaries recursively.
|
||||
shallow: Merge only top-level values.
|
||||
replace: Overwrite existing dictionaries.
|
||||
keep: Keep existing dictionaries.
|
||||
version_added: 12.5.0
|
||||
list_merge:
|
||||
description:
|
||||
- Behavior when encountering list values.
|
||||
type: str
|
||||
default: append
|
||||
choices:
|
||||
replace: Overwrite existing lists.
|
||||
keep: Keep existing lists.
|
||||
append: Append elements to the end of an existing list.
|
||||
prepend: Insert elements at the beginning of an existing list.
|
||||
merge: Take the index as key and merge each element.
|
||||
version_added: 12.5.0
|
||||
type_conflict_merge:
|
||||
description:
|
||||
- Merge strategy to apply on type conflicts.
|
||||
- This value is only considered in case of O(override=warn) or O(override=ignore).
|
||||
type: str
|
||||
default: replace
|
||||
choices:
|
||||
replace: Overwrite existing values.
|
||||
keep: Keep existing values.
|
||||
version_added: 12.5.0
|
||||
default_merge:
|
||||
description:
|
||||
- Merge strategy applied to other types.
|
||||
- This value is only considered in case of O(override=warn) or O(override=ignore).
|
||||
type: str
|
||||
default: replace
|
||||
choices:
|
||||
replace: Overwrite existing values.
|
||||
keep: Keep existing values.
|
||||
version_added: 12.5.0
|
||||
list_transformations:
|
||||
description:
|
||||
- List transformations applied to list types.
|
||||
- The definition order corresponds to the order in which these transformations are applied.
|
||||
- Elements can be a dict with the keys mentioned below or a string naming the transformation to apply.
|
||||
type: list
|
||||
elements: raw
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- Name of the list transformation.
|
||||
required: true
|
||||
type: str
|
||||
choices:
|
||||
flatten: Flatten lists, converting nested lists into single lists. Does not support any additional options.
|
||||
dedup: Remove duplicates from lists. Supported option is C(keep).
|
||||
options:
|
||||
description:
|
||||
- Options as key value pairs.
|
||||
type: dict
|
||||
suboptions:
|
||||
keep:
|
||||
description:
|
||||
- Determines which duplicates (if any) to keep.
|
||||
- Only valid in combination with the O(list_transformations[].name=dedup) list transformation.
|
||||
type: str
|
||||
default: first
|
||||
choices:
|
||||
first: Drop duplicates except for the first occurrence.
|
||||
last: Drop duplicates except for the last occurrence.
|
||||
default: []
|
||||
version_added: 12.5.0
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
@@ -88,6 +164,32 @@ testb__test_dict:
|
||||
ports:
|
||||
- 3
|
||||
|
||||
testa_low_dict__test:
|
||||
a:
|
||||
a:
|
||||
x: low_value
|
||||
y: low_value
|
||||
list:
|
||||
- low_value
|
||||
b:
|
||||
- 1
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
testb_high_dict__test:
|
||||
a:
|
||||
a:
|
||||
y: high_value
|
||||
z: high_value
|
||||
list:
|
||||
- high_value
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
- 4
|
||||
- '5': value
|
||||
|
||||
# Merge variables that end with '__test_dict' and store the result in a variable 'example_a'
|
||||
example_a: "{{ lookup('community.general.merge_variables', '__test_dict', pattern_type='suffix') }}"
|
||||
|
||||
@@ -105,6 +207,56 @@ example_b: "{{ lookup('community.general.merge_variables', '^.+__test_list$', in
|
||||
# - "list init item 2"
|
||||
# - "test a item 1"
|
||||
# - "test b item 1"
|
||||
|
||||
# Shallow merge variables that end with '__test', insert list elements at the beginning of the list,
|
||||
# remove duplicates from lists (keep the first occurrence), and store the result in a variable 'example_c'
|
||||
example_c: "{{
|
||||
lookup(
|
||||
'community.general.merge_variables',
|
||||
'^.+__test$',
|
||||
dict_merge='shallow',
|
||||
list_merge='prepend',
|
||||
list_transformations=['dedup']) }}"
|
||||
|
||||
# The variable example_c now contains:
|
||||
# a:
|
||||
# a:
|
||||
# y: high_value
|
||||
# z: high_value
|
||||
# list:
|
||||
# - high_value
|
||||
# b:
|
||||
# - 3
|
||||
# - 4
|
||||
# - '5': value
|
||||
# - 1
|
||||
# - 2
|
||||
|
||||
# Deep merge variables that end with '__test', merge list elements by index, ignore overrides, apply the strategies
|
||||
# 'keep' for type conflicts and 'replace' for other types, and store the result in a variable 'example_d'
|
||||
example_d: "{{
|
||||
lookup(
|
||||
'community.general.merge_variables',
|
||||
'^.+__test$',
|
||||
dict_merge='deep',
|
||||
list_merge='merge',
|
||||
override='ignore',
|
||||
type_conflict_merge='keep',
|
||||
default_merge='replace') }}"
|
||||
|
||||
# The variable example_d now contains:
|
||||
# a:
|
||||
# a:
|
||||
# x: low_value
|
||||
# y: high_value
|
||||
# list:
|
||||
# - high_value
|
||||
# z: high_value
|
||||
# b:
|
||||
# - 3
|
||||
# - 4
|
||||
# - 4
|
||||
# - 3
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
@@ -114,16 +266,23 @@ _raw:
|
||||
elements: raw
|
||||
"""
|
||||
|
||||
|
||||
import re
|
||||
import typing as t
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.utils.display import Display
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from collections.abc import Callable
|
||||
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
def _verify_and_get_type(variable):
|
||||
def _verify_and_get_type(variable: t.Any) -> str:
|
||||
if isinstance(variable, list):
|
||||
return "list"
|
||||
elif isinstance(variable, dict):
|
||||
@@ -133,12 +292,17 @@ def _verify_and_get_type(variable):
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
def run(self, terms: list[str], variables: dict[str, t.Any], **kwargs) -> list[t.Any]:
|
||||
self.set_options(direct=kwargs)
|
||||
initial_value = self.get_option("initial_value", None)
|
||||
self._override = self.get_option("override", "error")
|
||||
self._override_behavior = self.get_option("override", "error")
|
||||
self._pattern_type = self.get_option("pattern_type", "regex")
|
||||
self._groups = self.get_option("groups", None)
|
||||
self._dict_merge = self.get_option("dict_merge", "deep")
|
||||
self._list_merge = self.get_option("list_merge", "append")
|
||||
self._type_conflict_merge = self.get_option("type_conflict_merge", "replace")
|
||||
self._default_merge = self.get_option("default_merge", "replace")
|
||||
self._list_transformations = self.get_option("list_transformations", [])
|
||||
|
||||
ret = []
|
||||
for term in terms:
|
||||
@@ -158,25 +322,25 @@ class LookupModule(LookupBase):
|
||||
|
||||
return ret
|
||||
|
||||
def _is_host_in_allowed_groups(self, host_groups):
|
||||
def _is_host_in_allowed_groups(self, host_groups: list[str]) -> bool:
|
||||
if "all" in self._groups:
|
||||
return True
|
||||
|
||||
group_intersection = [host_group_name for host_group_name in host_groups if host_group_name in self._groups]
|
||||
return bool(group_intersection)
|
||||
|
||||
def _var_matches(self, key, search_pattern):
|
||||
def _var_matches(self, key: str, search_pattern: str) -> bool:
|
||||
if self._pattern_type == "prefix":
|
||||
return key.startswith(search_pattern)
|
||||
elif self._pattern_type == "suffix":
|
||||
return key.endswith(search_pattern)
|
||||
elif self._pattern_type == "regex":
|
||||
matcher = re.compile(search_pattern)
|
||||
return matcher.search(key)
|
||||
return matcher.search(key) is not None
|
||||
|
||||
return False
|
||||
|
||||
def _merge_vars(self, search_pattern, initial_value, variables):
|
||||
def _merge_vars(self, search_pattern: str, initial_value: t.Any, variables: dict[str, t.Any]) -> t.Any:
|
||||
display.vvv(f"Merge variables with {self._pattern_type}: {search_pattern}")
|
||||
var_merge_names = sorted([key for key in variables.keys() if self._var_matches(key, search_pattern)])
|
||||
display.vvv(f"The following variables will be merged: {var_merge_names}")
|
||||
@@ -187,11 +351,42 @@ class LookupModule(LookupBase):
|
||||
prev_var_type = _verify_and_get_type(initial_value)
|
||||
result = initial_value
|
||||
|
||||
builder = (
|
||||
MergerBuilder()
|
||||
.with_type_strategy(list, ListMergeStrategies.from_name(self._list_merge))
|
||||
.with_type_conflict_strategy(BaseMergeStrategies.from_name(self._type_conflict_merge))
|
||||
.with_default_strategy(BaseMergeStrategies.from_name(self._default_merge))
|
||||
.with_override_behavior(self._override_behavior)
|
||||
)
|
||||
|
||||
if self._dict_merge == "deep":
|
||||
builder.with_type_strategy(dict, DictMergeStrategies.Merge())
|
||||
elif self._dict_merge == "shallow":
|
||||
builder.with_shallow_merge()
|
||||
else:
|
||||
builder.with_type_strategy(dict, DictMergeStrategies.from_name(self._dict_merge))
|
||||
|
||||
for transformation in self._list_transformations:
|
||||
if isinstance(transformation, str):
|
||||
builder.with_transformation(list, ListTransformations.from_name(transformation))
|
||||
elif isinstance(transformation, dict):
|
||||
name = transformation["name"]
|
||||
options = transformation.get("options", {})
|
||||
builder.with_transformation(list, ListTransformations.from_name(name, **options))
|
||||
else:
|
||||
raise AnsibleError(
|
||||
f"Transformations must be specified through values of type 'str' or 'dict', but a value of type '{type(transformation)}' was given"
|
||||
)
|
||||
|
||||
merger = builder.build()
|
||||
|
||||
if self._templar is None:
|
||||
raise AnsibleError("Templar is not available")
|
||||
|
||||
templar = self._templar.copy_with_new_env(available_variables=variables)
|
||||
|
||||
for var_name in var_merge_names:
|
||||
temp_templar = self._templar.copy_with_new_env(
|
||||
available_variables=variables
|
||||
) # tmp. switch renderer to context of current variables
|
||||
var_value = temp_templar.template(variables[var_name]) # Render jinja2 templates
|
||||
var_value = templar.template(variables[var_name]) # Render jinja2 templates
|
||||
var_type = _verify_and_get_type(var_value)
|
||||
|
||||
if prev_var_type is None:
|
||||
@@ -203,29 +398,271 @@ class LookupModule(LookupBase):
|
||||
result = var_value
|
||||
continue
|
||||
|
||||
if var_type == "dict":
|
||||
result = self._merge_dict(var_value, result, [var_name])
|
||||
else: # var_type == "list"
|
||||
result += var_value
|
||||
result = merger.merge(path=[var_name], left=result, right=var_value)
|
||||
|
||||
return result
|
||||
|
||||
def _merge_dict(self, src, dest, path):
|
||||
for key, value in src.items():
|
||||
if isinstance(value, dict):
|
||||
node = dest.setdefault(key, {})
|
||||
self._merge_dict(value, node, path + [key])
|
||||
elif isinstance(value, list) and key in dest:
|
||||
dest[key] += value
|
||||
|
||||
class MergeStrategy(ABC):
|
||||
@abstractmethod
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class MergeStrategies:
|
||||
@classmethod
|
||||
def from_name(cls, name: str, *args, **kwargs) -> MergeStrategy:
|
||||
if name in cls.strategies:
|
||||
return cls.strategies[name](*args, **kwargs)
|
||||
else:
|
||||
raise AnsibleError(f"Unknown merge strategy '{name}'")
|
||||
|
||||
strategies: dict[str, Callable[..., t.Any]] = {}
|
||||
|
||||
|
||||
class BaseMergeStrategies(MergeStrategies):
|
||||
class Replace(MergeStrategy):
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
return right
|
||||
|
||||
class Keep(MergeStrategy):
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
return left
|
||||
|
||||
strategies = {
|
||||
"replace": Replace,
|
||||
"keep": Keep,
|
||||
}
|
||||
|
||||
|
||||
class DictMergeStrategies(MergeStrategies):
|
||||
class Merge(MergeStrategy):
|
||||
def merge(
|
||||
self, merger: ObjectMerger, path: list[str], left: dict[str, t.Any], right: dict[str, t.Any]
|
||||
) -> dict[str, t.Any]:
|
||||
result = left
|
||||
for key, value in right.items():
|
||||
if key not in result:
|
||||
result[key] = value
|
||||
else:
|
||||
path.append(key)
|
||||
merged = merger.merge(path=path, left=result[key], right=value)
|
||||
merger.before_override(path=path, old_value=result[key], new_value=merged)
|
||||
result[key] = merged
|
||||
|
||||
return result
|
||||
|
||||
strategies = {
|
||||
"merge": Merge,
|
||||
"replace": BaseMergeStrategies.Replace,
|
||||
"keep": BaseMergeStrategies.Keep,
|
||||
}
|
||||
|
||||
|
||||
class ListMergeStrategies(MergeStrategies):
|
||||
class Append(MergeStrategy):
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
|
||||
return left + right
|
||||
|
||||
class Prepend(MergeStrategy):
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
|
||||
return right + left
|
||||
|
||||
class Merge(MergeStrategy):
|
||||
def merge(self, merger: ObjectMerger, path: list[str], left: list[t.Any], right: list[t.Any]) -> list[t.Any]:
|
||||
result = left
|
||||
for i, value in enumerate(right):
|
||||
if i >= len(result):
|
||||
result.extend(right[i:])
|
||||
break
|
||||
|
||||
path.append(str(i))
|
||||
merged = merger.merge(path=path, left=result[i], right=value)
|
||||
merger.before_override(path=path, old_value=result[i], new_value=merged)
|
||||
result[i] = merged
|
||||
|
||||
return result
|
||||
|
||||
strategies = {
|
||||
"append": Append,
|
||||
"prepend": Prepend,
|
||||
"merge": Merge,
|
||||
"replace": BaseMergeStrategies.Replace,
|
||||
"keep": BaseMergeStrategies.Keep,
|
||||
}
|
||||
|
||||
|
||||
class Transformation(ABC):
|
||||
@abstractmethod
|
||||
def transform(self, merger: ObjectMerger, value: t.Any) -> t.Any:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Transformations:
|
||||
@classmethod
|
||||
def from_name(cls, name: str, *args, **kwargs) -> Transformation:
|
||||
if name in cls.transformations:
|
||||
return cls.transformations[name](*args, **kwargs)
|
||||
else:
|
||||
raise AnsibleError(f"Unknown transformation '{name}'")
|
||||
|
||||
transformations: dict[str, Callable[..., t.Any]] = {}
|
||||
|
||||
|
||||
class ListTransformations(Transformations):
|
||||
class Dedup(Transformation):
|
||||
def __init__(self, keep: str = "first"):
|
||||
self.keep = keep
|
||||
|
||||
def transform(self, merger: ObjectMerger, value: list[t.Any]) -> list[t.Any]:
|
||||
result = []
|
||||
if self.keep == "first":
|
||||
for item in value:
|
||||
if item not in result:
|
||||
result.append(item)
|
||||
elif self.keep == "last":
|
||||
for item in reversed(value):
|
||||
if item not in result:
|
||||
result.insert(0, item)
|
||||
else:
|
||||
if (key in dest) and dest[key] != value:
|
||||
msg = f"The key '{key}' with value '{dest[key]}' will be overwritten with value '{value}' from '{'.'.join(path)}.{key}'"
|
||||
raise AnsibleError(
|
||||
f"Unsupported 'keep' value for deduplication transformation. Given was '{self.keep}', but must be either 'first' or 'last'"
|
||||
)
|
||||
|
||||
if self._override == "error":
|
||||
raise AnsibleError(msg)
|
||||
if self._override == "warn":
|
||||
display.warning(msg)
|
||||
return result
|
||||
|
||||
dest[key] = value
|
||||
class Flatten(Transformation):
|
||||
def transform(self, merger: ObjectMerger, value: list[t.Any]) -> list[t.Any]:
|
||||
result = []
|
||||
for item in value:
|
||||
if isinstance(item, list):
|
||||
result.extend(self.transform(merger, item))
|
||||
else:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
return dest
|
||||
transformations = {
|
||||
"dedup": Dedup,
|
||||
"flatten": Flatten,
|
||||
}
|
||||
|
||||
|
||||
class MergerBuilder:
|
||||
def __init__(self) -> None:
|
||||
self.type_strategies: list[tuple[type, MergeStrategy]] = []
|
||||
self.type_conflict_strategy: MergeStrategy = BaseMergeStrategies.Replace()
|
||||
self.default_strategy: MergeStrategy = BaseMergeStrategies.Replace()
|
||||
self.transformations: list[tuple[type, Transformation]] = []
|
||||
self.override_behavior: str = "error"
|
||||
self.shallow_merge: bool = False
|
||||
|
||||
def with_shallow_merge(self, shallow_merge: bool = True) -> MergerBuilder:
|
||||
self.shallow_merge = shallow_merge
|
||||
return self
|
||||
|
||||
def with_override_behavior(self, override_behavior: str) -> MergerBuilder:
|
||||
self.override_behavior = override_behavior
|
||||
return self
|
||||
|
||||
def with_type_strategy(self, cls, merge_strategy: MergeStrategy) -> MergerBuilder:
|
||||
self.type_strategies.append((cls, merge_strategy))
|
||||
return self
|
||||
|
||||
def with_default_strategy(self, merge_strategy: MergeStrategy) -> MergerBuilder:
|
||||
self.default_strategy = merge_strategy
|
||||
return self
|
||||
|
||||
def with_type_conflict_strategy(self, merge_strategy: MergeStrategy) -> MergerBuilder:
|
||||
self.type_conflict_strategy = merge_strategy
|
||||
return self
|
||||
|
||||
def with_transformation(self, cls, *args: Transformation) -> MergerBuilder:
|
||||
for transformation in args:
|
||||
self.transformations.append((cls, transformation))
|
||||
return self
|
||||
|
||||
def build(self) -> Merger:
|
||||
merger = ObjectMerger(
|
||||
type_strategies=self.type_strategies,
|
||||
type_conflict_strategy=self.type_conflict_strategy,
|
||||
default_strategy=self.default_strategy,
|
||||
transformations=self.transformations,
|
||||
override_behavior=self.override_behavior,
|
||||
)
|
||||
|
||||
if self.shallow_merge:
|
||||
return ShallowMerger(merger)
|
||||
|
||||
return merger
|
||||
|
||||
|
||||
class Merger(ABC):
|
||||
@abstractmethod
|
||||
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ObjectMerger(Merger):
|
||||
def __init__(
|
||||
self,
|
||||
type_strategies: list[tuple[type, MergeStrategy]],
|
||||
type_conflict_strategy: MergeStrategy,
|
||||
default_strategy: MergeStrategy,
|
||||
transformations: list[tuple[type, Transformation]],
|
||||
override_behavior: str,
|
||||
) -> None:
|
||||
self.type_strategies = type_strategies
|
||||
self.type_conflict_strategy = type_conflict_strategy
|
||||
self.default_strategy = default_strategy
|
||||
self.transformations = transformations
|
||||
self.override_behavior = override_behavior
|
||||
|
||||
def before_override(self, path: list[str], old_value: t.Any, new_value: t.Any) -> None:
|
||||
if (
|
||||
not isinstance(old_value, type(new_value))
|
||||
and not isinstance(new_value, type(old_value))
|
||||
or not isinstance(new_value, dict)
|
||||
and not isinstance(new_value, list)
|
||||
and old_value != new_value
|
||||
):
|
||||
# An override is regarded as a value type conflict or
|
||||
# when both values are neither dicts nor lists and
|
||||
# have different values
|
||||
msg = f"The key '{path[-1]}' with value '{old_value}' will be overwritten with value '{new_value}' from '{'.'.join(path)}'"
|
||||
if self.override_behavior == "error":
|
||||
raise AnsibleError(msg)
|
||||
elif self.override_behavior == "warn":
|
||||
display.warning(msg)
|
||||
|
||||
def transform(self, value: t.Any) -> t.Any:
|
||||
for cls, transformation in self.transformations:
|
||||
if isinstance(value, cls):
|
||||
value = transformation.transform(self, value)
|
||||
return value
|
||||
|
||||
def lookup_merge_strategy(self, left: t.Any, right: t.Any) -> MergeStrategy:
|
||||
for cls, merge_strategy in self.type_strategies:
|
||||
if isinstance(left, cls) and isinstance(right, cls):
|
||||
return merge_strategy
|
||||
|
||||
if not isinstance(left, type(right)) and not isinstance(right, type(left)):
|
||||
return self.type_conflict_strategy
|
||||
|
||||
return self.default_strategy
|
||||
|
||||
def apply_merge_strategy(self, merge_strategy: MergeStrategy, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
return self.transform(merge_strategy.merge(self, path, left, right))
|
||||
|
||||
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
return self.apply_merge_strategy(self.lookup_merge_strategy(left, right), path, left, right)
|
||||
|
||||
|
||||
class ShallowMerger(Merger):
|
||||
def __init__(self, merger: ObjectMerger) -> None:
|
||||
self.merger = merger
|
||||
|
||||
def merge(self, path: list[str], left: t.Any, right: t.Any) -> t.Any:
|
||||
if isinstance(left, dict) and isinstance(right, dict):
|
||||
return self.merger.apply_merge_strategy(DictMergeStrategies.Merge(), path, left, right)
|
||||
|
||||
return self.merger.merge(path, left, right)
|
||||
|
||||
@@ -259,38 +259,21 @@ from ansible_collections.community.general.plugins.module_utils._filelock import
|
||||
display = Display()
|
||||
|
||||
|
||||
# backhacked check_output with input for python 2.7
|
||||
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
|
||||
# note: contains special logic for calling 'pass', so not a drop-in replacement for check_output
|
||||
def check_output2(*popenargs, **kwargs):
|
||||
if "stdout" in kwargs:
|
||||
raise ValueError("stdout argument not allowed, it will be overridden.")
|
||||
if "stderr" in kwargs:
|
||||
raise ValueError("stderr argument not allowed, it will be overridden.")
|
||||
if "input" in kwargs:
|
||||
if "stdin" in kwargs:
|
||||
raise ValueError("stdin and input arguments may not both be used.")
|
||||
b_inputdata = to_bytes(kwargs["input"], errors="surrogate_or_strict")
|
||||
del kwargs["input"]
|
||||
kwargs["stdin"] = subprocess.PIPE
|
||||
else:
|
||||
b_inputdata = None
|
||||
process = subprocess.Popen(*popenargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
|
||||
try:
|
||||
b_out, b_err = process.communicate(b_inputdata)
|
||||
except Exception:
|
||||
process.kill()
|
||||
process.wait()
|
||||
raise
|
||||
retcode = process.poll()
|
||||
def run_backend_cmd(cmd, *, input=None, env=None):
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
input=to_bytes(input, errors="surrogate_or_strict") if input else None,
|
||||
env=env,
|
||||
)
|
||||
b_out, b_err = result.stdout, result.stderr
|
||||
retcode = result.returncode
|
||||
if retcode == 0 and (
|
||||
b"encryption failed: Unusable public key" in b_out or b"encryption failed: Unusable public key" in b_err
|
||||
):
|
||||
retcode = 78 # os.EX_CONFIG
|
||||
if retcode != 0:
|
||||
cmd = kwargs.get("args")
|
||||
if cmd is None:
|
||||
cmd = popenargs[0]
|
||||
raise subprocess.CalledProcessError(retcode, cmd, to_native(b_out + b_err, errors="surrogate_or_strict"))
|
||||
return b_out
|
||||
|
||||
@@ -304,7 +287,7 @@ class LookupModule(LookupBase):
|
||||
if self.realpass is None:
|
||||
try:
|
||||
passoutput = to_text(
|
||||
check_output2([self.pass_cmd, "--version"], env=self.env), errors="surrogate_or_strict"
|
||||
run_backend_cmd([self.pass_cmd, "--version"], env=self.env), errors="surrogate_or_strict"
|
||||
)
|
||||
self.realpass = "pass: the standard unix password manager" in passoutput
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -349,7 +332,7 @@ class LookupModule(LookupBase):
|
||||
|
||||
# Collect pass environment variables from the plugin's parameters.
|
||||
self.env = os.environ.copy()
|
||||
self.env["LANGUAGE"] = "C" # make sure to get errors in English as required by check_output2
|
||||
self.env["LANGUAGE"] = "C" # make sure to get errors in English as required by run_backend_cmd
|
||||
|
||||
if self.backend == "gopass":
|
||||
self.env["GOPASS_NO_REMINDER"] = "YES"
|
||||
@@ -371,7 +354,7 @@ class LookupModule(LookupBase):
|
||||
def check_pass(self):
|
||||
try:
|
||||
self.passoutput = to_text(
|
||||
check_output2([self.pass_cmd, "show"] + [self.passname], env=self.env), errors="surrogate_or_strict"
|
||||
run_backend_cmd([self.pass_cmd, "show"] + [self.passname], env=self.env), errors="surrogate_or_strict"
|
||||
).splitlines()
|
||||
self.password = self.passoutput[0]
|
||||
self.passdict = {}
|
||||
@@ -456,7 +439,7 @@ class LookupModule(LookupBase):
|
||||
msg += f"lookup_pass: old password was {self.password} (Updated on {datetime})\n"
|
||||
|
||||
try:
|
||||
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
|
||||
run_backend_cmd([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}") from e
|
||||
return newpass
|
||||
@@ -477,7 +460,7 @@ class LookupModule(LookupBase):
|
||||
msg += f"\nlookup_pass: First generated by ansible on {datetime}\n"
|
||||
|
||||
try:
|
||||
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
|
||||
run_backend_cmd([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}") from e
|
||||
|
||||
|
||||
45
plugins/module_utils/_crypt.py
Normal file
45
plugins/module_utils/_crypt.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2026, Alexei Znamensky <russoz@gmail.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ["CryptContext", "has_crypt_context"]
|
||||
|
||||
has_crypt_context = True
|
||||
try:
|
||||
from passlib.context import CryptContext
|
||||
|
||||
except ImportError:
|
||||
try:
|
||||
try:
|
||||
import crypt as _crypt_mod
|
||||
except ImportError:
|
||||
import legacycrypt as _crypt_mod
|
||||
|
||||
_SCHEME_TO_METHOD = {
|
||||
"sha512_crypt": _crypt_mod.METHOD_SHA512,
|
||||
"sha256_crypt": _crypt_mod.METHOD_SHA256,
|
||||
"md5_crypt": _crypt_mod.METHOD_MD5,
|
||||
"des_crypt": _crypt_mod.METHOD_CRYPT,
|
||||
}
|
||||
|
||||
class CryptContext: # type: ignore[no-redef]
|
||||
@staticmethod
|
||||
def verify(password, password_hash):
|
||||
return _crypt_mod.crypt(password, password_hash) == password_hash
|
||||
|
||||
@staticmethod
|
||||
def hash(password, scheme="sha512_crypt", rounds=10000):
|
||||
method = _SCHEME_TO_METHOD.get(scheme)
|
||||
if method is None:
|
||||
raise ValueError(f"Unsupported scheme: {scheme}")
|
||||
salt = _crypt_mod.mksalt(method, rounds=rounds)
|
||||
return _crypt_mod.crypt(password, salt)
|
||||
|
||||
except ImportError:
|
||||
|
||||
class CryptContext: # type: ignore[no-redef]
|
||||
pass
|
||||
|
||||
has_crypt_context = False
|
||||
496
plugins/module_utils/_lvm.py
Normal file
496
plugins/module_utils/_lvm.py
Normal file
@@ -0,0 +1,496 @@
|
||||
# Copyright (c) 2026, Alexei Znamensky <russoz@gmail.com>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
|
||||
# Do not use this from other collections or standalone plugins/modules!
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
# Options shared by the reporting commands: pvs, vgs, lvs (and pvdisplay in column mode).
|
||||
_REPORT_ARG_FORMATS = dict(
|
||||
noheadings=cmd_runner_fmt.as_fixed("--noheadings"),
|
||||
nosuffix=cmd_runner_fmt.as_fixed("--nosuffix"),
|
||||
readonly=cmd_runner_fmt.as_fixed("--readonly"),
|
||||
units=cmd_runner_fmt.as_opt_val("--units"),
|
||||
separator=cmd_runner_fmt.as_opt_val("--separator"),
|
||||
fields=cmd_runner_fmt.as_opt_val("-o"),
|
||||
select=cmd_runner_fmt.as_opt_val("--select"),
|
||||
)
|
||||
|
||||
|
||||
# ---- PV commands ----
|
||||
|
||||
|
||||
def pvs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvs). Used by: community.general.lvg, community.general.lvm_pv,
|
||||
community.general.lvm_pv_move_data, community.general.lvg_rename,
|
||||
community.general.filesystem.
|
||||
|
||||
Suggested arg_formats keys: noheadings nosuffix readonly units separator fields select devices
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvs",
|
||||
arg_formats=dict(
|
||||
**_REPORT_ARG_FORMATS,
|
||||
devices=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvcreate). Used by: community.general.lvg, community.general.lvm_pv,
|
||||
community.general.filesystem.
|
||||
|
||||
Suggested arg_formats keys: pv_options force yes device
|
||||
|
||||
Note: C(pv_options) accepts a pre-split list (e.g. from C(shlex.split())).
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvcreate",
|
||||
arg_formats=dict(
|
||||
pv_options=cmd_runner_fmt.as_list(),
|
||||
force=cmd_runner_fmt.as_bool("-f"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
device=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvchange). Used by: community.general.lvg, community.general.filesystem.
|
||||
|
||||
Suggested arg_formats keys: uuid yes device
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvchange",
|
||||
arg_formats=dict(
|
||||
uuid=cmd_runner_fmt.as_bool("-u"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
device=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvresize_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvresize). Used by: community.general.lvg, community.general.lvm_pv,
|
||||
community.general.filesystem.
|
||||
|
||||
Suggested arg_formats keys: set_size device
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvresize",
|
||||
arg_formats=dict(
|
||||
set_size=cmd_runner_fmt.as_opt_val("--setphysicalvolumesize"),
|
||||
device=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvremove). Used by: community.general.lvm_pv.
|
||||
|
||||
Suggested arg_formats keys: force device
|
||||
|
||||
Note: C(-y) is always passed (non-interactive). C(force=True) passes C(-ff),
|
||||
which removes PVs even when part of a VG.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command=["pvremove", "-y"],
|
||||
arg_formats=dict(
|
||||
force=cmd_runner_fmt.as_bool("-ff"),
|
||||
device=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvdisplay_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvdisplay). Used by: community.general.lvg.
|
||||
|
||||
Enables machine-readable output via C(--columns). Fields such as C(dev_size),
|
||||
C(pe_start), and C(vg_extent_size) are only available through C(pvdisplay),
|
||||
not C(pvs).
|
||||
|
||||
Suggested arg_formats keys: columns noheadings nosuffix units separator fields device
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvdisplay",
|
||||
arg_formats=dict(
|
||||
columns=cmd_runner_fmt.as_fixed("--columns"),
|
||||
**_REPORT_ARG_FORMATS,
|
||||
device=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def pvmove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(pvmove). Used by: community.general.lvm_pv_move_data.
|
||||
|
||||
Suggested arg_formats keys: auto_answer atomic autobackup verbosity source destination
|
||||
|
||||
Note: C(auto_answer) matches the O(auto_answer) module parameter.
|
||||
Pass C(autobackup) as a boolean; it maps to C(--autobackup y/n).
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="pvmove",
|
||||
arg_formats=dict(
|
||||
auto_answer=cmd_runner_fmt.as_bool("-y"),
|
||||
atomic=cmd_runner_fmt.as_bool("--atomic"),
|
||||
autobackup=cmd_runner_fmt.as_bool(["--autobackup", "y"], ["--autobackup", "n"], ignore_none=False),
|
||||
verbosity=cmd_runner_fmt.as_func(lambda v: [f"-{'v' * v}"] if v > 0 else []),
|
||||
source=cmd_runner_fmt.as_list(),
|
||||
destination=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
# ---- VG commands ----
|
||||
|
||||
|
||||
def vgs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgs). Used by: community.general.lvol, community.general.lvg,
|
||||
community.general.lvg_rename.
|
||||
|
||||
Suggested arg_formats keys: noheadings nosuffix readonly units separator fields select vg
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgs",
|
||||
arg_formats=dict(
|
||||
**_REPORT_ARG_FORMATS,
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgcreate). Used by: community.general.lvg.
|
||||
|
||||
Suggested args order: vg_options pesize setautoactivation vg pvs
|
||||
|
||||
Note: C(vg) and C(pvs) are positional — C(vg) must appear before C(pvs)
|
||||
in the args_order string. C(pvs) matches the O(pvs) module parameter in
|
||||
community.general.lvg. C(vg_options) accepts a pre-split list (e.g. from
|
||||
C(shlex.split())). C(setautoactivation) accepts C(True)/C(False)/C(None);
|
||||
C(None) omits the flag entirely (C(ignore_none=True)).
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgcreate",
|
||||
arg_formats=dict(
|
||||
vg_options=cmd_runner_fmt.as_list(),
|
||||
pesize=cmd_runner_fmt.as_opt_val("-s"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
setautoactivation=cmd_runner_fmt.as_bool(
|
||||
["--setautoactivation", "y"],
|
||||
["--setautoactivation", "n"],
|
||||
ignore_none=True,
|
||||
),
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgchange). Used by: community.general.lvg, community.general.lvg_rename.
|
||||
|
||||
Suggested arg_formats keys: activate uuid setautoactivation help vg
|
||||
|
||||
Note: C(activate) and C(setautoactivation) are passed as booleans and map to
|
||||
C(--activate y/n) and C(--setautoactivation y/n) respectively.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgchange",
|
||||
arg_formats=dict(
|
||||
activate=cmd_runner_fmt.as_bool(
|
||||
["--activate", "y"],
|
||||
["--activate", "n"],
|
||||
ignore_none=False,
|
||||
),
|
||||
uuid=cmd_runner_fmt.as_bool("-u"),
|
||||
setautoactivation=cmd_runner_fmt.as_bool(
|
||||
["--setautoactivation", "y"],
|
||||
["--setautoactivation", "n"],
|
||||
ignore_none=False,
|
||||
),
|
||||
help=cmd_runner_fmt.as_fixed("--help"),
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgextend_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgextend). Used by: community.general.lvg.
|
||||
|
||||
Suggested args order: vg pvs
|
||||
|
||||
Note: C(vg) must appear before C(pvs) in the args_order string.
|
||||
C(pvs) matches the O(pvs) module parameter in community.general.lvg,
|
||||
but callers must pass the subset of PVs to add explicitly.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgextend",
|
||||
arg_formats=dict(
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgreduce_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgreduce). Used by: community.general.lvg.
|
||||
|
||||
Suggested args order: force vg pvs
|
||||
|
||||
Note: C(vg) must appear before C(pvs) in the args_order string.
|
||||
C(pvs) matches the O(pvs) module parameter in community.general.lvg,
|
||||
but callers must pass the subset of PVs to remove explicitly.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgreduce",
|
||||
arg_formats=dict(
|
||||
force=cmd_runner_fmt.as_bool("--force"),
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgremove). Used by: community.general.lvg.
|
||||
|
||||
Suggested arg_formats keys: force yes vg
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgremove",
|
||||
arg_formats=dict(
|
||||
force=cmd_runner_fmt.as_bool("--force"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def vgrename_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(vgrename). Used by: community.general.lvg_rename.
|
||||
|
||||
Suggested args order: vg vg_new
|
||||
|
||||
Note: C(vg) (old name or UUID) must appear before C(vg_new) in the args_order string.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="vgrename",
|
||||
arg_formats=dict(
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
vg_new=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
# ---- LV commands ----
|
||||
|
||||
|
||||
def lvs_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvs). Used by: community.general.lvol.
|
||||
|
||||
Suggested arg_formats keys: all noheadings nosuffix units separator fields select vg
|
||||
|
||||
Note: C(all) includes hidden internal LVs such as thin pool metadata.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvs",
|
||||
arg_formats=dict(
|
||||
all=cmd_runner_fmt.as_fixed("-a"),
|
||||
**_REPORT_ARG_FORMATS,
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def lvcreate_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvcreate). Used by: community.general.lvol, community.general.lxc_container.
|
||||
|
||||
Suggested args order (normal LV): test yes lv size_L opts vg pvs
|
||||
Suggested args order (snapshot): test yes size_L is_snapshot lv opts vg
|
||||
Suggested args order (thin pool): test yes size_L opts thin vg pvs
|
||||
Suggested args order (thin vol): test yes lv size_V opts thin vg
|
||||
|
||||
Note: C(vg) must appear after all option args and before C(pvs).
|
||||
For snapshots and thin volumes, pass the origin as C(vg="{vg}/{lv}").
|
||||
C(opts) accepts a pre-split list (e.g. from C(shlex.split())).
|
||||
|
||||
Intentional mismatches with module parameters:
|
||||
- C(lv) matches O(lv) in community.general.lvol (the LV name, passed as C(-n lv)).
|
||||
- C(is_snapshot) is a boolean flag for C(-s); it differs from the O(snapshot)
|
||||
module parameter, which is a string holding the snapshot name.
|
||||
- C(thin) is a boolean flag for C(-T); it differs from the O(thinpool)
|
||||
module parameter, which is the pool name string.
|
||||
- C(size_L), C(size_l), C(size_V) cannot match the O(size) module parameter
|
||||
because one module param maps to three distinct CLI size options; callers
|
||||
must always pass the appropriate size key explicitly.
|
||||
- C(pvs) matches O(pvs) in community.general.lvol; callers must pass the value
|
||||
explicitly since it is the list of PV paths, not the full module param value.
|
||||
- C(opts) matches O(opts) in community.general.lvol; callers must pass the
|
||||
pre-split list explicitly.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvcreate",
|
||||
arg_formats=dict(
|
||||
test=cmd_runner_fmt.as_bool("--test"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
lv=cmd_runner_fmt.as_opt_val("-n"),
|
||||
size_L=cmd_runner_fmt.as_opt_val("-L"),
|
||||
size_l=cmd_runner_fmt.as_opt_val("-l"),
|
||||
size_V=cmd_runner_fmt.as_opt_val("-V"),
|
||||
is_snapshot=cmd_runner_fmt.as_bool("-s"),
|
||||
thin=cmd_runner_fmt.as_fixed("-T"),
|
||||
opts=cmd_runner_fmt.as_list(),
|
||||
vg=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def lvchange_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvchange). Used by: community.general.lvol.
|
||||
|
||||
Suggested arg_formats keys: active lv
|
||||
|
||||
Note: C(active) matches the O(active) module parameter in community.general.lvol.
|
||||
It maps to C(-ay) when true and C(-an) when false.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvchange",
|
||||
arg_formats=dict(
|
||||
active=cmd_runner_fmt.as_bool("-ay", "-an", ignore_none=False),
|
||||
lv=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def lvextend_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvextend). Used by: community.general.lvol.
|
||||
|
||||
Suggested args order: test resizefs size_L lv pvs
|
||||
(use size_l instead of size_L when sizing by extents or percentage)
|
||||
|
||||
Note: C(lv) must appear before C(pvs) in the args_order string.
|
||||
C(pvs) matches the O(pvs) module parameter in community.general.lvol.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvextend",
|
||||
arg_formats=dict(
|
||||
test=cmd_runner_fmt.as_bool("--test"),
|
||||
resizefs=cmd_runner_fmt.as_bool("--resizefs"),
|
||||
size_L=cmd_runner_fmt.as_opt_val("-L"),
|
||||
size_l=cmd_runner_fmt.as_opt_val("-l"),
|
||||
lv=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def lvreduce_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvreduce). Used by: community.general.lvol.
|
||||
|
||||
Suggested args order: test force resizefs size_L lv pvs
|
||||
(use size_l instead of size_L when sizing by extents or percentage)
|
||||
|
||||
Note: C(lv) must appear before C(pvs) in the args_order string.
|
||||
C(pvs) matches the O(pvs) module parameter in community.general.lvol.
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvreduce",
|
||||
arg_formats=dict(
|
||||
test=cmd_runner_fmt.as_bool("--test"),
|
||||
force=cmd_runner_fmt.as_bool("--force"),
|
||||
resizefs=cmd_runner_fmt.as_bool("--resizefs"),
|
||||
size_L=cmd_runner_fmt.as_opt_val("-L"),
|
||||
size_l=cmd_runner_fmt.as_opt_val("-l"),
|
||||
lv=cmd_runner_fmt.as_list(),
|
||||
pvs=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
def lvremove_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
"""
|
||||
Runner for C(lvremove). Used by: community.general.lvol, community.general.lxc_container.
|
||||
|
||||
Suggested arg_formats keys: test force yes lv
|
||||
"""
|
||||
return CmdRunner(
|
||||
module,
|
||||
command="lvremove",
|
||||
arg_formats=dict(
|
||||
test=cmd_runner_fmt.as_bool("--test"),
|
||||
force=cmd_runner_fmt.as_bool("--force"),
|
||||
yes=cmd_runner_fmt.as_bool("--yes"),
|
||||
lv=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
**kwargs,
|
||||
)
|
||||
@@ -35,6 +35,7 @@ class BtrfsCommands:
|
||||
|
||||
def __init__(self, module: AnsibleModule) -> None:
|
||||
self.__module = module
|
||||
self.__module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
self.__btrfs: str = self.__module.get_bin_path("btrfs", required=True)
|
||||
|
||||
def filesystem_show(self) -> list[dict[str, t.Any]]:
|
||||
|
||||
@@ -8,6 +8,7 @@ import copy
|
||||
import json
|
||||
import re
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
from urllib import error as urllib_error
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@@ -41,7 +42,7 @@ class RequestError(Exception):
|
||||
|
||||
|
||||
def handle_consul_response_error(response):
|
||||
if 400 <= response.status_code < 600:
|
||||
if response.status_code >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
raise RequestError(f"{response.status_code} {response.content}")
|
||||
|
||||
|
||||
@@ -242,9 +243,9 @@ class _ConsulModule:
|
||||
try:
|
||||
return self.get(url)
|
||||
except RequestError as e:
|
||||
if e.status == 404:
|
||||
if e.status == HTTPStatus.NOT_FOUND:
|
||||
return
|
||||
elif e.status == 403 and b"ACL not found" in e.response_data:
|
||||
elif e.status == HTTPStatus.FORBIDDEN and b"ACL not found" in e.response_data:
|
||||
return
|
||||
raise
|
||||
|
||||
@@ -321,7 +322,7 @@ class _ConsulModule:
|
||||
)
|
||||
raise
|
||||
|
||||
if 400 <= status < 600:
|
||||
if status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
raise RequestError(status, response_data)
|
||||
|
||||
if response_data:
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
@@ -60,7 +61,7 @@ class GandiLiveDNSAPI:
|
||||
resp, info = fetch_url(self.module, self.api_endpoint + api_call, headers=headers, data=data, method=method)
|
||||
|
||||
error_msg = ""
|
||||
if info["status"] >= 400 and (info["status"] != 404 or error_on_404):
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST and (info["status"] != HTTPStatus.NOT_FOUND or error_on_404):
|
||||
err_s = self.error_strings.get(info["status"], "")
|
||||
|
||||
error_msg = f"API Error {err_s}: {self._build_error_message(self.module, info)}"
|
||||
@@ -112,7 +113,7 @@ class GandiLiveDNSAPI:
|
||||
|
||||
records, status = self._gandi_api_call(url, error_on_404=False)
|
||||
|
||||
if status == 404:
|
||||
if status == HTTPStatus.NOT_FOUND:
|
||||
return []
|
||||
|
||||
if not isinstance(records, list):
|
||||
@@ -135,8 +136,8 @@ class GandiLiveDNSAPI:
|
||||
record, status = self._gandi_api_call(url, method="POST", payload=new_record)
|
||||
|
||||
if status in (
|
||||
200,
|
||||
201,
|
||||
HTTPStatus.OK,
|
||||
HTTPStatus.CREATED,
|
||||
):
|
||||
return new_record
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import re
|
||||
import time
|
||||
import traceback
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
THIRD_LIBRARIES_IMP_ERR = None
|
||||
try:
|
||||
@@ -70,7 +71,7 @@ def session_method_wrapper(f):
|
||||
raise HwcClientException(0, f"Parsing response to json failed, error: {ex}") from ex
|
||||
|
||||
code = r.status_code
|
||||
if code not in [200, 201, 202, 203, 204, 205, 206, 207, 208, 226]:
|
||||
if not (HTTPStatus.OK <= code < HTTPStatus.MULTIPLE_CHOICES): # not 2xx codes
|
||||
msg = ""
|
||||
for i in ["message", "error.message"]:
|
||||
try:
|
||||
@@ -81,7 +82,7 @@ def session_method_wrapper(f):
|
||||
else:
|
||||
msg = str(result)
|
||||
|
||||
if code == 404:
|
||||
if code == HTTPStatus.NOT_FOUND:
|
||||
raise HwcClientException404(msg)
|
||||
|
||||
raise HwcClientException(code, msg)
|
||||
|
||||
@@ -8,6 +8,7 @@ import copy
|
||||
import json
|
||||
import traceback
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
@@ -102,6 +103,7 @@ URL_REALM_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{group}/role-m
|
||||
|
||||
URL_CLIENTSECRET = "{url}/admin/realms/{realm}/clients/{id}/client-secret"
|
||||
|
||||
URL_AUTHENTICATION_AUTHENTICATOR_PROVIDERS = "{url}/admin/realms/{realm}/authentication/authenticator-providers"
|
||||
URL_AUTHENTICATION_FLOWS = "{url}/admin/realms/{realm}/authentication/flows"
|
||||
URL_AUTHENTICATION_FLOW = "{url}/admin/realms/{realm}/authentication/flows/{id}"
|
||||
URL_AUTHENTICATION_FLOW_COPY = "{url}/admin/realms/{realm}/authentication/flows/{copyfrom}/copy"
|
||||
@@ -418,7 +420,7 @@ class KeycloakAPI:
|
||||
validate_certs=self.validate_certs,
|
||||
)
|
||||
except HTTPError as e:
|
||||
if e.code != 401:
|
||||
if e.code != HTTPStatus.UNAUTHORIZED:
|
||||
raise e
|
||||
return e
|
||||
|
||||
@@ -440,7 +442,7 @@ class KeycloakAPI:
|
||||
r = make_request_catching_401(headers)
|
||||
except KeycloakError as e:
|
||||
# Token refresh returns 400 if token is expired/invalid, so continue on if we get a 400
|
||||
if e.authError is not None and e.authError.code != 400: # type: ignore # TODO!
|
||||
if e.authError is not None and e.authError.code != HTTPStatus.BAD_REQUEST: # type: ignore # TODO!
|
||||
raise e
|
||||
|
||||
if isinstance(r, Exception):
|
||||
@@ -465,7 +467,7 @@ class KeycloakAPI:
|
||||
r = make_request_catching_401(headers)
|
||||
except KeycloakError as e:
|
||||
# Token refresh returns 400 if token is expired/invalid, so continue on if we get a 400
|
||||
if e.authError is not None and e.authError.code != 400: # type: ignore # TODO!
|
||||
if e.authError is not None and e.authError.code != HTTPStatus.BAD_REQUEST: # type: ignore # TODO!
|
||||
raise e
|
||||
|
||||
if isinstance(r, Exception):
|
||||
@@ -496,7 +498,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(realm_info_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
|
||||
@@ -525,7 +527,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(realm_keys_metadata_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
|
||||
@@ -551,7 +553,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(realm_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain realm {realm}: {e}", exception=traceback.format_exc())
|
||||
@@ -718,7 +720,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(client_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain client {id} for realm {realm}: {e}")
|
||||
@@ -1310,7 +1312,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(clientscope_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch clientscope {cid} in realm {realm}: {e}")
|
||||
@@ -1434,7 +1436,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(protocolmapper_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch protocolmapper {pid} in realm {realm}: {e}")
|
||||
@@ -1641,7 +1643,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(clientsecret_url, method="POST")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain clientsecret of client {id} for realm {realm}: {e}")
|
||||
@@ -1661,7 +1663,7 @@ class KeycloakAPI:
|
||||
return self._request_and_deserialize(clientsecret_url, method="GET")
|
||||
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not obtain clientsecret of client {id} for realm {realm}: {e}")
|
||||
@@ -1695,7 +1697,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(groups_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch group {gid} in realm {realm}: {e}")
|
||||
@@ -1967,7 +1969,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(role_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch role {name} in realm {realm}: {e}")
|
||||
@@ -2169,7 +2171,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(role_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch role {name} in client {clientid} of realm {realm}: {e}")
|
||||
@@ -2252,6 +2254,19 @@ class KeycloakAPI:
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Unable to delete role {name} for client {clientid} in realm {realm}: {e}")
|
||||
|
||||
def get_authenticator_providers(self, realm: str = "master"):
|
||||
"""
|
||||
Get all available authenticator providers of the realm.
|
||||
:param realm: Realm.
|
||||
:return: List of authenticator provider representations.
|
||||
"""
|
||||
try:
|
||||
return self._request_and_deserialize(
|
||||
URL_AUTHENTICATION_AUTHENTICATOR_PROVIDERS.format(url=self.baseurl, realm=realm), method="GET"
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Unable get authenticator providers in realm {realm}: {e}")
|
||||
|
||||
def get_authentication_flow_by_alias(self, alias, realm: str = "master"):
|
||||
"""
|
||||
Get an authentication flow by its alias
|
||||
@@ -2273,6 +2288,35 @@ class KeycloakAPI:
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Unable get authentication flow {alias}: {e}")
|
||||
|
||||
def get_authentication_flow_by_id(self, id, realm: str = "master"):
|
||||
"""
|
||||
Get an authentication flow by its id
|
||||
:param id: id of the authentication flow to get.
|
||||
:param realm: Realm.
|
||||
:return: Authentication flow representation.
|
||||
"""
|
||||
flow_url = URL_AUTHENTICATION_FLOW.format(url=self.baseurl, realm=realm, id=id)
|
||||
|
||||
try:
|
||||
return json.load(self._request(flow_url, method="GET"))
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Could not get authentication flow {id} in realm {realm}: {e}")
|
||||
|
||||
def update_authentication_flow(self, id, config, realm: str = "master"):
|
||||
"""
|
||||
Updates an authentication flow
|
||||
:param id: id of the authentication flow to update.
|
||||
:param config: Authentication flow configuration.
|
||||
:param realm: Realm.
|
||||
:return: Authentication flow representation.
|
||||
"""
|
||||
flow_url = URL_AUTHENTICATION_FLOW.format(url=self.baseurl, realm=realm, id=id)
|
||||
|
||||
try:
|
||||
return self._request(flow_url, method="PUT", data=json.dumps(config))
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Could not get authentication flow {id} in realm {realm}: {e}")
|
||||
|
||||
def delete_authentication_flow_by_id(self, id, realm: str = "master"):
|
||||
"""
|
||||
Delete an authentication flow from Keycloak
|
||||
@@ -2378,6 +2422,22 @@ class KeycloakAPI:
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Unable to add authenticationConfig {executionId}: {e}")
|
||||
|
||||
def update_authentication_config(self, configId, authenticationConfig, realm: str = "master"):
|
||||
"""
|
||||
Updates an authentication config
|
||||
:param configId: id of the authentication config
|
||||
:param authenticationConfig: The authentication config
|
||||
:param realm: realm of authentication config
|
||||
"""
|
||||
try:
|
||||
self._request(
|
||||
URL_AUTHENTICATION_CONFIG.format(url=self.baseurl, realm=realm, id=configId),
|
||||
method="PUT",
|
||||
data=json.dumps(authenticationConfig),
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail_request(e, msg=f"Unable to update the authentication config {configId}: {e}")
|
||||
|
||||
def delete_authentication_config(self, configId, realm: str = "master"):
|
||||
"""Delete authenticator config
|
||||
|
||||
@@ -2597,7 +2657,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(idp_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch identity provider {alias} in realm {realm}: {e}")
|
||||
@@ -2682,7 +2742,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(mapper_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(
|
||||
@@ -2767,7 +2827,7 @@ class KeycloakAPI:
|
||||
try:
|
||||
return self._request_and_deserialize(comp_url, method="GET")
|
||||
except HTTPError as e:
|
||||
if e.code == 404:
|
||||
if e.code == HTTPStatus.NOT_FOUND:
|
||||
return None
|
||||
else:
|
||||
self.fail_request(e, msg=f"Could not fetch component {cid} in realm {realm}: {e}")
|
||||
|
||||
@@ -17,6 +17,7 @@ import re
|
||||
import socket
|
||||
import typing as t
|
||||
import uuid
|
||||
from http import HTTPStatus
|
||||
from urllib.parse import quote
|
||||
|
||||
from ansible.module_utils.basic import AnsibleFallbackNotFound, env_fallback
|
||||
@@ -90,7 +91,7 @@ class IPAClient:
|
||||
module=self.module, url=url, data=to_bytes(data), headers=headers, timeout=self.timeout
|
||||
)
|
||||
status_code = info["status"]
|
||||
if status_code not in [200, 201, 204]:
|
||||
if status_code not in (HTTPStatus.OK, HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
|
||||
self._fail("login", info["msg"])
|
||||
|
||||
self.headers = {"Cookie": info.get("set-cookie")}
|
||||
@@ -145,7 +146,7 @@ class IPAClient:
|
||||
use_gssapi=self.use_gssapi,
|
||||
)
|
||||
status_code = info["status"]
|
||||
if status_code not in [200, 201, 204]:
|
||||
if status_code not in (HTTPStatus.OK, HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
|
||||
self._fail(method, info["msg"])
|
||||
except Exception as e:
|
||||
self._fail(f"post {method}", f"{e}")
|
||||
@@ -158,6 +159,9 @@ class IPAClient:
|
||||
|
||||
if "result" in resp:
|
||||
result = resp.get("result")
|
||||
failed = result.get("failed")
|
||||
if failed:
|
||||
self._fail(f"response {method}", failed)
|
||||
if "result" in result:
|
||||
result = result.get("result")
|
||||
if isinstance(result, list):
|
||||
|
||||
@@ -152,7 +152,7 @@ def add_host_key(module, fqdn, port=22, key_type="rsa", create_dir=False):
|
||||
else:
|
||||
this_cmd = f"{keyscan_cmd} -t {key_type} {fqdn}"
|
||||
|
||||
rc, out, err = module.run_command(this_cmd)
|
||||
rc, out, err = module.run_command(this_cmd, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
|
||||
# ssh-keyscan gives a 0 exit code and prints nothing on timeout
|
||||
if rc != 0 or not out:
|
||||
msg = "failed to retrieve hostkey"
|
||||
|
||||
@@ -53,7 +53,6 @@ def check_client(module: AnsibleModule) -> None:
|
||||
|
||||
def validate_connection_params(module: AnsibleModule) -> dict[str, t.Any]:
|
||||
params: dict[str, t.Any] = module.params["manageiq_connection"]
|
||||
error_str = "missing required argument: manageiq_connection[{}]"
|
||||
url: str | None = params["url"]
|
||||
token: str | None = params["token"]
|
||||
username: str | None = params["username"]
|
||||
@@ -63,7 +62,7 @@ def validate_connection_params(module: AnsibleModule) -> dict[str, t.Any]:
|
||||
return params
|
||||
for arg in ["url", "username", "password"]:
|
||||
if params[arg] in (None, ""):
|
||||
module.fail_json(msg=error_str.format(arg))
|
||||
module.fail_json(msg=f"missing required argument: manageiq_connection[{arg}]")
|
||||
raise AssertionError("should be unreachable")
|
||||
|
||||
|
||||
@@ -218,9 +217,9 @@ class ManageIQPolicies:
|
||||
|
||||
def query_resource_profiles(self):
|
||||
"""Returns a set of the profile objects objects assigned to the resource"""
|
||||
url = "{resource_url}/policy_profiles?expand=resources"
|
||||
url = f"{self.resource_url}/policy_profiles?expand=resources"
|
||||
try:
|
||||
response = self.client.get(url.format(resource_url=self.resource_url))
|
||||
response = self.client.get(url)
|
||||
except Exception as e:
|
||||
msg = f"Failed to query {self.resource_type} policies: {e}"
|
||||
self.module.fail_json(msg=msg)
|
||||
@@ -235,9 +234,9 @@ class ManageIQPolicies:
|
||||
|
||||
def query_profile_policies(self, profile_id):
|
||||
"""Returns a set of the policy objects assigned to the resource"""
|
||||
url = "{api_url}/policy_profiles/{profile_id}?expand=policies"
|
||||
url = f"{self.api_url}/policy_profiles/{profile_id}?expand=policies"
|
||||
try:
|
||||
response = self.client.get(url.format(api_url=self.api_url, profile_id=profile_id))
|
||||
response = self.client.get(url)
|
||||
except Exception as e:
|
||||
msg = f"Failed to query {self.resource_type} policies: {e}"
|
||||
self.module.fail_json(msg=msg)
|
||||
@@ -370,9 +369,9 @@ class ManageIQTags:
|
||||
|
||||
def query_resource_tags(self):
|
||||
"""Returns a set of the tag objects assigned to the resource"""
|
||||
url = "{resource_url}/tags?expand=resources&attributes=categorization"
|
||||
url = f"{self.resource_url}/tags?expand=resources&attributes=categorization"
|
||||
try:
|
||||
response = self.client.get(url.format(resource_url=self.resource_url))
|
||||
response = self.client.get(url)
|
||||
except Exception as e:
|
||||
msg = f"Failed to query {self.resource_type} tags: {e}"
|
||||
self.module.fail_json(msg=msg)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import urllib.error as urllib_error
|
||||
from http import HTTPStatus
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from ansible.module_utils.basic import json
|
||||
@@ -93,7 +94,7 @@ def check_zone_domain(data, domain):
|
||||
"""
|
||||
exists = False
|
||||
|
||||
if data.status_code in [201, 200]:
|
||||
if data.status_code in (HTTPStatus.CREATED, HTTPStatus.OK):
|
||||
for zone_domain in data.json():
|
||||
if zone_domain["domain"] == domain:
|
||||
exists = True
|
||||
@@ -108,7 +109,7 @@ def check_zone(data, name):
|
||||
counter = 0
|
||||
exists = False
|
||||
|
||||
if data.status_code in [201, 200]:
|
||||
if data.status_code in (HTTPStatus.CREATED, HTTPStatus.OK):
|
||||
for zone in data.json():
|
||||
if zone["nickname"] == name:
|
||||
counter += 1
|
||||
|
||||
@@ -15,6 +15,7 @@ import json
|
||||
import time
|
||||
import typing as t
|
||||
import uuid
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.urls import open_url
|
||||
|
||||
@@ -158,7 +159,7 @@ def list_pritunl_organizations(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException("Could not retrieve organizations from Pritunl")
|
||||
else:
|
||||
for org in json.loads(response.read()):
|
||||
@@ -190,7 +191,7 @@ def list_pritunl_users(
|
||||
organization_id=organization_id,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException("Could not retrieve users from Pritunl")
|
||||
else:
|
||||
for user in json.loads(response.read()):
|
||||
@@ -220,7 +221,7 @@ def post_pritunl_organization(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException(f"Could not add organization {organization_name} to Pritunl")
|
||||
# The user PUT request returns the updated user object
|
||||
return json.loads(response.read())
|
||||
@@ -246,7 +247,7 @@ def post_pritunl_user(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException(f"Could not remove user {user_id} from organization {organization_id} from Pritunl")
|
||||
# user POST request returns an array of a single item,
|
||||
# so return this item instead of the list
|
||||
@@ -262,7 +263,7 @@ def post_pritunl_user(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException(f"Could not update user {user_id} from organization {organization_id} from Pritunl")
|
||||
# The user PUT request returns the updated user object
|
||||
return json.loads(response.read())
|
||||
@@ -279,7 +280,7 @@ def delete_pritunl_organization(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException(f"Could not remove organization {organization_id} from Pritunl")
|
||||
|
||||
return json.loads(response.read())
|
||||
@@ -297,7 +298,7 @@ def delete_pritunl_user(
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
if response.getcode() != HTTPStatus.OK:
|
||||
raise PritunlException(f"Could not remove user {user_id} from organization {organization_id} from Pritunl")
|
||||
|
||||
return json.loads(response.read())
|
||||
|
||||
@@ -9,6 +9,7 @@ import json
|
||||
import os
|
||||
import typing as t
|
||||
import uuid
|
||||
from http import HTTPStatus
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@@ -91,7 +92,7 @@ class OcapiUtils:
|
||||
use_proxy=True,
|
||||
timeout=self.timeout,
|
||||
)
|
||||
if resp.status != 204:
|
||||
if resp.status != HTTPStatus.NO_CONTENT:
|
||||
data = json.loads(resp.read())
|
||||
else:
|
||||
data = ""
|
||||
@@ -390,7 +391,7 @@ class OcapiUtils:
|
||||
job_uri = self.get_uri_with_slot_number_query_param(job_uri)
|
||||
response = self.get_request(job_uri)
|
||||
if response["ret"] is False:
|
||||
if response.get("status") == 404:
|
||||
if response.get("status") == HTTPStatus.NOT_FOUND:
|
||||
# Job not found -- assume 0%
|
||||
return {
|
||||
"ret": True,
|
||||
@@ -436,7 +437,7 @@ class OcapiUtils:
|
||||
return {"ret": False, "changed": False, "msg": "Cannot delete job because it is in progress."}
|
||||
|
||||
if response["ret"] is False:
|
||||
if response["status"] == 404:
|
||||
if response["status"] == HTTPStatus.NOT_FOUND:
|
||||
return {"ret": True, "changed": False, "msg": "Job already deleted."}
|
||||
return response
|
||||
if self.module.check_mode:
|
||||
@@ -445,9 +446,9 @@ class OcapiUtils:
|
||||
# Do the DELETE (unless we are in check mode)
|
||||
response = self.delete_request(job_uri, etag)
|
||||
if response["ret"] is False:
|
||||
if response["status"] == 404:
|
||||
if response["status"] == HTTPStatus.NOT_FOUND:
|
||||
return {"ret": True, "changed": False}
|
||||
elif response["status"] == 409:
|
||||
elif response["status"] == HTTPStatus.CONFLICT:
|
||||
return {"ret": False, "changed": False, "msg": "Cannot delete job because it is in progress."}
|
||||
return response
|
||||
return {"ret": True, "changed": True}
|
||||
|
||||
@@ -186,7 +186,6 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
|
||||
MSG_DELETED = "Resource deleted successfully."
|
||||
MSG_ALREADY_PRESENT = "Resource is already present."
|
||||
MSG_ALREADY_ABSENT = "Resource is already absent."
|
||||
MSG_DIFF_AT_KEY = "Difference found at key '{0}'. "
|
||||
|
||||
ONEVIEW_COMMON_ARGS = dict(
|
||||
config=dict(type="path"),
|
||||
@@ -407,7 +406,7 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
|
||||
if key not in resource2:
|
||||
if resource1[key] is not None:
|
||||
# Inexistent key is equivalent to exist with value None
|
||||
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
|
||||
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
|
||||
return False
|
||||
# If both values are null, empty or False it will be considered equal.
|
||||
elif not resource1[key] and not resource2[key]:
|
||||
@@ -415,15 +414,15 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
|
||||
elif isinstance(resource1[key], Mapping):
|
||||
# recursive call
|
||||
if not self.compare(resource1[key], resource2[key]):
|
||||
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
|
||||
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
|
||||
return False
|
||||
elif isinstance(resource1[key], list):
|
||||
# change comparison function to compare_list
|
||||
if not self.compare_list(resource1[key], resource2[key]):
|
||||
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
|
||||
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
|
||||
return False
|
||||
elif _standardize_value(resource1[key]) != _standardize_value(resource2[key]):
|
||||
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
|
||||
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
|
||||
return False
|
||||
|
||||
# Checks all keys in the second dict, looking for missing elements
|
||||
@@ -431,7 +430,7 @@ class OneViewModuleBase(metaclass=abc.ABCMeta):
|
||||
if key not in resource1:
|
||||
if resource2[key] is not None:
|
||||
# Inexistent key is equivalent to exist with value None
|
||||
self.module.log(self.MSG_DIFF_AT_KEY.format(key) + debug_resources)
|
||||
self.module.log(f"Difference found at key '{key}'. {debug_resources}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import sys
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
@@ -60,7 +61,12 @@ class Response:
|
||||
|
||||
@property
|
||||
def ok(self):
|
||||
return self.status_code in (200, 201, 202, 204)
|
||||
return self.status_code in (
|
||||
HTTPStatus.OK,
|
||||
HTTPStatus.CREATED,
|
||||
HTTPStatus.ACCEPTED,
|
||||
HTTPStatus.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class Online:
|
||||
|
||||
@@ -18,6 +18,7 @@ import typing as t
|
||||
|
||||
# (TODO: remove next line!)
|
||||
from datetime import datetime # noqa: F401, pylint: disable=unused-import
|
||||
from http import HTTPStatus
|
||||
from operator import eq
|
||||
|
||||
try:
|
||||
@@ -1381,7 +1382,7 @@ def delete_and_wait(
|
||||
except MaximumWaitTimeExceeded as ex:
|
||||
module.fail_json(msg=str(ex))
|
||||
except ServiceError as ex:
|
||||
if ex.status != 404:
|
||||
if ex.status != HTTPStatus.NOT_FOUND:
|
||||
module.fail_json(msg=ex.message)
|
||||
else:
|
||||
# While waiting for resource to get into terminated state, if the resource is not found.
|
||||
@@ -1405,9 +1406,9 @@ def delete_and_wait(
|
||||
# DNS API throws a 400 InvalidParameter when a zone id is provided for zone_name_or_id and if the zone
|
||||
# resource is not available, instead of the expected 404. So working around this for now.
|
||||
if isinstance(client, oci.dns.DnsClient):
|
||||
if ex.status == 400 and ex.code == "InvalidParameter":
|
||||
if ex.status == HTTPStatus.BAD_REQUEST and ex.code == "InvalidParameter":
|
||||
_debug(f"Resource {resource_type} with {kwargs_get} already deleted. So returning changed=False")
|
||||
elif ex.status != 404:
|
||||
elif ex.status != HTTPStatus.NOT_FOUND:
|
||||
module.fail_json(msg=ex.message)
|
||||
result[resource_type] = dict()
|
||||
return result
|
||||
@@ -1654,7 +1655,7 @@ def get_existing_resource(target_fn, module: AnsibleModule, **kwargs):
|
||||
response = call_with_backoff(target_fn, **kwargs)
|
||||
existing_resource = response.data
|
||||
except ServiceError as ex:
|
||||
if ex.status != 404:
|
||||
if ex.status != HTTPStatus.NOT_FOUND:
|
||||
module.fail_json(msg=ex.message)
|
||||
|
||||
return existing_resource
|
||||
@@ -1682,7 +1683,7 @@ def get_attached_instance_info(
|
||||
|
||||
# Pass ServiceError due to authorization issue in accessing volume attachments of a compartment
|
||||
except ServiceError as ex:
|
||||
if ex.status == 404:
|
||||
if ex.status == HTTPStatus.NOT_FOUND:
|
||||
pass
|
||||
|
||||
else:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import time
|
||||
import typing as t
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner, cmd_runner_fmt
|
||||
@@ -59,6 +60,22 @@ def get_pacemaker_maintenance_mode(runner: CmdRunner) -> bool:
|
||||
return bool(maintenance_mode_output)
|
||||
|
||||
|
||||
def wait_for_resource(runner: CmdRunner, cli_noun: str, name: str, wait: int, sleep_interval: int = 5) -> None:
|
||||
"""Poll ``pcs <cli_noun> status <name>`` until the resource reports Started or the wait budget expires.
|
||||
|
||||
Raises an exception if the resource does not reach the Started state within *wait* seconds.
|
||||
"""
|
||||
deadline = time.monotonic() + wait
|
||||
while True:
|
||||
with runner("cli_action state name") as ctx:
|
||||
rc, out, err = ctx.run(cli_action=cli_noun, state="status")
|
||||
if out and "Started" in out:
|
||||
return
|
||||
if time.monotonic() >= deadline:
|
||||
raise Exception(f"Timed out waiting {wait}s for {cli_noun} resource '{name}' to start")
|
||||
time.sleep(sleep_interval)
|
||||
|
||||
|
||||
def pacemaker_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
runner_command = ["pcs"]
|
||||
runner = CmdRunner(
|
||||
|
||||
@@ -52,12 +52,11 @@ def puppet_runner(module: AnsibleModule) -> CmdRunner:
|
||||
# If this can be replaced with ansible `timeout` parameter in playbook,
|
||||
# then this function could be removed.
|
||||
def _prepare_base_cmd():
|
||||
_tout_cmd = module.get_bin_path("timeout", False)
|
||||
if _tout_cmd:
|
||||
cmd = ["timeout", "-s", "9", module.params["timeout"], _puppet_cmd(module)]
|
||||
else:
|
||||
cmd = ["puppet"]
|
||||
return cmd
|
||||
if module.params["timeout"]:
|
||||
_tout_cmd = module.get_bin_path("timeout", False)
|
||||
if _tout_cmd:
|
||||
return ["timeout", "-s", "9", module.params["timeout"], _puppet_cmd(module)]
|
||||
return ["puppet"]
|
||||
|
||||
def noop_func(v):
|
||||
return ["--noop"] if module.check_mode or v else ["--no-noop"]
|
||||
|
||||
@@ -11,6 +11,7 @@ import random
|
||||
import string
|
||||
import time
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@@ -442,7 +443,7 @@ class RedfishUtils:
|
||||
"""
|
||||
msg = http_client.responses.get(error.code, "")
|
||||
data = None
|
||||
if error.code >= 400:
|
||||
if error.code >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
try:
|
||||
body = error.read().decode("utf-8")
|
||||
data = json.loads(body)
|
||||
@@ -1498,8 +1499,8 @@ class RedfishUtils:
|
||||
|
||||
response = self.post_request(self.root_uri + self.accounts_uri, payload)
|
||||
if not response["ret"]:
|
||||
if response.get("status") == 405:
|
||||
# if POST returned a 405, try to add via PATCH
|
||||
if response.get("status") == HTTPStatus.METHOD_NOT_ALLOWED:
|
||||
# if POST is not allowed, try to add via PATCH
|
||||
return self.add_user_via_patch(user)
|
||||
else:
|
||||
return response
|
||||
@@ -1549,8 +1550,8 @@ class RedfishUtils:
|
||||
|
||||
response = self.delete_request(self.root_uri + uri)
|
||||
if not response["ret"]:
|
||||
if response.get("status") == 405:
|
||||
# if DELETE returned a 405, try to delete via PATCH
|
||||
if response.get("status") == HTTPStatus.METHOD_NOT_ALLOWED:
|
||||
# if DELETE is not allowed, try to delete via PATCH
|
||||
return self.delete_user_via_patch(user, uri=uri, data=data)
|
||||
else:
|
||||
return response
|
||||
@@ -1868,7 +1869,7 @@ class RedfishUtils:
|
||||
|
||||
operation_results = {"status": None, "messages": [], "handle": None, "ret": True, "resets_requested": []}
|
||||
|
||||
if response.status == 204:
|
||||
if response.status == HTTPStatus.NO_CONTENT:
|
||||
# No content; successful, but nothing to return
|
||||
# Use the Redfish "Completed" enum from TaskState for the operation status
|
||||
operation_results["status"] = "Completed"
|
||||
@@ -1877,7 +1878,7 @@ class RedfishUtils:
|
||||
|
||||
# Determine the next handle, if any
|
||||
operation_results["handle"] = handle
|
||||
if response.status == 202:
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
# Task generated; get the task monitor URI
|
||||
operation_results["handle"] = response.getheader("Location", handle)
|
||||
|
||||
@@ -1891,15 +1892,15 @@ class RedfishUtils:
|
||||
else:
|
||||
# Error response body, which is a bit of a misnomer since it is used in successful action responses
|
||||
operation_results["status"] = "Completed"
|
||||
if response.status >= 400:
|
||||
if response.status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
operation_results["status"] = "Exception"
|
||||
operation_results["messages"] = data.get("error", {}).get("@Message.ExtendedInfo", [])
|
||||
else:
|
||||
# No response body (or malformed); build based on status code
|
||||
operation_results["status"] = "Completed"
|
||||
if response.status == 202:
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
operation_results["status"] = "New"
|
||||
elif response.status >= 400:
|
||||
elif response.status >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
operation_results["status"] = "Exception"
|
||||
|
||||
# Clear out the handle if the operation is complete
|
||||
|
||||
@@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import traceback
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.urls import fetch_url, url_argument_spec
|
||||
|
||||
@@ -74,13 +75,15 @@ def api_request(
|
||||
},
|
||||
)
|
||||
|
||||
if info["status"] == 403:
|
||||
_status = HTTPStatus(info["status"])
|
||||
|
||||
if _status == HTTPStatus.FORBIDDEN:
|
||||
module.fail_json(msg="Token authorization failed", execution_info=json.loads(info["body"]))
|
||||
elif info["status"] == 404:
|
||||
elif _status == HTTPStatus.NOT_FOUND:
|
||||
return None, info
|
||||
elif info["status"] == 409:
|
||||
elif _status == HTTPStatus.CONFLICT:
|
||||
module.fail_json(msg="Job executions limit reached", execution_info=json.loads(info["body"]))
|
||||
elif info["status"] >= 500:
|
||||
elif _status >= HTTPStatus.INTERNAL_SERVER_ERROR: # 5xx errors
|
||||
module.fail_json(msg="Rundeck API error", execution_info=json.loads(info["body"]))
|
||||
|
||||
try:
|
||||
|
||||
@@ -12,6 +12,7 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from ansible.module_utils.basic import env_fallback, missing_required_lib
|
||||
@@ -199,7 +200,12 @@ class Response:
|
||||
|
||||
@property
|
||||
def ok(self):
|
||||
return self.status_code in (200, 201, 202, 204)
|
||||
return self.status_code in (
|
||||
HTTPStatus.OK,
|
||||
HTTPStatus.CREATED,
|
||||
HTTPStatus.ACCEPTED,
|
||||
HTTPStatus.NO_CONTENT,
|
||||
)
|
||||
|
||||
|
||||
class Scaleway:
|
||||
@@ -231,10 +237,15 @@ class Scaleway:
|
||||
results = self.get(f"/{self.name}")
|
||||
|
||||
if not results.ok:
|
||||
api_response = results.json if results.json is not None else results.body
|
||||
message = api_response.get("message") if isinstance(api_response, dict) else api_response
|
||||
raise ScalewayException(
|
||||
f"Error fetching {self.name} ({self.module.params.get('api_url')}/{self.name}) [{results.status_code}: {results.json['message']}]"
|
||||
f"Error fetching {self.name} ({self.module.params.get('api_url')}/{self.name}) [{results.status_code}: {message}]"
|
||||
)
|
||||
|
||||
if results.json is None:
|
||||
raise ScalewayException(f"Scaleway API returned an empty or non-JSON response for {self.name}")
|
||||
|
||||
return results.json.get(self.name)
|
||||
|
||||
def _url_builder(self, path, params):
|
||||
@@ -302,7 +313,7 @@ class Scaleway:
|
||||
self.module.debug(f"fetch_state of resource: {resource['id']}")
|
||||
response = self.get(path=f"{self.api_path}/{resource['id']}")
|
||||
|
||||
if response.status_code == 404:
|
||||
if response.status_code == HTTPStatus.NOT_FOUND:
|
||||
return "absent"
|
||||
|
||||
if not response.ok:
|
||||
|
||||
@@ -45,6 +45,10 @@ def snap_runner(module: AnsibleModule, **kwargs) -> CmdRunner:
|
||||
info=cmd_runner_fmt.as_fixed("info"),
|
||||
dangerous=cmd_runner_fmt.as_bool("--dangerous"),
|
||||
version=cmd_runner_fmt.as_fixed("version"),
|
||||
_connect=cmd_runner_fmt.as_func(lambda v: ["connect", v]),
|
||||
_disconnect=cmd_runner_fmt.as_func(lambda v: ["disconnect", v]),
|
||||
_connections=cmd_runner_fmt.as_fixed("connections"),
|
||||
slot=cmd_runner_fmt.as_list(),
|
||||
),
|
||||
check_rc=False,
|
||||
**kwargs,
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.urls import basic_auth_header, fetch_url
|
||||
@@ -56,7 +57,7 @@ class BitbucketHelper:
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
if info["status"] == 200:
|
||||
if info["status"] == HTTPStatus.OK:
|
||||
self.access_token = content["access_token"]
|
||||
else:
|
||||
self.module.fail_json(msg=f"Failed to retrieve access token: {info}")
|
||||
|
||||
@@ -13,6 +13,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
@@ -116,7 +117,7 @@ class UTM:
|
||||
returns the info for an object in utm
|
||||
"""
|
||||
info, result = self._lookup_entry(self.module, self.request_url)
|
||||
if info["status"] >= 400:
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
self.module.fail_json(result=json.loads(info))
|
||||
else:
|
||||
if result is None:
|
||||
@@ -133,7 +134,7 @@ class UTM:
|
||||
|
||||
is_changed = False
|
||||
info, result = self._lookup_entry(self.module, self.request_url)
|
||||
if info["status"] >= 400:
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
self.module.fail_json(result=json.loads(info))
|
||||
else:
|
||||
data_as_json_string = self.module.jsonify(self.module.params)
|
||||
@@ -141,7 +142,7 @@ class UTM:
|
||||
response, info = fetch_url(
|
||||
self.module, self.request_url, method="POST", headers=combined_headers, data=data_as_json_string
|
||||
)
|
||||
if info["status"] >= 400:
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
self.module.fail_json(msg=json.loads(info["body"]))
|
||||
is_changed = True
|
||||
result = self._clean_result(json.loads(response.read()))
|
||||
@@ -154,7 +155,7 @@ class UTM:
|
||||
headers=combined_headers,
|
||||
data=data_as_json_string,
|
||||
)
|
||||
if info["status"] >= 400:
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
self.module.fail_json(msg=json.loads(info["body"]))
|
||||
is_changed = True
|
||||
result = self._clean_result(json.loads(response.read()))
|
||||
@@ -187,7 +188,7 @@ class UTM:
|
||||
headers={"Accept": "application/json", "X-Restd-Err-Ack": "all"},
|
||||
data=self.module.jsonify(self.module.params),
|
||||
)
|
||||
if info["status"] >= 400:
|
||||
if info["status"] >= HTTPStatus.BAD_REQUEST: # 4xx and 5xx errors
|
||||
self.module.fail_json(msg=json.loads(info["body"]))
|
||||
else:
|
||||
is_changed = True
|
||||
|
||||
@@ -13,6 +13,12 @@ module: aix_devices
|
||||
short_description: Manages AIX devices
|
||||
description:
|
||||
- This module discovers, defines, removes and modifies attributes of AIX devices.
|
||||
deprecated:
|
||||
removed_in: 15.0.0
|
||||
why: The module is not actively maintained.
|
||||
alternative: >-
|
||||
Use C(ibm.power_aix.devices) instead.
|
||||
See U(https://ibm.github.io/ansible-power-aix/modules/devices.html) for details.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -14,6 +14,12 @@ short_description: Configure LVM and NFS file systems for AIX
|
||||
description:
|
||||
- This module creates, removes, mount and unmount LVM and NFS file system for AIX using C(/etc/filesystems).
|
||||
- For LVM file systems is possible to resize a file system.
|
||||
deprecated:
|
||||
removed_in: 15.0.0
|
||||
why: The module is not actively maintained.
|
||||
alternative: >-
|
||||
Use C(ibm.power_aix.filesystem) instead.
|
||||
See U(https://ibm.github.io/ansible-power-aix/modules/filesystem.html) for details.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -13,6 +13,12 @@ module: aix_inittab
|
||||
short_description: Manages the C(inittab) on AIX
|
||||
description:
|
||||
- Manages the C(inittab) on AIX.
|
||||
deprecated:
|
||||
removed_in: 15.0.0
|
||||
why: The module is not actively maintained.
|
||||
alternative: >-
|
||||
Use C(ibm.power_aix.inittab) instead.
|
||||
See U(https://ibm.github.io/ansible-power-aix/modules/inittab.html) for details.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -13,6 +13,12 @@ module: aix_lvg
|
||||
short_description: Manage LVM volume groups on AIX
|
||||
description:
|
||||
- This module creates, removes or resize volume groups on AIX LVM.
|
||||
deprecated:
|
||||
removed_in: 15.0.0
|
||||
why: The module is not actively maintained.
|
||||
alternative: >-
|
||||
Use C(ibm.power_aix.lvg) instead.
|
||||
See U(https://ibm.github.io/ansible-power-aix/modules/lvg.html) for details.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -13,6 +13,12 @@ module: aix_lvol
|
||||
short_description: Configure AIX LVM logical volumes
|
||||
description:
|
||||
- This module creates, removes or resizes AIX logical volumes. Inspired by M(community.general.lvol) module.
|
||||
deprecated:
|
||||
removed_in: 15.0.0
|
||||
why: The module is not actively maintained.
|
||||
alternative: >-
|
||||
Use C(ibm.power_aix.lvol) instead.
|
||||
See U(https://ibm.github.io/ansible-power-aix/modules/lvol.html) for details.
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -163,7 +163,7 @@ class AlternativesModule:
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.result = dict(changed=False, diff=dict(before=dict(), after=dict()))
|
||||
self.module.run_command_environ_update = {"LC_ALL": "C"}
|
||||
self.module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
self.messages = []
|
||||
self.run()
|
||||
|
||||
|
||||
@@ -72,6 +72,12 @@ options:
|
||||
- Please notice that C(ansible-galaxy) does not install collections with O(type=both), when O(requirements_file) contains
|
||||
both roles and collections and O(dest) is specified.
|
||||
type: path
|
||||
executable:
|
||||
description:
|
||||
- Path to the C(ansible-galaxy) executable.
|
||||
- When not specified, the module uses C(ansible-galaxy) found by Ansible.
|
||||
type: path
|
||||
version_added: 12.5.0
|
||||
no_deps:
|
||||
description:
|
||||
- Refrain from installing dependencies.
|
||||
@@ -202,7 +208,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
)
|
||||
ansible_version = None
|
||||
|
||||
output_params = ("type", "name", "dest", "requirements_file", "force", "no_deps")
|
||||
output_params = ("type", "name", "dest", "requirements_file", "executable", "force", "no_deps")
|
||||
module = dict(
|
||||
argument_spec=dict(
|
||||
state=dict(type="str", choices=["present", "latest"], default="present"),
|
||||
@@ -210,6 +216,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
name=dict(type="str"),
|
||||
requirements_file=dict(type="path"),
|
||||
dest=dict(type="path"),
|
||||
executable=dict(type="path"),
|
||||
force=dict(type="bool", default=False),
|
||||
no_deps=dict(type="bool", default=False),
|
||||
),
|
||||
@@ -234,7 +241,11 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
|
||||
def _make_runner(self, lang):
|
||||
return CmdRunner(
|
||||
self.module, command=self.command, arg_formats=self.command_args_formats, force_lang=lang, check_rc=True
|
||||
self.module,
|
||||
command=self.vars.executable or self.command,
|
||||
arg_formats=self.command_args_formats,
|
||||
force_lang=lang,
|
||||
check_rc=True,
|
||||
)
|
||||
|
||||
def _get_ansible_galaxy_version(self):
|
||||
@@ -264,7 +275,7 @@ class AnsibleGalaxyInstall(ModuleHelper):
|
||||
self.runner, self.vars.version = self._get_ansible_galaxy_version()
|
||||
self.ansible_version = tuple(int(x) for x in self.vars.version.split(".")[:3])
|
||||
if self.ansible_version < (2, 11):
|
||||
self.module.fail_json(msg="Support for Ansible 2.9 and ansible-base 2.10 has been removed.")
|
||||
self.do_raise(msg="Support for Ansible 2.9 and ansible-base 2.10 has been removed.")
|
||||
self.vars.set("new_collections", {}, change=True)
|
||||
self.vars.set("new_roles", {}, change=True)
|
||||
if self.vars.type != "collection":
|
||||
|
||||
@@ -245,6 +245,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
name = module.params["name"]
|
||||
if name == "cgi" and module.params["state"] == "present" and _run_threaded(module):
|
||||
|
||||
@@ -342,7 +342,7 @@ def main():
|
||||
)
|
||||
|
||||
# Set LANG env since we parse stdout
|
||||
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
|
||||
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
|
||||
|
||||
global APK_PATH
|
||||
APK_PATH = [module.get_bin_path("apk", required=True)]
|
||||
|
||||
@@ -122,6 +122,7 @@ def main():
|
||||
update=dict(type="bool", default=False),
|
||||
),
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
if not os.path.exists(APT_REPO_PATH):
|
||||
module.fail_json(msg="cannot find /usr/bin/apt-repo")
|
||||
|
||||
@@ -175,7 +175,7 @@ def check_package_version(module, name):
|
||||
# if newest version already installed return True
|
||||
# otherwise return False
|
||||
|
||||
rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANG": "C"})
|
||||
rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
|
||||
installed = re.split("\n |: ", out)[2]
|
||||
candidate = re.split("\n |: ", out)[4]
|
||||
return installed >= candidate
|
||||
@@ -204,7 +204,9 @@ def query_package_provides(module, name, allow_upgrade=False):
|
||||
|
||||
|
||||
def update_package_db(module):
|
||||
rc, update_out, err = module.run_command([APT_PATH, "update"], check_rc=True, environ_update={"LANG": "C"})
|
||||
rc, update_out, err = module.run_command(
|
||||
[APT_PATH, "update"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
)
|
||||
return (False, update_out)
|
||||
|
||||
|
||||
@@ -223,12 +225,16 @@ def clean(module):
|
||||
|
||||
|
||||
def dist_upgrade(module):
|
||||
rc, out, err = module.run_command([APT_PATH, "-y", "dist-upgrade"], check_rc=True, environ_update={"LANG": "C"})
|
||||
rc, out, err = module.run_command(
|
||||
[APT_PATH, "-y", "dist-upgrade"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
)
|
||||
return (APT_GET_ZERO not in out, out)
|
||||
|
||||
|
||||
def update_kernel(module):
|
||||
rc, out, err = module.run_command(["/usr/sbin/update-kernel", "-y"], check_rc=True, environ_update={"LANG": "C"})
|
||||
rc, out, err = module.run_command(
|
||||
["/usr/sbin/update-kernel", "-y"], check_rc=True, environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
)
|
||||
return (UPDATE_KERNEL_ZERO not in out, out)
|
||||
|
||||
|
||||
@@ -243,7 +249,9 @@ def remove_packages(module, packages):
|
||||
if not query_package(module, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command([APT_PATH, "-y", "remove", package], environ_update={"LANG": "C"})
|
||||
rc, out, err = module.run_command(
|
||||
[APT_PATH, "-y", "remove", package], environ_update={"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg=f"failed to remove {package}: {err}")
|
||||
@@ -267,7 +275,7 @@ def install_packages(module, pkgspec, allow_upgrade=False):
|
||||
|
||||
if packages:
|
||||
command = [APT_PATH, "-y", "install"] + packages
|
||||
rc, out, err = module.run_command(command, environ_update={"LANG": "C"})
|
||||
rc, out, err = module.run_command(command, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
|
||||
|
||||
installed = True
|
||||
for package in pkgspec:
|
||||
|
||||
@@ -135,6 +135,7 @@ def main():
|
||||
required_one_of=[["name", "activate"]],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
global AWALL_PATH
|
||||
AWALL_PATH = module.get_bin_path("awall", required=True)
|
||||
|
||||
@@ -288,6 +288,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
be = BE(module)
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ def main():
|
||||
version=dict(),
|
||||
)
|
||||
module = AnsibleModule(argument_spec=arg_spec)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
name = module.params["name"]
|
||||
offline = module.params["offline"]
|
||||
|
||||
@@ -143,6 +143,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
state = module.params.get("state")
|
||||
chdir = module.params.get("chdir")
|
||||
|
||||
@@ -147,6 +147,7 @@ def main():
|
||||
executable=dict(type="str"),
|
||||
)
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
dest = module.params["dest"]
|
||||
parent = module.params["name"]
|
||||
|
||||
@@ -183,6 +183,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
CapabilitiesModule(module)
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ def main():
|
||||
module.fail_json(msg="Source directory does not exist")
|
||||
|
||||
# Set LANG env since we parse stdout
|
||||
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
|
||||
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
|
||||
|
||||
cargo = Cargo(module, **module.params)
|
||||
changed, out, err = False, None, None
|
||||
|
||||
@@ -99,9 +99,9 @@ def main():
|
||||
use_ssl = module.params["use_ssl"]
|
||||
validate_certs = module.params["validate_certs"]
|
||||
|
||||
module.params["proto"] = "https" if use_ssl else "http"
|
||||
proto = "https" if use_ssl else "http"
|
||||
if not port:
|
||||
module.params["port"] = "443" if use_ssl else "80"
|
||||
port = "443" if use_ssl else "80"
|
||||
|
||||
result = dict(
|
||||
changed=True,
|
||||
@@ -111,17 +111,13 @@ def main():
|
||||
|
||||
ssl_context = None if validate_certs or not use_ssl else ssl._create_unverified_context()
|
||||
|
||||
url = "{proto}://{host}:{port}/cobbler_api".format(**module.params)
|
||||
url = f"{proto}://{module.params['host']}:{port}/cobbler_api"
|
||||
conn = xmlrpc_client.ServerProxy(url, context=ssl_context)
|
||||
|
||||
try:
|
||||
token = conn.login(username, password)
|
||||
except xmlrpc_client.Fault as e:
|
||||
module.fail_json(
|
||||
msg="Failed to log in to Cobbler '{url}' as '{username}'. {error}".format(
|
||||
url=url, error=f"{e}", **module.params
|
||||
)
|
||||
)
|
||||
module.fail_json(msg=f"Failed to log in to Cobbler '{url}' as '{username}'. {e}")
|
||||
except Exception as e:
|
||||
module.fail_json(msg=f"Connection to '{url}' failed. {e}")
|
||||
|
||||
|
||||
@@ -220,9 +220,9 @@ def main():
|
||||
name = module.params["name"]
|
||||
state = module.params["state"]
|
||||
|
||||
module.params["proto"] = "https" if use_ssl else "http"
|
||||
proto = "https" if use_ssl else "http"
|
||||
if not port:
|
||||
module.params["port"] = "443" if use_ssl else "80"
|
||||
port = "443" if use_ssl else "80"
|
||||
|
||||
result = dict(
|
||||
changed=False,
|
||||
@@ -232,17 +232,13 @@ def main():
|
||||
|
||||
ssl_context = None if validate_certs or not use_ssl else ssl._create_unverified_context()
|
||||
|
||||
url = "{proto}://{host}:{port}/cobbler_api".format(**module.params)
|
||||
url = f"{proto}://{module.params['host']}:{port}/cobbler_api"
|
||||
conn = xmlrpc_client.ServerProxy(url, context=ssl_context)
|
||||
|
||||
try:
|
||||
token = conn.login(username, password)
|
||||
except xmlrpc_client.Fault as e:
|
||||
module.fail_json(
|
||||
msg="Failed to log in to Cobbler '{url}' as '{username}'. {error}".format(
|
||||
url=url, error=f"{e}", **module.params
|
||||
)
|
||||
)
|
||||
module.fail_json(msg=f"Failed to log in to Cobbler '{url}' as '{username}'. {e}")
|
||||
except Exception as e:
|
||||
module.fail_json(msg=f"Connection to '{url}' failed. {e}")
|
||||
|
||||
|
||||
@@ -98,6 +98,14 @@ options:
|
||||
these.
|
||||
default: false
|
||||
type: bool
|
||||
force:
|
||||
description:
|
||||
- When O(command) is V(create-project), the module checks whether a V(composer.json) already
|
||||
exists in O(working_dir) and skips the command if it does, making the task idempotent.
|
||||
- Set to V(true) to always run the command regardless.
|
||||
default: false
|
||||
type: bool
|
||||
version_added: 12.6.0
|
||||
composer_executable:
|
||||
type: path
|
||||
description:
|
||||
@@ -139,6 +147,7 @@ EXAMPLES = r"""
|
||||
arguments: my/package
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
|
||||
@@ -212,11 +221,13 @@ def main():
|
||||
optimize_autoloader=dict(default=True, type="bool"),
|
||||
classmap_authoritative=dict(default=False, type="bool"),
|
||||
ignore_platform_reqs=dict(default=False, type="bool"),
|
||||
force=dict(default=False, type="bool"),
|
||||
composer_executable=dict(type="path"),
|
||||
),
|
||||
required_if=[("global_command", False, ["working_dir"])],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
# Get composer command with fallback to default
|
||||
command = module.params["command"]
|
||||
@@ -257,6 +268,12 @@ def main():
|
||||
option = f"--{option}"
|
||||
options.append(option)
|
||||
|
||||
working_dir = module.params["working_dir"]
|
||||
|
||||
if command == "create-project" and not module.params["force"]:
|
||||
if working_dir and os.path.exists(os.path.join(working_dir, "composer.json")):
|
||||
module.exit_json(changed=False, msg="composer.json already exists in working_dir, skipping create-project")
|
||||
|
||||
if module.check_mode:
|
||||
if "dry-run" in available_options:
|
||||
options.append("--dry-run")
|
||||
|
||||
@@ -94,9 +94,15 @@ options:
|
||||
default: http
|
||||
validate_certs:
|
||||
description:
|
||||
- Whether to verify the tls certificate of the Consul agent.
|
||||
- Whether to verify the TLS certificate of the Consul agent.
|
||||
- Instead of setting this to V(false), please consider using O(ca_path) instead.
|
||||
type: bool
|
||||
default: true
|
||||
ca_path:
|
||||
description:
|
||||
- The CA bundle to use for HTTPS connections.
|
||||
type: str
|
||||
version_added: "12.6.0"
|
||||
datacenter:
|
||||
description:
|
||||
- The name of the datacenter to query. If unspecified, the query defaults to the datacenter of the Consul agent on O(host).
|
||||
@@ -263,11 +269,14 @@ def remove_value(module):
|
||||
|
||||
|
||||
def get_consul_api(module):
|
||||
ca_path = module.params.get("ca_path")
|
||||
validate_certs = module.params.get("validate_certs")
|
||||
verify = (ca_path or validate_certs) if validate_certs else False
|
||||
return consul.Consul(
|
||||
host=module.params.get("host"),
|
||||
port=module.params.get("port"),
|
||||
scheme=module.params.get("scheme"),
|
||||
verify=module.params.get("validate_certs"),
|
||||
verify=verify,
|
||||
token=module.params.get("token"),
|
||||
dc=module.params.get("datacenter"),
|
||||
)
|
||||
@@ -291,6 +300,7 @@ def main():
|
||||
host=dict(type="str", default="localhost"),
|
||||
scheme=dict(type="str", default="http"),
|
||||
validate_certs=dict(type="bool", default=True),
|
||||
ca_path=dict(type="str"),
|
||||
port=dict(type="int", default=8500),
|
||||
recurse=dict(type="bool"),
|
||||
retrieve=dict(type="bool", default=True),
|
||||
|
||||
@@ -360,6 +360,7 @@ def main():
|
||||
mutually_exclusive=[["insertbefore", "insertafter"]],
|
||||
supports_check_mode=False,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
name = module.params["name"]
|
||||
value = module.params["value"]
|
||||
|
||||
@@ -281,7 +281,7 @@ class Options(dict):
|
||||
self.itemlist = []
|
||||
if opts_string is not None:
|
||||
for opt in opts_string.split(","):
|
||||
kv = opt.split("=")
|
||||
kv = opt.split("=", 1)
|
||||
if len(kv) > 1:
|
||||
k, v = (kv[0], kv[1])
|
||||
else:
|
||||
|
||||
@@ -15,13 +15,15 @@ description:
|
||||
- This module allows modifications and reading of C(dconf) database. The module is implemented as a wrapper around C(dconf)
|
||||
tool. Please see the dconf(1) man page for more details.
|
||||
- Since C(dconf) requires a running D-Bus session to change values, the module tries to detect an existing session and reuse
|
||||
it, or run the tool using C(dbus-run-session).
|
||||
it, or run the tool using C(dbus-run-session). Both C(dbus-daemon) and C(dbus-broker) are supported.
|
||||
requirements:
|
||||
- Optionally the C(gi.repository) Python library (usually included in the OS on hosts which have C(dconf)); this is to become
|
||||
a non-optional requirement in a future major release of community.general.
|
||||
notes:
|
||||
- This module depends on C(psutil) Python library (version 4.0.0 and upwards), C(dconf), C(dbus-send), and C(dbus-run-session)
|
||||
binaries. Depending on distribution you are using, you may need to install additional packages to have these available.
|
||||
- This module depends on C(psutil) Python library (version 4.0.0 and upwards), C(dconf), and either C(dbus-send) or C(busctl)
|
||||
for D-Bus session validation, and C(dbus-run-session) as a fallback when no existing session is found.
|
||||
Depending on distribution you are using, you may need to install additional packages to have these available.
|
||||
Both the reference C(dbus-daemon) implementation and C(dbus-broker) are supported.
|
||||
- This module uses the C(gi.repository) Python library when available for accurate comparison of values in C(dconf) to values
|
||||
specified in Ansible code. C(gi.repository) is likely to be present on most systems which have C(dconf) but may not be
|
||||
present everywhere. When it is missing, a simple string comparison between values is used, and there may be false positives,
|
||||
@@ -156,6 +158,13 @@ class DBusWrapper:
|
||||
If possible, command will be run against an existing D-Bus session,
|
||||
otherwise the session will be spawned via dbus-run-session.
|
||||
|
||||
Discovery order:
|
||||
1. DBUS_SESSION_BUS_ADDRESS in the current process environment
|
||||
2. /run/user/<uid>/bus -- canonical socket for systemd and dbus-broker
|
||||
3. Process scan for DBUS_SESSION_BUS_ADDRESS -- legacy fallback
|
||||
|
||||
Validation uses C(dbus-send) if available, C(busctl) otherwise.
|
||||
|
||||
Example usage:
|
||||
|
||||
dbus_wrapper = DBusWrapper(ansible_module)
|
||||
@@ -163,24 +172,32 @@ class DBusWrapper:
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
"""
|
||||
Initialises an instance of the class.
|
||||
|
||||
:param module: Ansible module instance used to signal failures and run commands.
|
||||
:type module: AnsibleModule
|
||||
"""
|
||||
|
||||
# Store passed-in arguments and set-up some defaults.
|
||||
self.module = module
|
||||
|
||||
# Try to extract existing D-Bus session address.
|
||||
self.dbus_session_bus_address = self._get_existing_dbus_session()
|
||||
|
||||
# If no existing D-Bus session was detected, check if dbus-run-session
|
||||
# is available.
|
||||
if self.dbus_session_bus_address is None:
|
||||
self.dbus_run_session_cmd = self.module.get_bin_path("dbus-run-session", required=True)
|
||||
|
||||
def _validate_address(self, address):
|
||||
dbus_send = self.module.get_bin_path("dbus-send")
|
||||
if dbus_send:
|
||||
rc, dummy, dummy = self.module.run_command(
|
||||
[dbus_send, f"--address={address}", "--type=signal", "/", "com.example.test"]
|
||||
)
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
busctl = self.module.get_bin_path("busctl")
|
||||
if busctl:
|
||||
rc, dummy, dummy = self.module.run_command([busctl, f"--address={address}", "list"])
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
if not dbus_send and not busctl:
|
||||
self.module.fail_json(msg="Neither dbus-send nor busctl is available. Please install one of them.")
|
||||
|
||||
return False
|
||||
|
||||
def _get_existing_dbus_session(self):
|
||||
"""
|
||||
Detects and returns an existing D-Bus session bus address.
|
||||
@@ -191,11 +208,25 @@ class DBusWrapper:
|
||||
# We'll be checking the processes of current user only.
|
||||
uid = os.getuid()
|
||||
|
||||
# Go through all the pids for this user, try to extract the D-Bus
|
||||
# session bus address from environment, and ensure it is possible to
|
||||
# connect to it.
|
||||
self.module.debug(f"Trying to detect existing D-Bus user session for user: {int(uid)}")
|
||||
# Step 1: current process environment
|
||||
address = os.environ.get("DBUS_SESSION_BUS_ADDRESS")
|
||||
if address:
|
||||
self.module.debug(f"Trying D-Bus address from environment: {address}")
|
||||
if self._validate_address(address):
|
||||
self.module.debug(f"Using D-Bus session from environment: {address}")
|
||||
return address
|
||||
|
||||
# Step 2: canonical systemd/dbus-broker socket path
|
||||
canonical_path = f"/run/user/{uid}/bus"
|
||||
if os.path.exists(canonical_path):
|
||||
address = f"unix:path={canonical_path}"
|
||||
self.module.debug(f"Trying canonical D-Bus socket: {canonical_path}")
|
||||
if self._validate_address(address):
|
||||
self.module.debug(f"Using canonical D-Bus socket: {canonical_path}")
|
||||
return address
|
||||
|
||||
# Step 3: process scan (legacy fallback)
|
||||
self.module.debug(f"Scanning processes for D-Bus session (uid={uid})")
|
||||
for pid in psutil.pids():
|
||||
try:
|
||||
process = psutil.Process(pid)
|
||||
@@ -205,21 +236,10 @@ class DBusWrapper:
|
||||
self.module.debug(
|
||||
f"Found D-Bus user session candidate at address: {dbus_session_bus_address_candidate}"
|
||||
)
|
||||
dbus_send_cmd = self.module.get_bin_path("dbus-send", required=True)
|
||||
command = [
|
||||
dbus_send_cmd,
|
||||
f"--address={dbus_session_bus_address_candidate}",
|
||||
"--type=signal",
|
||||
"/",
|
||||
"com.example.test",
|
||||
]
|
||||
rc, dummy, dummy = self.module.run_command(command)
|
||||
|
||||
if rc == 0:
|
||||
if self._validate_address(dbus_session_bus_address_candidate):
|
||||
self.module.debug(
|
||||
f"Verified D-Bus user session candidate as usable at address: {dbus_session_bus_address_candidate}"
|
||||
)
|
||||
|
||||
return dbus_session_bus_address_candidate
|
||||
|
||||
# This can happen with things like SSH sessions etc.
|
||||
@@ -230,7 +250,6 @@ class DBusWrapper:
|
||||
pass
|
||||
|
||||
self.module.debug("Failed to find running D-Bus user session, will use dbus-run-session")
|
||||
|
||||
return None
|
||||
|
||||
def run_command(self, command):
|
||||
@@ -249,8 +268,7 @@ class DBusWrapper:
|
||||
self.module.debug("Using dbus-run-session wrapper for running commands.")
|
||||
command = [self.dbus_run_session_cmd] + command
|
||||
rc, out, err = self.module.run_command(command)
|
||||
|
||||
if self.dbus_session_bus_address is None and rc == 127:
|
||||
if rc == 127:
|
||||
self.module.fail_json(
|
||||
msg=f"Failed to run passed-in command, dbus-run-session faced an internal error: {err}"
|
||||
)
|
||||
@@ -311,7 +329,7 @@ class DconfPreference:
|
||||
"""
|
||||
command = [self.dconf_bin, "read", key]
|
||||
|
||||
rc, out, err = self.module.run_command(command)
|
||||
rc, out, err = self.module.run_command(command, environ_update={"LANGUAGE": "C", "LC_ALL": "C"})
|
||||
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg=f"dconf failed while reading the value with error: {err}", out=out, err=err)
|
||||
|
||||
@@ -257,6 +257,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
patterns = module.params["name"]
|
||||
raw = module.params["raw"]
|
||||
|
||||
@@ -171,6 +171,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
path = module.params["path"]
|
||||
state = module.params["state"]
|
||||
|
||||
@@ -139,6 +139,7 @@ def main():
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=True)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
name = module.params["name"]
|
||||
env = module.params["virtualenv"]
|
||||
|
||||
@@ -69,6 +69,7 @@ def main():
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
facter_path = module.get_bin_path("facter", opt_dirs=["/opt/puppetlabs/bin"])
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ import stat
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils._lvm import pvs_runner
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
|
||||
@@ -213,7 +214,7 @@ class Filesystem:
|
||||
CHANGE_UUID_OPTION: str | None = None
|
||||
CHANGE_UUID_OPTION_HAS_ARG = True
|
||||
|
||||
LANG_ENV = {"LANG": "C", "LC_ALL": "C", "LC_MESSAGES": "C"}
|
||||
LANG_ENV = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
@@ -569,14 +570,15 @@ class LVM(Filesystem):
|
||||
CHANGE_UUID_OPTION = "-u"
|
||||
CHANGE_UUID_OPTION_HAS_ARG = False
|
||||
|
||||
def __init__(self, module):
|
||||
super().__init__(module)
|
||||
self._pvs = pvs_runner(module)
|
||||
|
||||
def get_fs_size(self, dev):
|
||||
"""Get and return PV size, in bytes."""
|
||||
cmd = self.module.get_bin_path(self.INFO, required=True)
|
||||
dummy, size, dummy = self.module.run_command(
|
||||
[cmd, "--noheadings", "-o", "pv_size", "--units", "b", "--nosuffix", str(dev)], check_rc=True
|
||||
)
|
||||
pv_size = int(size)
|
||||
return pv_size
|
||||
with self._pvs("noheadings nosuffix units fields devices") as ctx:
|
||||
dummy, size, dummy = ctx.run(units="b", fields="pv_size", devices=[str(dev)])
|
||||
return int(size.strip())
|
||||
|
||||
|
||||
class Swap(Filesystem):
|
||||
|
||||
@@ -45,18 +45,27 @@ options:
|
||||
name:
|
||||
description:
|
||||
- The name of the flatpak to manage. To operate on several packages this can accept a list of packages.
|
||||
- When used with O(state=present), O(name) can be specified as a URL to a C(flatpakref) file or the unique reverse DNS
|
||||
name that identifies a flatpak.
|
||||
- Both C(https://) and C(http://) URLs are supported.
|
||||
- Should be specified as the unique reverse DNS name that identifies a flatpak (for example V(org.gnome.gedit)).
|
||||
- When supplying a reverse DNS name, you can use the O(remote) option to specify on what remote to look for the flatpak.
|
||||
An example for a reverse DNS name is C(org.gnome.gedit).
|
||||
- When used with O(state=absent) or O(state=latest), it is recommended to specify the name in the reverse DNS format.
|
||||
- When used with O(state=present), O(name) can also be specified as a C(https://) or C(http://) URL to a C(flatpakref) file.
|
||||
However, it is recommended you use O(from_url) instead to get reliable idempotency.
|
||||
Passing URLs in O(name) will be deprecated in the future.
|
||||
- When used with O(state=absent) or O(state=latest), always specify the name in the reverse DNS format.
|
||||
- When supplying a URL with O(state=absent) or O(state=latest), the module tries to match the installed flatpak based
|
||||
on the name of the flatpakref to remove or update it. However, there is no guarantee that the names of the flatpakref
|
||||
file and the reverse DNS name of the installed flatpak do match.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
from_url:
|
||||
description:
|
||||
- A C(http://) or C(https://) URL pointing to a C(.flatpakref) file to install from.
|
||||
- When this option is set, O(name) must contain exactly one entry specifying the reverse DNS application ID of the
|
||||
flatpak (for example V(com.onepassword.OnePassword)). This is used to check whether the flatpak is already installed.
|
||||
- O(name) and O(from_url) cannot both contain URLs.
|
||||
- This option is recommended instead of passing a URL in O(name); passing URLs in O(name) will be deprecated in the future.
|
||||
type: str
|
||||
version_added: "12.6.0"
|
||||
no_dependencies:
|
||||
description:
|
||||
- If installing runtime dependencies should be omitted or not.
|
||||
@@ -84,12 +93,14 @@ options:
|
||||
EXAMPLES = r"""
|
||||
- name: Install the spotify flatpak
|
||||
community.general.flatpak:
|
||||
name: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
|
||||
name: com.spotify.Client
|
||||
from_url: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
|
||||
state: present
|
||||
|
||||
- name: Install the gedit flatpak package without dependencies (not recommended)
|
||||
community.general.flatpak:
|
||||
name: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
|
||||
name: org.gnome.gedit
|
||||
from_url: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
|
||||
state: present
|
||||
no_dependencies: true
|
||||
|
||||
@@ -120,12 +131,14 @@ EXAMPLES = r"""
|
||||
|
||||
- name: Update the spotify flatpak
|
||||
community.general.flatpak:
|
||||
name: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
|
||||
name: com.spotify.Client
|
||||
from_url: https://s3.amazonaws.com/alexlarsson/spotify-repo/spotify.flatpakref
|
||||
state: latest
|
||||
|
||||
- name: Update the gedit flatpak package without dependencies (not recommended)
|
||||
community.general.flatpak:
|
||||
name: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
|
||||
name: org.gnome.gedit
|
||||
from_url: https://git.gnome.org/browse/gnome-apps-nightly/plain/gedit.flatpakref
|
||||
state: latest
|
||||
no_dependencies: true
|
||||
|
||||
@@ -180,7 +193,7 @@ from ansible_collections.community.general.plugins.module_utils.version import L
|
||||
OUTDATED_FLATPAK_VERSION_ERROR_MESSAGE = "Unknown option --columns=application"
|
||||
|
||||
|
||||
def install_flat(module, binary, remote, names, method, no_dependencies):
|
||||
def install_flat(module, binary, remote, names, method, no_dependencies, from_url=None):
|
||||
"""Add new flatpaks."""
|
||||
global result # pylint: disable=global-variable-not-assigned
|
||||
uri_names = []
|
||||
@@ -198,12 +211,16 @@ def install_flat(module, binary, remote, names, method, no_dependencies):
|
||||
base_command += ["--noninteractive"]
|
||||
if no_dependencies:
|
||||
base_command += ["--no-deps"]
|
||||
if uri_names:
|
||||
command = base_command + uri_names
|
||||
_flatpak_command(module, module.check_mode, command)
|
||||
if id_names:
|
||||
command = base_command + [remote] + id_names
|
||||
if from_url:
|
||||
command = base_command + ["--from", from_url]
|
||||
_flatpak_command(module, module.check_mode, command)
|
||||
else:
|
||||
if uri_names:
|
||||
command = base_command + uri_names
|
||||
_flatpak_command(module, module.check_mode, command)
|
||||
if id_names:
|
||||
command = base_command + [remote] + id_names
|
||||
_flatpak_command(module, module.check_mode, command)
|
||||
result["changed"] = True
|
||||
|
||||
|
||||
@@ -221,7 +238,9 @@ def update_flat(module, binary, names, method, no_dependencies):
|
||||
command += ["--no-deps"]
|
||||
command += installed_flat_names
|
||||
stdout = _flatpak_command(module, module.check_mode, command)
|
||||
result["changed"] = True if module.check_mode else stdout.find("Nothing to do.") == -1
|
||||
result["changed"] = (
|
||||
True if module.check_mode else (stdout.find("Nothing to do.") == -1 and stdout.find("Nothing to update.") == -1)
|
||||
)
|
||||
|
||||
|
||||
def uninstall_flat(module, binary, names, method):
|
||||
@@ -261,7 +280,7 @@ def _match_installed_flat_name(module, binary, name, method):
|
||||
global result # pylint: disable=global-variable-not-assigned
|
||||
parsed_name = _parse_flatpak_name(name)
|
||||
# Try running flatpak list with columns feature
|
||||
command = [binary, "list", f"--{method}", "--app", "--columns=application"]
|
||||
command = [binary, "list", f"--{method}", "--columns=application"]
|
||||
_flatpak_command(module, False, command, ignore_failure=True)
|
||||
if result["rc"] != 0 and OUTDATED_FLATPAK_VERSION_ERROR_MESSAGE in result["stderr"]:
|
||||
# Probably flatpak before 1.2
|
||||
@@ -283,7 +302,7 @@ def _match_installed_flat_name(module, binary, name, method):
|
||||
|
||||
def _match_flat_using_outdated_flatpak_format(module, binary, parsed_name, method):
|
||||
global result # pylint: disable=global-variable-not-assigned
|
||||
command = [binary, "list", f"--{method}", "--app", "--columns=application"]
|
||||
command = [binary, "list", f"--{method}", "--columns=application"]
|
||||
output = _flatpak_command(module, False, command)
|
||||
for row in output.split("\n"):
|
||||
if parsed_name.lower() == row.lower():
|
||||
@@ -292,7 +311,7 @@ def _match_flat_using_outdated_flatpak_format(module, binary, parsed_name, metho
|
||||
|
||||
def _match_flat_using_flatpak_column_feature(module, binary, parsed_name, method):
|
||||
global result # pylint: disable=global-variable-not-assigned
|
||||
command = [binary, "list", f"--{method}", "--app"]
|
||||
command = [binary, "list", f"--{method}"]
|
||||
output = _flatpak_command(module, False, command)
|
||||
for row in output.split("\n"):
|
||||
if parsed_name.lower() in row.lower():
|
||||
@@ -356,6 +375,7 @@ def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(type="list", elements="str", required=True),
|
||||
from_url=dict(type="str"),
|
||||
remote=dict(type="str", default="flathub"),
|
||||
method=dict(type="str", default="system", choices=["user", "system"]),
|
||||
state=dict(type="str", default="present", choices=["absent", "present", "latest"]),
|
||||
@@ -366,6 +386,7 @@ def main():
|
||||
)
|
||||
|
||||
name = module.params["name"]
|
||||
from_url = module.params["from_url"]
|
||||
state = module.params["state"]
|
||||
remote = module.params["remote"]
|
||||
no_dependencies = module.params["no_dependencies"]
|
||||
@@ -380,6 +401,14 @@ def main():
|
||||
if not binary:
|
||||
module.fail_json(msg=f"Executable '{executable}' was not found on the system.", **result)
|
||||
|
||||
url_names = [n for n in name if n.startswith("http://") or n.startswith("https://")]
|
||||
if from_url is not None:
|
||||
if not (from_url.startswith("http://") or from_url.startswith("https://")):
|
||||
module.fail_json(msg="The 'from_url' parameter must be an http:// or https:// URL.", **result)
|
||||
if url_names:
|
||||
module.fail_json(msg="The 'name' and 'from_url' parameters cannot both contain URLs.", **result)
|
||||
if len(name) != 1:
|
||||
module.fail_json(msg="When 'from_url' is used, 'name' must contain exactly one entry.", **result)
|
||||
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
|
||||
|
||||
installed, not_installed = flatpak_exists(module, binary, name, method)
|
||||
@@ -389,7 +418,7 @@ def main():
|
||||
if state == "latest" and installed:
|
||||
update_flat(module, binary, installed, method, no_dependencies)
|
||||
if state in ("present", "latest") and not_installed:
|
||||
install_flat(module, binary, remote, not_installed, method, no_dependencies)
|
||||
install_flat(module, binary, remote, not_installed, method, no_dependencies, from_url)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -199,6 +199,7 @@ def main():
|
||||
# This module supports check mode
|
||||
supports_check_mode=True,
|
||||
)
|
||||
module.run_command_environ_update = {"LANGUAGE": "C", "LC_ALL": "C"}
|
||||
|
||||
name = module.params["name"]
|
||||
flatpakrepo_url = module.params["flatpakrepo_url"]
|
||||
|
||||
@@ -126,53 +126,86 @@ import re
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils import cmd_runner_fmt as fmt
|
||||
from ansible_collections.community.general.plugins.module_utils.cmd_runner import CmdRunner
|
||||
|
||||
RE_VERSION = re.compile(r"^(\d+)\.(\d+)\.(\d+)")
|
||||
RE_INSTALLED = re.compile(r"\S+\s+\((?:default: )?(.+)\)")
|
||||
|
||||
|
||||
def get_rubygems_path(module):
|
||||
if module.params["executable"]:
|
||||
result = module.params["executable"].split(" ")
|
||||
else:
|
||||
result = [module.get_bin_path("gem", True)]
|
||||
return result
|
||||
return module.params["executable"].split()
|
||||
return [module.get_bin_path("gem", True)]
|
||||
|
||||
|
||||
def get_rubygems_version(module):
|
||||
if hasattr(get_rubygems_version, "ver"):
|
||||
return get_rubygems_version.ver
|
||||
|
||||
cmd = get_rubygems_path(module) + ["--version"]
|
||||
(rc, out, err) = module.run_command(cmd, check_rc=True)
|
||||
|
||||
match = re.match(r"^(\d+)\.(\d+)\.(\d+)", out)
|
||||
rc, out, err = module.run_command(cmd, check_rc=True)
|
||||
match = RE_VERSION.match(out)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
ver = tuple(int(x) for x in match.groups())
|
||||
get_rubygems_version.ver = ver
|
||||
|
||||
return ver
|
||||
return tuple(int(x) for x in match.groups())
|
||||
|
||||
|
||||
def get_rubygems_environ(module):
|
||||
def make_runner(module, ver):
|
||||
command = get_rubygems_path(module)
|
||||
|
||||
environ_update = {}
|
||||
if module.params["install_dir"]:
|
||||
return {"GEM_HOME": module.params["install_dir"]}
|
||||
return None
|
||||
environ_update["GEM_HOME"] = module.params["install_dir"]
|
||||
|
||||
if ver and ver < (2, 0, 0):
|
||||
include_dependencies_fmt = fmt.as_bool("--include-dependencies", "--ignore-dependencies")
|
||||
include_doc_fmt = fmt.as_bool_not(["--no-rdoc", "--no-ri"])
|
||||
else:
|
||||
include_dependencies_fmt = fmt.as_bool_not("--ignore-dependencies")
|
||||
include_doc_fmt = fmt.as_bool_not("--no-document")
|
||||
|
||||
norc_fmt = fmt.as_bool("--norc") if (ver and ver >= (2, 5, 2)) else fmt.as_bool([])
|
||||
|
||||
return CmdRunner(
|
||||
module,
|
||||
command=command,
|
||||
environ_update=environ_update,
|
||||
check_rc=True,
|
||||
arg_formats=dict(
|
||||
_list_subcmd=fmt.as_fixed("list"),
|
||||
_install_subcmd=fmt.as_fixed("install"),
|
||||
_uninstall_subcmd=fmt.as_fixed("uninstall"),
|
||||
norc=norc_fmt,
|
||||
_remote_flag=fmt.as_fixed("--remote"),
|
||||
repository=fmt.as_opt_val("--source"),
|
||||
_name_pattern=fmt.as_func(lambda v: [f"^{v}$"]),
|
||||
version=fmt.as_opt_val("--version"),
|
||||
include_dependencies=include_dependencies_fmt,
|
||||
user_install=fmt.as_bool("--user-install", "--no-user-install"),
|
||||
install_dir=fmt.as_opt_val("--install-dir"),
|
||||
bindir=fmt.as_opt_val("--bindir"),
|
||||
pre_release=fmt.as_bool("--pre"),
|
||||
include_doc=include_doc_fmt,
|
||||
env_shebang=fmt.as_bool("--env-shebang"),
|
||||
gem_source=fmt.as_list(),
|
||||
build_flags=fmt.as_opt_val("--"),
|
||||
force=fmt.as_bool("--force"),
|
||||
_uninstall_version=fmt.as_func(lambda v: ["--version", v] if v else ["--all"], ignore_none=False),
|
||||
_executable_flag=fmt.as_fixed("--executable"),
|
||||
name=fmt.as_list(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def get_installed_versions(module, remote=False):
|
||||
cmd = get_rubygems_path(module)
|
||||
cmd.append("list")
|
||||
cmd.extend(common_opts(module))
|
||||
def get_installed_versions(runner, remote=False):
|
||||
name = runner.module.params["name"]
|
||||
if remote:
|
||||
cmd.append("--remote")
|
||||
if module.params["repository"]:
|
||||
cmd.extend(["--source", module.params["repository"]])
|
||||
cmd.append(f"^{module.params['name']}$")
|
||||
|
||||
environ = get_rubygems_environ(module)
|
||||
(rc, out, err) = module.run_command(cmd, environ_update=environ, check_rc=True)
|
||||
args_order = ["_list_subcmd", "norc", "_remote_flag", "repository", "_name_pattern"]
|
||||
else:
|
||||
args_order = ["_list_subcmd", "norc", "_name_pattern"]
|
||||
with runner(args_order) as ctx:
|
||||
rc, out, err = ctx.run(_name_pattern=name)
|
||||
installed_versions = []
|
||||
for line in out.splitlines():
|
||||
match = re.match(r"\S+\s+\((?:default: )?(.+)\)", line)
|
||||
match = RE_INSTALLED.match(line)
|
||||
if match:
|
||||
versions = match.group(1)
|
||||
for version in versions.split(", "):
|
||||
@@ -180,95 +213,52 @@ def get_installed_versions(module, remote=False):
|
||||
return installed_versions
|
||||
|
||||
|
||||
def exists(module):
|
||||
def exists(runner):
|
||||
module = runner.module
|
||||
if module.params["state"] == "latest":
|
||||
remoteversions = get_installed_versions(module, remote=True)
|
||||
remoteversions = get_installed_versions(runner, remote=True)
|
||||
if remoteversions:
|
||||
module.params["version"] = remoteversions[0]
|
||||
installed_versions = get_installed_versions(module)
|
||||
installed_versions = get_installed_versions(runner)
|
||||
if module.params["version"]:
|
||||
if module.params["version"] in installed_versions:
|
||||
return True
|
||||
else:
|
||||
if installed_versions:
|
||||
return True
|
||||
return False
|
||||
return module.params["version"] in installed_versions
|
||||
return bool(installed_versions)
|
||||
|
||||
|
||||
def common_opts(module):
|
||||
opts = []
|
||||
ver = get_rubygems_version(module)
|
||||
if module.params["norc"] and ver and ver >= (2, 5, 2):
|
||||
opts.append("--norc")
|
||||
return opts
|
||||
def install(runner):
|
||||
args_order = [
|
||||
"_install_subcmd",
|
||||
"norc",
|
||||
"version",
|
||||
"repository",
|
||||
"include_dependencies",
|
||||
"user_install",
|
||||
"install_dir",
|
||||
"bindir",
|
||||
"pre_release",
|
||||
"include_doc",
|
||||
"env_shebang",
|
||||
"gem_source",
|
||||
"build_flags",
|
||||
"force",
|
||||
]
|
||||
with runner(args_order, check_mode_skip=True) as ctx:
|
||||
ctx.run()
|
||||
|
||||
|
||||
def uninstall(module):
|
||||
if module.check_mode:
|
||||
return
|
||||
cmd = get_rubygems_path(module)
|
||||
environ = get_rubygems_environ(module)
|
||||
cmd.append("uninstall")
|
||||
cmd.extend(common_opts(module))
|
||||
if module.params["install_dir"]:
|
||||
cmd.extend(["--install-dir", module.params["install_dir"]])
|
||||
|
||||
if module.params["bindir"]:
|
||||
cmd.extend(["--bindir", module.params["bindir"]])
|
||||
|
||||
if module.params["version"]:
|
||||
cmd.extend(["--version", module.params["version"]])
|
||||
else:
|
||||
cmd.append("--all")
|
||||
cmd.append("--executable")
|
||||
if module.params["force"]:
|
||||
cmd.append("--force")
|
||||
cmd.append(module.params["name"])
|
||||
return module.run_command(cmd, environ_update=environ, check_rc=True)
|
||||
|
||||
|
||||
def install(module):
|
||||
if module.check_mode:
|
||||
return
|
||||
|
||||
ver = get_rubygems_version(module)
|
||||
|
||||
cmd = get_rubygems_path(module)
|
||||
cmd.append("install")
|
||||
cmd.extend(common_opts(module))
|
||||
if module.params["version"]:
|
||||
cmd.extend(["--version", module.params["version"]])
|
||||
if module.params["repository"]:
|
||||
cmd.extend(["--source", module.params["repository"]])
|
||||
if not module.params["include_dependencies"]:
|
||||
cmd.append("--ignore-dependencies")
|
||||
else:
|
||||
if ver and ver < (2, 0, 0):
|
||||
cmd.append("--include-dependencies")
|
||||
if module.params["user_install"]:
|
||||
cmd.append("--user-install")
|
||||
else:
|
||||
cmd.append("--no-user-install")
|
||||
if module.params["install_dir"]:
|
||||
cmd.extend(["--install-dir", module.params["install_dir"]])
|
||||
if module.params["bindir"]:
|
||||
cmd.extend(["--bindir", module.params["bindir"]])
|
||||
if module.params["pre_release"]:
|
||||
cmd.append("--pre")
|
||||
if not module.params["include_doc"]:
|
||||
if ver and ver < (2, 0, 0):
|
||||
cmd.append("--no-rdoc")
|
||||
cmd.append("--no-ri")
|
||||
else:
|
||||
cmd.append("--no-document")
|
||||
if module.params["env_shebang"]:
|
||||
cmd.append("--env-shebang")
|
||||
cmd.append(module.params["gem_source"])
|
||||
if module.params["build_flags"]:
|
||||
cmd.extend(["--", module.params["build_flags"]])
|
||||
if module.params["force"]:
|
||||
cmd.append("--force")
|
||||
module.run_command(cmd, check_rc=True)
|
||||
def uninstall(runner):
|
||||
args_order = [
|
||||
"_uninstall_subcmd",
|
||||
"norc",
|
||||
"install_dir",
|
||||
"bindir",
|
||||
"_uninstall_version",
|
||||
"_executable_flag",
|
||||
"force",
|
||||
"name",
|
||||
]
|
||||
with runner(args_order, check_mode_skip=True) as ctx:
|
||||
return ctx.run(_uninstall_version=runner.module.params["version"])
|
||||
|
||||
|
||||
def main():
|
||||
@@ -305,16 +295,19 @@ def main():
|
||||
if not module.params["gem_source"]:
|
||||
module.params["gem_source"] = module.params["name"]
|
||||
|
||||
ver = get_rubygems_version(module)
|
||||
runner = make_runner(module, ver)
|
||||
|
||||
changed = False
|
||||
|
||||
if module.params["state"] in ["present", "latest"]:
|
||||
if not exists(module):
|
||||
install(module)
|
||||
if not exists(runner):
|
||||
install(runner)
|
||||
changed = True
|
||||
elif module.params["state"] == "absent":
|
||||
if exists(module):
|
||||
command_output = uninstall(module)
|
||||
if command_output is not None and exists(module):
|
||||
if exists(runner):
|
||||
command_output = uninstall(runner)
|
||||
if command_output is not None and exists(runner):
|
||||
rc, out, err = command_output
|
||||
module.fail_json(
|
||||
msg=(
|
||||
|
||||
@@ -163,7 +163,7 @@ def main():
|
||||
params = module.params
|
||||
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
|
||||
# Set the locale to C to ensure consistent messages.
|
||||
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
|
||||
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
|
||||
|
||||
name = params["name"] or ""
|
||||
unset = params["state"] == "absent"
|
||||
|
||||
@@ -122,7 +122,7 @@ def main():
|
||||
|
||||
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
|
||||
# Set the locale to C to ensure consistent messages.
|
||||
module.run_command_environ_update = dict(LANG="C", LC_ALL="C", LC_MESSAGES="C", LC_CTYPE="C")
|
||||
module.run_command_environ_update = dict(LANGUAGE="C", LC_ALL="C")
|
||||
|
||||
name = module.params["name"]
|
||||
path = module.params["path"]
|
||||
|
||||
401
plugins/modules/github_secrets.py
Normal file
401
plugins/modules/github_secrets.py
Normal file
@@ -0,0 +1,401 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) Ansible project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
module: github_secrets
|
||||
short_description: Manage GitHub repository or organization secrets
|
||||
description:
|
||||
- Create, update, or delete secrets in a GitHub repository or organization.
|
||||
author:
|
||||
- Thomas Sjögren (@konstruktoid)
|
||||
version_added: '12.5.0'
|
||||
requirements:
|
||||
- pynacl
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
check_mode:
|
||||
support: full
|
||||
diff_mode:
|
||||
support: none
|
||||
options:
|
||||
organization:
|
||||
description:
|
||||
- The GitHub username or organization name.
|
||||
type: str
|
||||
required: true
|
||||
aliases: ["org", "username"]
|
||||
repository:
|
||||
description:
|
||||
- The name of the repository.
|
||||
- If not provided, the secret will be managed at the organization level.
|
||||
type: str
|
||||
aliases: ["repo"]
|
||||
key:
|
||||
description:
|
||||
- The name of the secret.
|
||||
type: str
|
||||
value:
|
||||
description:
|
||||
- The value of the secret. Required when O(state=present).
|
||||
type: str
|
||||
visibility:
|
||||
description:
|
||||
- The visibility of the secret when set at the organization level.
|
||||
- Required when O(state=present) and O(repository) is not set.
|
||||
type: str
|
||||
choices: ["all", "private", "selected"]
|
||||
state:
|
||||
description:
|
||||
- The desired state of the secret.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: "present"
|
||||
api_url:
|
||||
description:
|
||||
- The base URL for the GitHub API.
|
||||
type: str
|
||||
default: "https://api.github.com"
|
||||
token:
|
||||
description:
|
||||
- The GitHub token used for authentication.
|
||||
type: str
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Add Github secret
|
||||
community.general.github_secrets:
|
||||
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
|
||||
repository: "ansible"
|
||||
organization: "ansible"
|
||||
key: "TEST_SECRET"
|
||||
value: "bob"
|
||||
state: "present"
|
||||
|
||||
- name: Delete Github secret
|
||||
community.general.github_secrets:
|
||||
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
|
||||
repository: "ansible"
|
||||
organization: "ansible"
|
||||
key: "TEST_SECRET"
|
||||
state: "absent"
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
result:
|
||||
description: The result of the module.
|
||||
type: dict
|
||||
returned: always
|
||||
sample: {
|
||||
"msg": "OK (2 bytes)",
|
||||
"response": "Secret created",
|
||||
"status": 201
|
||||
}
|
||||
"""
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils import deps
|
||||
|
||||
with deps.declare(
|
||||
"pynacl",
|
||||
reason="pynacl is a required dependency",
|
||||
url="https://pypi.org/project/PyNaCl/",
|
||||
):
|
||||
from nacl import encoding, public
|
||||
|
||||
|
||||
def get_public_key(
|
||||
module: AnsibleModule,
|
||||
api_url: str,
|
||||
headers: dict[str, str],
|
||||
organization: str,
|
||||
repository: str,
|
||||
) -> tuple[str, str]:
|
||||
"""Retrieve the GitHub Actions public key used to encrypt secrets."""
|
||||
if repository:
|
||||
url = f"{api_url}/repos/{organization}/{repository}/actions/secrets/public-key"
|
||||
else:
|
||||
url = f"{api_url}/orgs/{organization}/actions/secrets/public-key"
|
||||
|
||||
resp, info = fetch_url(module, url, headers=headers)
|
||||
|
||||
if info["status"] != HTTPStatus.OK:
|
||||
module.fail_json(msg=f"Failed to get public key: {info}")
|
||||
|
||||
data = json.loads(resp.read())
|
||||
return data["key_id"], data["key"]
|
||||
|
||||
|
||||
def encrypt_secret(public_key: str, secret_value: str) -> str:
|
||||
"""Encrypt a secret value using GitHub's public key."""
|
||||
key = public.PublicKey(
|
||||
public_key.encode("utf-8"),
|
||||
encoding.Base64Encoder(), # type: ignore [arg-type]
|
||||
)
|
||||
sealed_box = public.SealedBox(key)
|
||||
encrypted = sealed_box.encrypt(secret_value.encode("utf-8"))
|
||||
return encoding.Base64Encoder.encode(encrypted).decode("utf-8")
|
||||
|
||||
|
||||
def check_secret(
|
||||
module: AnsibleModule,
|
||||
api_url: str,
|
||||
headers: dict[str, str],
|
||||
organization: str,
|
||||
repository: str,
|
||||
key: str,
|
||||
) -> dict[str, int]:
|
||||
url = (
|
||||
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
|
||||
if repository
|
||||
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
|
||||
)
|
||||
|
||||
resp, info = fetch_url(module, url, headers=headers)
|
||||
|
||||
if info["status"] in (HTTPStatus.OK, HTTPStatus.NOT_FOUND):
|
||||
return {"status": info["status"]}
|
||||
else:
|
||||
module.fail_json(msg=f"Failed to check secret: {info}")
|
||||
|
||||
|
||||
def upsert_secret(
|
||||
module: AnsibleModule,
|
||||
api_url: str,
|
||||
headers: dict[str, str],
|
||||
organization: str,
|
||||
repository: str,
|
||||
key: str,
|
||||
encrypted_value: str,
|
||||
key_id: str,
|
||||
) -> dict[str, t.Any]:
|
||||
"""Create or update a GitHub Actions secret."""
|
||||
url = (
|
||||
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
|
||||
if repository
|
||||
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
|
||||
)
|
||||
|
||||
payload = {
|
||||
"encrypted_value": encrypted_value,
|
||||
"key_id": key_id,
|
||||
}
|
||||
|
||||
if not repository and module.params.get("visibility"):
|
||||
payload["visibility"] = module.params["visibility"]
|
||||
|
||||
if module.check_mode:
|
||||
secret_present = check_secret(module, api_url, headers, organization, repository, key)
|
||||
if secret_present["status"] == HTTPStatus.NOT_FOUND:
|
||||
check_mode_msg = "OK (2 bytes)"
|
||||
check_mode_status = HTTPStatus.CREATED.value
|
||||
|
||||
info = {
|
||||
"msg": check_mode_msg,
|
||||
"status": check_mode_status,
|
||||
}
|
||||
else:
|
||||
check_mode_msg = "OK (unknown bytes)"
|
||||
check_mode_status = HTTPStatus.NO_CONTENT
|
||||
|
||||
info = {
|
||||
"msg": check_mode_msg,
|
||||
"status": check_mode_status,
|
||||
}
|
||||
else:
|
||||
resp, info = fetch_url(
|
||||
module,
|
||||
url,
|
||||
headers=headers,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
method="PUT",
|
||||
)
|
||||
|
||||
if info["status"] not in (HTTPStatus.CREATED, HTTPStatus.NO_CONTENT):
|
||||
module.fail_json(msg=f"Failed to upsert secret: {info}")
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def delete_secret(
|
||||
module: AnsibleModule,
|
||||
api_url: str,
|
||||
headers: dict[str, str],
|
||||
organization: str,
|
||||
repository: str,
|
||||
key: str,
|
||||
) -> dict[str, t.Any]:
|
||||
"""Delete a GitHub Actions secret."""
|
||||
url = (
|
||||
f"{api_url}/repos/{organization}/{repository}/actions/secrets/{key}"
|
||||
if repository
|
||||
else f"{api_url}/orgs/{organization}/actions/secrets/{key}"
|
||||
)
|
||||
|
||||
if module.check_mode:
|
||||
secret_present = check_secret(module, api_url, headers, organization, repository, key)
|
||||
info = {
|
||||
"msg": (
|
||||
"HTTP Error 404: Not Found"
|
||||
if secret_present["status"] == HTTPStatus.NOT_FOUND
|
||||
else "OK (unknown bytes)"
|
||||
),
|
||||
"status": (
|
||||
HTTPStatus.NO_CONTENT if secret_present["status"] == HTTPStatus.OK else secret_present["status"]
|
||||
),
|
||||
}
|
||||
else:
|
||||
resp, info = fetch_url(
|
||||
module,
|
||||
url,
|
||||
headers=headers,
|
||||
method="DELETE",
|
||||
)
|
||||
|
||||
if info["status"] not in (HTTPStatus.NO_CONTENT, HTTPStatus.NOT_FOUND):
|
||||
module.fail_json(msg=f"Failed to delete secret: {info}")
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Ansible module entry point."""
|
||||
argument_spec = {
|
||||
"organization": {
|
||||
"type": "str",
|
||||
"aliases": ["org", "username"],
|
||||
"required": True,
|
||||
},
|
||||
"repository": {"type": "str", "aliases": ["repo"]},
|
||||
"key": {"type": "str", "no_log": False},
|
||||
"value": {"type": "str", "no_log": True},
|
||||
"visibility": {"type": "str", "choices": ["all", "private", "selected"]},
|
||||
"state": {
|
||||
"type": "str",
|
||||
"choices": ["present", "absent"],
|
||||
"default": "present",
|
||||
},
|
||||
"api_url": {"type": "str", "default": "https://api.github.com"},
|
||||
"token": {"type": "str", "required": True, "no_log": True},
|
||||
}
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
required_if=[("state", "present", ["value"])],
|
||||
required_by={"value": "key"},
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
deps.validate(module)
|
||||
|
||||
organization: str = module.params["organization"]
|
||||
repository: str = module.params["repository"]
|
||||
key: str = module.params["key"]
|
||||
value: str = module.params["value"]
|
||||
visibility: str = module.params.get("visibility")
|
||||
state: str = module.params["state"]
|
||||
api_url: str = module.params["api_url"]
|
||||
token: str = module.params["token"]
|
||||
|
||||
if state == "present" and value is None:
|
||||
module.fail_json(
|
||||
msg="Invalid parameters",
|
||||
details="The 'value' parameter cannot be empty",
|
||||
params=module.params,
|
||||
)
|
||||
|
||||
if state == "present" and not repository and not visibility:
|
||||
module.fail_json(
|
||||
msg="Invalid parameters",
|
||||
details="When 'state' is 'present' and 'repository' is not set, 'visibility' must be provided",
|
||||
params=module.params,
|
||||
)
|
||||
|
||||
result: dict[str, t.Any] = {}
|
||||
|
||||
headers = {
|
||||
"Accept": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
if state == "present":
|
||||
key_id, public_key = get_public_key(
|
||||
module,
|
||||
api_url,
|
||||
headers,
|
||||
organization,
|
||||
repository,
|
||||
)
|
||||
|
||||
encrypted_value = encrypt_secret(public_key, value)
|
||||
|
||||
upsert = upsert_secret(
|
||||
module,
|
||||
api_url,
|
||||
headers,
|
||||
organization,
|
||||
repository,
|
||||
key,
|
||||
encrypted_value,
|
||||
key_id,
|
||||
)
|
||||
|
||||
response_msg = "Secret created" if upsert["status"] == HTTPStatus.CREATED else "Secret updated"
|
||||
|
||||
result["changed"] = True
|
||||
result.update(
|
||||
result={
|
||||
"status": upsert["status"],
|
||||
"msg": upsert.get("msg"),
|
||||
"response": response_msg,
|
||||
},
|
||||
)
|
||||
|
||||
if state == "absent":
|
||||
delete = delete_secret(
|
||||
module,
|
||||
api_url,
|
||||
headers,
|
||||
organization,
|
||||
repository,
|
||||
key,
|
||||
)
|
||||
|
||||
if delete["status"] == HTTPStatus.NO_CONTENT:
|
||||
result["changed"] = True
|
||||
result.update(
|
||||
result={
|
||||
"status": delete["status"],
|
||||
"msg": delete.get("msg"),
|
||||
"response": "Secret deleted",
|
||||
},
|
||||
)
|
||||
|
||||
if delete["status"] == HTTPStatus.NOT_FOUND:
|
||||
result["changed"] = False
|
||||
result.update(
|
||||
result={
|
||||
"status": delete["status"],
|
||||
"msg": delete.get("msg"),
|
||||
"response": "Secret not found",
|
||||
},
|
||||
)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
158
plugins/modules/github_secrets_info.py
Normal file
158
plugins/modules/github_secrets_info.py
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) Ansible project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
module: github_secrets_info
|
||||
short_description: List GitHub repository or organization secrets
|
||||
description:
|
||||
- List secrets in a GitHub repository or organization.
|
||||
author:
|
||||
- Thomas Sjögren (@konstruktoid)
|
||||
version_added: '12.5.0'
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
options:
|
||||
organization:
|
||||
description:
|
||||
- The GitHub username or organization name.
|
||||
type: str
|
||||
required: true
|
||||
aliases: ["org", "username"]
|
||||
repository:
|
||||
description:
|
||||
- The name of the repository.
|
||||
- If not provided, the listing will be at organization level.
|
||||
type: str
|
||||
aliases: ["repo"]
|
||||
api_url:
|
||||
description:
|
||||
- The base URL for the GitHub API.
|
||||
type: str
|
||||
default: "https://api.github.com"
|
||||
token:
|
||||
description:
|
||||
- The GitHub token used for authentication.
|
||||
type: str
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: List Github secret
|
||||
community.general.github_secrets_info:
|
||||
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
|
||||
repository: "ansible"
|
||||
organization: "ansible"
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
secrets:
|
||||
description: The list of currently existing secrets.
|
||||
type: list
|
||||
elements: dict
|
||||
returned: success
|
||||
sample: [
|
||||
{
|
||||
"created_at": "2026-01-11T23:19:00Z",
|
||||
"name": "ANSIBLE",
|
||||
"updated_at": "2026-02-15T22:18:16Z"
|
||||
},
|
||||
]
|
||||
contains:
|
||||
name:
|
||||
description: The name of the secret.
|
||||
type: str
|
||||
created_at:
|
||||
description: The date and time when the secret was created.
|
||||
type: str
|
||||
updated_at:
|
||||
description: The date and time when the secret was last updated.
|
||||
type: str
|
||||
"""
|
||||
|
||||
import json
|
||||
import typing as t
|
||||
from http import HTTPStatus
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils import deps
|
||||
|
||||
|
||||
def list_secrets(
|
||||
module: AnsibleModule,
|
||||
api_url: str,
|
||||
headers: dict[str, str],
|
||||
organization: str,
|
||||
repository: str,
|
||||
) -> dict[str, list]:
|
||||
url = (
|
||||
f"{api_url}/repos/{organization}/{repository}/actions/secrets"
|
||||
if repository
|
||||
else f"{api_url}/orgs/{organization}/actions/secrets"
|
||||
)
|
||||
|
||||
resp, info = fetch_url(module, url, headers=headers, method="GET")
|
||||
|
||||
if info["status"] == HTTPStatus.OK:
|
||||
body = resp.read()
|
||||
return {"secrets": json.loads(body).get("secrets", [])}
|
||||
elif info["status"] == HTTPStatus.NOT_FOUND:
|
||||
return {
|
||||
"secrets": [],
|
||||
}
|
||||
else:
|
||||
module.fail_json(msg=f"Failed to list secrets: {info}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Ansible module entry point."""
|
||||
argument_spec = {
|
||||
"organization": {
|
||||
"type": "str",
|
||||
"aliases": ["org", "username"],
|
||||
"required": True,
|
||||
},
|
||||
"repository": {"type": "str", "aliases": ["repo"]},
|
||||
"api_url": {"type": "str", "default": "https://api.github.com"},
|
||||
"token": {"type": "str", "required": True, "no_log": True},
|
||||
}
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
deps.validate(module)
|
||||
|
||||
organization: str = module.params["organization"]
|
||||
repository: str = module.params["repository"]
|
||||
api_url: str = module.params["api_url"]
|
||||
token: str = module.params["token"]
|
||||
|
||||
result: dict[str, t.Any] = {}
|
||||
|
||||
headers = {
|
||||
"Accept": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
secrets = list_secrets(module, api_url, headers, organization, repository)
|
||||
|
||||
result["changed"] = False
|
||||
result.update(
|
||||
secrets=secrets["secrets"],
|
||||
)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -179,8 +179,15 @@ class GitLabProjectMembers:
|
||||
return project_exists.id
|
||||
except gitlab.exceptions.GitlabGetError:
|
||||
project_exists = self._gitlab.projects.list(search=project_name, all=False)
|
||||
if project_exists:
|
||||
if len(project_exists) == 1:
|
||||
return project_exists[0].id
|
||||
if len(project_exists) > 1:
|
||||
self._module.fail_json(
|
||||
msg=(
|
||||
f"More than one project matches '{project_name}'. "
|
||||
"Use the full path ('group/project') to disambiguate."
|
||||
)
|
||||
)
|
||||
|
||||
def get_user_id(self, gitlab_user):
|
||||
user_exists = self._gitlab.users.list(username=gitlab_user, all=False)
|
||||
|
||||
@@ -240,6 +240,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec,
|
||||
filter_returned_variables,
|
||||
find_project,
|
||||
gitlab_authentication,
|
||||
list_all_kwargs,
|
||||
vars_to_variables,
|
||||
@@ -249,11 +250,14 @@ from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
class GitlabProjectVariables:
|
||||
def __init__(self, module, gitlab_instance):
|
||||
self.repo = gitlab_instance
|
||||
self.project = self.get_project(module.params["project"])
|
||||
self._module = module
|
||||
self.project = self.get_project(module.params["project"])
|
||||
|
||||
def get_project(self, project_name):
|
||||
return self.repo.projects.get(project_name)
|
||||
project = find_project(self.repo, project_name)
|
||||
if project is None:
|
||||
self._module.fail_json(msg=f"Project {project_name} not found or insufficient permissions.")
|
||||
return project
|
||||
|
||||
def list_all_project_variables(self):
|
||||
return list(self.project.variables.list(**list_all_kwargs))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user