mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-29 09:56:53 +00:00
Compare commits
300 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc055f1741 | ||
|
|
c663a3009a | ||
|
|
cee1d9365b | ||
|
|
1a1b1654bf | ||
|
|
1f3fefa31c | ||
|
|
7efdcb618d | ||
|
|
451f34f8d7 | ||
|
|
54a4d5c110 | ||
|
|
39f163b3e9 | ||
|
|
2df9748e5e | ||
|
|
820d067c29 | ||
|
|
ec5e4919eb | ||
|
|
e7c4239640 | ||
|
|
34fd2c01f4 | ||
|
|
4689114fac | ||
|
|
09b3253edd | ||
|
|
739998779b | ||
|
|
d250bb5217 | ||
|
|
12df7f7a95 | ||
|
|
db28a2e94a | ||
|
|
fa865a19a5 | ||
|
|
d15a41d6c2 | ||
|
|
40de10b9b3 | ||
|
|
6137ffe2a4 | ||
|
|
a7770647ae | ||
|
|
0c4461f9cd | ||
|
|
2f16e78431 | ||
|
|
4002e458dd | ||
|
|
02ee120a6e | ||
|
|
78c16ca5e5 | ||
|
|
32a348d73f | ||
|
|
5a1ea5bac3 | ||
|
|
0805f97905 | ||
|
|
54fe541081 | ||
|
|
67cb03a77e | ||
|
|
010877691a | ||
|
|
827967310e | ||
|
|
fe385eb131 | ||
|
|
9f16c7baf1 | ||
|
|
e13f9c1092 | ||
|
|
1f60829b9d | ||
|
|
e6c2a12a4a | ||
|
|
0be65af9a9 | ||
|
|
3c021dc4fc | ||
|
|
2f64e8c732 | ||
|
|
5f2a8d5e59 | ||
|
|
6bc2a8e949 | ||
|
|
56662f82fe | ||
|
|
938ed56d70 | ||
|
|
1357e47f92 | ||
|
|
cc6d4209d4 | ||
|
|
01134d4625 | ||
|
|
16089ab2de | ||
|
|
0da4607c7f | ||
|
|
46cbf60c2d | ||
|
|
e7d86f5add | ||
|
|
ee4c76fa43 | ||
|
|
095d09ec12 | ||
|
|
d9ed00fb12 | ||
|
|
94bb204e29 | ||
|
|
9b1f450102 | ||
|
|
dd3bc067f5 | ||
|
|
15916cd61f | ||
|
|
02a257569a | ||
|
|
c486e42faa | ||
|
|
7f7e622262 | ||
|
|
e1551b3d34 | ||
|
|
a3bc0535a5 | ||
|
|
9e59665bee | ||
|
|
30b29d24ab | ||
|
|
d5efc3f13a | ||
|
|
d237faa447 | ||
|
|
65ce979d4a | ||
|
|
938367b67a | ||
|
|
578df1b054 | ||
|
|
0b494a5d2d | ||
|
|
f92043c7f5 | ||
|
|
839336c21d | ||
|
|
2a5e4b8a46 | ||
|
|
fae1dbc198 | ||
|
|
dc7aba3bca | ||
|
|
03c66d0db4 | ||
|
|
5707fc1b33 | ||
|
|
830e3988aa | ||
|
|
f4ccef462e | ||
|
|
cd26dd6b0a | ||
|
|
009bfd786d | ||
|
|
9f08cc11a8 | ||
|
|
cae4bc80af | ||
|
|
058462973e | ||
|
|
23dc90812f | ||
|
|
97e17fcee2 | ||
|
|
d75d5f67f7 | ||
|
|
c597a75372 | ||
|
|
031a3b56bf | ||
|
|
5fd87a1811 | ||
|
|
e463f94ce9 | ||
|
|
4205a94f0c | ||
|
|
bcfcdd1052 | ||
|
|
2638413475 | ||
|
|
9ea55a81b3 | ||
|
|
32c1e39df1 | ||
|
|
7bb23e9649 | ||
|
|
eeedd97eec | ||
|
|
4e1ba6af46 | ||
|
|
aa1ae85b55 | ||
|
|
4d2873afd2 | ||
|
|
43c1d9f66c | ||
|
|
201f49acd9 | ||
|
|
6f0d46d0a2 | ||
|
|
92529d5605 | ||
|
|
f635ed6c2e | ||
|
|
0e0fce54ab | ||
|
|
caae74abd8 | ||
|
|
c01a16c1bc | ||
|
|
15c832b8d5 | ||
|
|
b104c580e1 | ||
|
|
a4e1beefe3 | ||
|
|
b0898e5c51 | ||
|
|
eca1d0191f | ||
|
|
08036e7f65 | ||
|
|
3c6c9ba425 | ||
|
|
3eeb0009cb | ||
|
|
c92215d339 | ||
|
|
1a4ae5e9aa | ||
|
|
9ecfa370ff | ||
|
|
f3828ebdd7 | ||
|
|
7b71ffa1c4 | ||
|
|
d7494bb9e4 | ||
|
|
443a1c3ed7 | ||
|
|
177e327c24 | ||
|
|
6ff4b479ab | ||
|
|
feb8d421dc | ||
|
|
d633f6c4c8 | ||
|
|
3405b24fa6 | ||
|
|
540c92fa62 | ||
|
|
8cf2358fb1 | ||
|
|
2d92ab91eb | ||
|
|
d03abae7a1 | ||
|
|
d7efa7eb13 | ||
|
|
a9a9e723e5 | ||
|
|
3d87fbf6f9 | ||
|
|
9e6960639f | ||
|
|
7074a52721 | ||
|
|
d18afe6746 | ||
|
|
ee03af599c | ||
|
|
42c643ddda | ||
|
|
a7d89fc1ee | ||
|
|
d4477615a9 | ||
|
|
c84738324e | ||
|
|
0c3ae48f85 | ||
|
|
a3c711491a | ||
|
|
d6a57882d2 | ||
|
|
edbef2266d | ||
|
|
2b88ee01d3 | ||
|
|
afd24ccd35 | ||
|
|
26ada26df1 | ||
|
|
59999a89f1 | ||
|
|
e1f4be1e01 | ||
|
|
e7e2f095ee | ||
|
|
45200fc233 | ||
|
|
154d1b7024 | ||
|
|
541fcec900 | ||
|
|
dc6ccbea63 | ||
|
|
6cb044ac13 | ||
|
|
af78b2068a | ||
|
|
73569b1c36 | ||
|
|
5914c1df8e | ||
|
|
f847531a35 | ||
|
|
df01cde23d | ||
|
|
cdd9ced441 | ||
|
|
dfb61b283d | ||
|
|
fe7b151a26 | ||
|
|
9b983fba86 | ||
|
|
2d27dbd9ea | ||
|
|
55cbccf0fc | ||
|
|
675860c392 | ||
|
|
5e8914e00c | ||
|
|
c0230342b4 | ||
|
|
ebf15447f0 | ||
|
|
86d10f53fd | ||
|
|
d679f51018 | ||
|
|
e9e494e1ff | ||
|
|
bf90b4e88a | ||
|
|
874d7f7050 | ||
|
|
3a19fbc89c | ||
|
|
2d8e1339d1 | ||
|
|
4892f954fa | ||
|
|
6fd58ba388 | ||
|
|
49967547df | ||
|
|
492170b414 | ||
|
|
25b9391fb4 | ||
|
|
1e30afa92f | ||
|
|
7d4e69cdf7 | ||
|
|
ff23e41c21 | ||
|
|
3ce7d2fc7e | ||
|
|
20a9d120aa | ||
|
|
f4a40592a1 | ||
|
|
3d5145e924 | ||
|
|
1ae5a2cd05 | ||
|
|
75aa353281 | ||
|
|
5fe10915a8 | ||
|
|
eca6494503 | ||
|
|
b12d422fcc | ||
|
|
33809395ab | ||
|
|
60fe6ebc3c | ||
|
|
957f3e6eca | ||
|
|
dbd918865f | ||
|
|
46a83df85e | ||
|
|
57f262504d | ||
|
|
29671cb54c | ||
|
|
fd91e94279 | ||
|
|
b001e36fb3 | ||
|
|
5f63476404 | ||
|
|
eff452e4a5 | ||
|
|
d393b16064 | ||
|
|
40b5967fc3 | ||
|
|
ccabc342b9 | ||
|
|
570f6a8791 | ||
|
|
b10cf1e357 | ||
|
|
acfe464a31 | ||
|
|
f32a8dc740 | ||
|
|
ea8f109056 | ||
|
|
7e7b84348b | ||
|
|
baf552337d | ||
|
|
3ff9161ab0 | ||
|
|
aa8728b22c | ||
|
|
590ff351b4 | ||
|
|
a5824a2a9d | ||
|
|
71975be3c1 | ||
|
|
564f87c775 | ||
|
|
6750a866c6 | ||
|
|
c6316c1153 | ||
|
|
2c825f04e7 | ||
|
|
8a33e070be | ||
|
|
d2a5fdfc71 | ||
|
|
b6b2419206 | ||
|
|
4c399f1c01 | ||
|
|
923d335646 | ||
|
|
be96c33257 | ||
|
|
e68b1017e3 | ||
|
|
44e4b1d202 | ||
|
|
24378fd944 | ||
|
|
c3e1715233 | ||
|
|
ec86ebed98 | ||
|
|
5aa2779a48 | ||
|
|
f6d15ec818 | ||
|
|
f0320b5ac9 | ||
|
|
79578e5db3 | ||
|
|
43beaf4b00 | ||
|
|
6b0cc3c1de | ||
|
|
81a95a347d | ||
|
|
8026337c44 | ||
|
|
8fb1aaaf53 | ||
|
|
fda610cc23 | ||
|
|
8ecb322816 | ||
|
|
1260a63241 | ||
|
|
f6aad230c2 | ||
|
|
f3a4e5ea27 | ||
|
|
e26eaa0565 | ||
|
|
3432be3a2f | ||
|
|
4f78e7979e | ||
|
|
8a0b7dcdc9 | ||
|
|
9cd3f37686 | ||
|
|
5e1508e0df | ||
|
|
be4d294b61 | ||
|
|
1d36db1806 | ||
|
|
16a18d1456 | ||
|
|
493fa405e2 | ||
|
|
25464602d9 | ||
|
|
8a670a3929 | ||
|
|
47b8df8019 | ||
|
|
9c411586ea | ||
|
|
e0465d1f48 | ||
|
|
ad6c28069a | ||
|
|
31a1c8e185 | ||
|
|
20bd0d130c | ||
|
|
e5ecaffa1a | ||
|
|
8fd89721cd | ||
|
|
b1231c1315 | ||
|
|
48b20894b3 | ||
|
|
1676b09573 | ||
|
|
94efecaf67 | ||
|
|
e9bc32528e | ||
|
|
8e84b3ef8e | ||
|
|
944bc78360 | ||
|
|
a2a81f11c3 | ||
|
|
1a72aea4c5 | ||
|
|
36eff2fd99 | ||
|
|
47514e1401 | ||
|
|
186b4200f6 | ||
|
|
6057c3c7c4 | ||
|
|
b12113c182 | ||
|
|
4860c20108 | ||
|
|
8efbd8172c | ||
|
|
8c1b7e3ddb | ||
|
|
ec228bf32f | ||
|
|
1d39bbefd9 | ||
|
|
59fb0cf506 | ||
|
|
6c4080e78d |
@@ -1,425 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- stable-*
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- stable-*
|
||||
|
||||
schedules:
|
||||
- cron: 0 8 * * *
|
||||
displayName: Nightly (main)
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
- cron: 0 10 * * *
|
||||
displayName: Nightly (active stable branches)
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-6
|
||||
- stable-5
|
||||
- cron: 0 11 * * 0
|
||||
displayName: Weekly (old stable branches)
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-4
|
||||
|
||||
variables:
|
||||
- name: checkoutPath
|
||||
value: ansible_collections/community/general
|
||||
- name: coverageBranches
|
||||
value: main
|
||||
- name: pipelinesCoverage
|
||||
value: coverage
|
||||
- name: entryPoint
|
||||
value: tests/utils/shippable/shippable.sh
|
||||
- name: fetchDepth
|
||||
value: 0
|
||||
|
||||
resources:
|
||||
containers:
|
||||
- container: default
|
||||
image: quay.io/ansible/azure-pipelines-test-container:3.0.0
|
||||
|
||||
pool: Standard
|
||||
|
||||
stages:
|
||||
### Sanity
|
||||
- stage: Sanity_devel
|
||||
displayName: Sanity devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: devel/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- test: extra
|
||||
- stage: Sanity_2_14
|
||||
displayName: Sanity 2.14
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.14/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_13
|
||||
displayName: Sanity 2.13
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.13/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
- stage: Sanity_2_12
|
||||
displayName: Sanity 2.12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Test {0}
|
||||
testFormat: 2.12/sanity/{0}
|
||||
targets:
|
||||
- test: 1
|
||||
- test: 2
|
||||
- test: 3
|
||||
- test: 4
|
||||
### Units
|
||||
- stage: Units_devel
|
||||
displayName: Units devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: devel/units/{0}/1
|
||||
targets:
|
||||
- test: 2.7
|
||||
- test: 3.5
|
||||
- test: 3.6
|
||||
- test: 3.7
|
||||
- test: 3.8
|
||||
- test: 3.9
|
||||
- test: '3.10'
|
||||
- test: '3.11'
|
||||
- stage: Units_2_14
|
||||
displayName: Units 2.14
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.14/units/{0}/1
|
||||
targets:
|
||||
- test: 2.7
|
||||
- test: 3.9
|
||||
- stage: Units_2_13
|
||||
displayName: Units 2.13
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.13/units/{0}/1
|
||||
targets:
|
||||
- test: 2.7
|
||||
- test: 3.8
|
||||
- stage: Units_2_12
|
||||
displayName: Units 2.12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.12/units/{0}/1
|
||||
targets:
|
||||
- test: 2.6
|
||||
- test: 3.8
|
||||
|
||||
## Remote
|
||||
- stage: Remote_devel_extra_vms
|
||||
displayName: Remote devel extra VMs
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: Alpine 3.17
|
||||
test: alpine/3.17
|
||||
# - name: Fedora 37
|
||||
# test: fedora/37
|
||||
# - name: Ubuntu 20.04
|
||||
# test: ubuntu/20.04
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu/22.04
|
||||
groups:
|
||||
- vm
|
||||
- stage: Remote_devel
|
||||
displayName: Remote devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/{0}
|
||||
targets:
|
||||
- name: macOS 12.0
|
||||
test: macos/12.0
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
- name: RHEL 9.1
|
||||
test: rhel/9.1
|
||||
- name: FreeBSD 13.1
|
||||
test: freebsd/13.1
|
||||
- name: FreeBSD 12.4
|
||||
test: freebsd/12.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_14
|
||||
displayName: Remote 2.14
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.14/{0}
|
||||
targets:
|
||||
- name: RHEL 9.0
|
||||
test: rhel/9.0
|
||||
- name: FreeBSD 12.3
|
||||
test: freebsd/12.3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_13
|
||||
displayName: Remote 2.13
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.13/{0}
|
||||
targets:
|
||||
- name: macOS 12.0
|
||||
test: macos/12.0
|
||||
- name: RHEL 8.5
|
||||
test: rhel/8.5
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Remote_2_12
|
||||
displayName: Remote 2.12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.12/{0}
|
||||
targets:
|
||||
- name: macOS 11.1
|
||||
test: macos/11.1
|
||||
- name: RHEL 8.4
|
||||
test: rhel/8.4
|
||||
- name: FreeBSD 13.0
|
||||
test: freebsd/13.0
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Docker
|
||||
- stage: Docker_devel
|
||||
displayName: Docker devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}
|
||||
targets:
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: Fedora 37
|
||||
test: fedora37
|
||||
- name: openSUSE 15
|
||||
test: opensuse15
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- name: Alpine 3
|
||||
test: alpine3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_14
|
||||
displayName: Docker 2.14
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.14/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 36
|
||||
test: fedora36
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_13
|
||||
displayName: Docker 2.13
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.13/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 35
|
||||
test: fedora35
|
||||
- name: openSUSE 15 py2
|
||||
test: opensuse15py2
|
||||
- name: Alpine 3
|
||||
test: alpine3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- stage: Docker_2_12
|
||||
displayName: Docker 2.12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.12/linux/{0}
|
||||
targets:
|
||||
- name: CentOS 6
|
||||
test: centos6
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: Ubuntu 18.04
|
||||
test: ubuntu1804
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Community Docker
|
||||
- stage: Docker_community_devel
|
||||
displayName: Docker (community images) devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: devel/linux-community/{0}
|
||||
targets:
|
||||
- name: Debian Bullseye
|
||||
test: debian-bullseye/3.9
|
||||
- name: ArchLinux
|
||||
test: archlinux/3.10
|
||||
- name: CentOS Stream 8
|
||||
test: centos-stream8/3.9
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
|
||||
### Generic
|
||||
- stage: Generic_devel
|
||||
displayName: Generic devel
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: devel/generic/{0}/1
|
||||
targets:
|
||||
- test: 2.7
|
||||
- test: '3.11'
|
||||
- stage: Generic_2_14
|
||||
displayName: Generic 2.14
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.14/generic/{0}/1
|
||||
targets:
|
||||
- test: '3.10'
|
||||
- stage: Generic_2_13
|
||||
displayName: Generic 2.13
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.13/generic/{0}/1
|
||||
targets:
|
||||
- test: 3.9
|
||||
- stage: Generic_2_12
|
||||
displayName: Generic 2.12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: Python {0}
|
||||
testFormat: 2.12/generic/{0}/1
|
||||
targets:
|
||||
- test: 3.8
|
||||
|
||||
- stage: Summary
|
||||
condition: succeededOrFailed()
|
||||
dependsOn:
|
||||
- Sanity_devel
|
||||
- Sanity_2_12
|
||||
- Sanity_2_13
|
||||
- Sanity_2_14
|
||||
- Units_devel
|
||||
- Units_2_12
|
||||
- Units_2_13
|
||||
- Units_2_14
|
||||
- Remote_devel_extra_vms
|
||||
- Remote_devel
|
||||
- Remote_2_12
|
||||
- Remote_2_13
|
||||
- Remote_2_14
|
||||
- Docker_devel
|
||||
- Docker_2_12
|
||||
- Docker_2_13
|
||||
- Docker_2_14
|
||||
- Docker_community_devel
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - Generic_devel
|
||||
# - Generic_2_12
|
||||
# - Generic_2_13
|
||||
# - Generic_2_14
|
||||
jobs:
|
||||
- template: templates/coverage.yml
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# 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
|
||||
|
||||
# Aggregate code coverage results for later processing.
|
||||
|
||||
set -o pipefail -eu
|
||||
|
||||
agent_temp_directory="$1"
|
||||
|
||||
PATH="${PWD}/bin:${PATH}"
|
||||
|
||||
mkdir "${agent_temp_directory}/coverage/"
|
||||
|
||||
options=(--venv --venv-system-site-packages --color -v)
|
||||
|
||||
ansible-test coverage combine --group-by command --export "${agent_temp_directory}/coverage/" "${options[@]}"
|
||||
|
||||
if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then
|
||||
# Only analyze coverage if the installed version of ansible-test supports it.
|
||||
# Doing so allows this script to work unmodified for multiple Ansible versions.
|
||||
ansible-test coverage analyze targets generate "${agent_temp_directory}/coverage/coverage-analyze-targets.json" "${options[@]}"
|
||||
fi
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env 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
|
||||
|
||||
"""
|
||||
Combine coverage data from multiple jobs, keeping the data only from the most recent attempt from each job.
|
||||
Coverage artifacts must be named using the format: "Coverage $(System.JobAttempt) {StableUniqueNameForEachJob}"
|
||||
The recommended coverage artifact name format is: Coverage $(System.JobAttempt) $(System.StageDisplayName) $(System.JobDisplayName)
|
||||
Keep in mind that Azure Pipelines does not enforce unique job display names (only names).
|
||||
It is up to pipeline authors to avoid name collisions when deviating from the recommended format.
|
||||
"""
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Main program entry point."""
|
||||
source_directory = sys.argv[1]
|
||||
|
||||
if '/ansible_collections/' in os.getcwd():
|
||||
output_path = "tests/output"
|
||||
else:
|
||||
output_path = "test/results"
|
||||
|
||||
destination_directory = os.path.join(output_path, 'coverage')
|
||||
|
||||
if not os.path.exists(destination_directory):
|
||||
os.makedirs(destination_directory)
|
||||
|
||||
jobs = {}
|
||||
count = 0
|
||||
|
||||
for name in os.listdir(source_directory):
|
||||
match = re.search('^Coverage (?P<attempt>[0-9]+) (?P<label>.+)$', name)
|
||||
label = match.group('label')
|
||||
attempt = int(match.group('attempt'))
|
||||
jobs[label] = max(attempt, jobs.get(label, 0))
|
||||
|
||||
for label, attempt in jobs.items():
|
||||
name = 'Coverage {attempt} {label}'.format(label=label, attempt=attempt)
|
||||
source = os.path.join(source_directory, name)
|
||||
source_files = os.listdir(source)
|
||||
|
||||
for source_file in source_files:
|
||||
source_path = os.path.join(source, source_file)
|
||||
destination_path = os.path.join(destination_directory, source_file + '.' + label)
|
||||
print('"%s" -> "%s"' % (source_path, destination_path))
|
||||
shutil.copyfile(source_path, destination_path)
|
||||
count += 1
|
||||
|
||||
print('Coverage file count: %d' % count)
|
||||
print('##vso[task.setVariable variable=coverageFileCount]%d' % count)
|
||||
print('##vso[task.setVariable variable=outputPath]%s' % output_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# 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
|
||||
|
||||
# Check the test results and set variables for use in later steps.
|
||||
|
||||
set -o pipefail -eu
|
||||
|
||||
if [[ "$PWD" =~ /ansible_collections/ ]]; then
|
||||
output_path="tests/output"
|
||||
else
|
||||
output_path="test/results"
|
||||
fi
|
||||
|
||||
echo "##vso[task.setVariable variable=outputPath]${output_path}"
|
||||
|
||||
if compgen -G "${output_path}"'/junit/*.xml' > /dev/null; then
|
||||
echo "##vso[task.setVariable variable=haveTestResults]true"
|
||||
fi
|
||||
|
||||
if compgen -G "${output_path}"'/bot/ansible-test-*' > /dev/null; then
|
||||
echo "##vso[task.setVariable variable=haveBotResults]true"
|
||||
fi
|
||||
|
||||
if compgen -G "${output_path}"'/coverage/*' > /dev/null; then
|
||||
echo "##vso[task.setVariable variable=haveCoverageData]true"
|
||||
fi
|
||||
@@ -1,105 +0,0 @@
|
||||
#!/usr/bin/env 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
|
||||
|
||||
"""
|
||||
Upload code coverage reports to codecov.io.
|
||||
Multiple coverage files from multiple languages are accepted and aggregated after upload.
|
||||
Python coverage, as well as PowerShell and Python stubs can all be uploaded.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import dataclasses
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import typing as t
|
||||
import urllib.request
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CoverageFile:
|
||||
name: str
|
||||
path: pathlib.Path
|
||||
flags: t.List[str]
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Args:
|
||||
dry_run: bool
|
||||
path: pathlib.Path
|
||||
|
||||
|
||||
def parse_args() -> Args:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-n', '--dry-run', action='store_true')
|
||||
parser.add_argument('path', type=pathlib.Path)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Store arguments in a typed dataclass
|
||||
fields = dataclasses.fields(Args)
|
||||
kwargs = {field.name: getattr(args, field.name) for field in fields}
|
||||
|
||||
return Args(**kwargs)
|
||||
|
||||
|
||||
def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]:
|
||||
processed = []
|
||||
for file in directory.joinpath('reports').glob('coverage*.xml'):
|
||||
name = file.stem.replace('coverage=', '')
|
||||
|
||||
# Get flags from name
|
||||
flags = name.replace('-powershell', '').split('=') # Drop '-powershell' suffix
|
||||
flags = [flag if not flag.startswith('stub') else flag.split('-')[0] for flag in flags] # Remove "-01" from stub files
|
||||
|
||||
processed.append(CoverageFile(name, file, flags))
|
||||
|
||||
return tuple(processed)
|
||||
|
||||
|
||||
def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], dry_run: bool = False) -> None:
|
||||
for file in files:
|
||||
cmd = [
|
||||
str(codecov_bin),
|
||||
'--name', file.name,
|
||||
'--file', str(file.path),
|
||||
]
|
||||
for flag in file.flags:
|
||||
cmd.extend(['--flags', flag])
|
||||
|
||||
if dry_run:
|
||||
print(f'DRY-RUN: Would run command: {cmd}')
|
||||
continue
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
|
||||
def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = False) -> None:
|
||||
if dry_run:
|
||||
print(f'DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}')
|
||||
return
|
||||
|
||||
with urllib.request.urlopen(url) as resp:
|
||||
with dest.open('w+b') as f:
|
||||
# Read data in chunks rather than all at once
|
||||
shutil.copyfileobj(resp, f, 64 * 1024)
|
||||
|
||||
dest.chmod(flags)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
url = 'https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov'
|
||||
with tempfile.TemporaryDirectory(prefix='codecov-') as tmpdir:
|
||||
codecov_bin = pathlib.Path(tmpdir) / 'codecov'
|
||||
download_file(url, codecov_bin, 0o755, args.dry_run)
|
||||
|
||||
files = process_files(args.path)
|
||||
upload_files(codecov_bin, files, args.dry_run)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# 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
|
||||
|
||||
# Generate code coverage reports for uploading to Azure Pipelines and codecov.io.
|
||||
|
||||
set -o pipefail -eu
|
||||
|
||||
PATH="${PWD}/bin:${PATH}"
|
||||
|
||||
if ! ansible-test --help >/dev/null 2>&1; then
|
||||
# Install the devel version of ansible-test for generating code coverage reports.
|
||||
# This is only used by Ansible Collections, which are typically tested against multiple Ansible versions (in separate jobs).
|
||||
# Since a version of ansible-test is required that can work the output from multiple older releases, the devel version is used.
|
||||
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
|
||||
fi
|
||||
|
||||
ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# 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
|
||||
|
||||
# Configure the test environment and run the tests.
|
||||
|
||||
set -o pipefail -eu
|
||||
|
||||
entry_point="$1"
|
||||
test="$2"
|
||||
read -r -a coverage_branches <<< "$3" # space separated list of branches to run code coverage on for scheduled builds
|
||||
|
||||
export COMMIT_MESSAGE
|
||||
export COMPLETE
|
||||
export COVERAGE
|
||||
export IS_PULL_REQUEST
|
||||
|
||||
if [ "${SYSTEM_PULLREQUEST_TARGETBRANCH:-}" ]; then
|
||||
IS_PULL_REQUEST=true
|
||||
COMMIT_MESSAGE=$(git log --format=%B -n 1 HEAD^2)
|
||||
else
|
||||
IS_PULL_REQUEST=
|
||||
COMMIT_MESSAGE=$(git log --format=%B -n 1 HEAD)
|
||||
fi
|
||||
|
||||
COMPLETE=
|
||||
COVERAGE=
|
||||
|
||||
if [ "${BUILD_REASON}" = "Schedule" ]; then
|
||||
COMPLETE=yes
|
||||
|
||||
if printf '%s\n' "${coverage_branches[@]}" | grep -q "^${BUILD_SOURCEBRANCHNAME}$"; then
|
||||
COVERAGE=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
"${entry_point}" "${test}" 2>&1 | "$(dirname "$0")/time-command.py"
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env 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
|
||||
|
||||
"""Prepends a relative timestamp to each input line from stdin and writes it to stdout."""
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def main():
|
||||
"""Main program entry point."""
|
||||
start = time.time()
|
||||
|
||||
sys.stdin.reconfigure(errors='surrogateescape')
|
||||
sys.stdout.reconfigure(errors='surrogateescape')
|
||||
|
||||
for line in sys.stdin:
|
||||
seconds = time.time() - start
|
||||
sys.stdout.write('%02d:%02d %s' % (seconds // 60, seconds % 60, line))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,44 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# This template adds a job for processing code coverage data.
|
||||
# It will upload results to Azure Pipelines and codecov.io.
|
||||
# Use it from a job stage that completes after all other jobs have completed.
|
||||
# This can be done by placing it in a separate summary stage that runs after the test stage(s) have completed.
|
||||
|
||||
jobs:
|
||||
- job: Coverage
|
||||
displayName: Code Coverage
|
||||
container: default
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: $(fetchDepth)
|
||||
path: $(checkoutPath)
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download Coverage Data
|
||||
inputs:
|
||||
path: coverage/
|
||||
patterns: "Coverage */*=coverage.combined"
|
||||
- bash: .azure-pipelines/scripts/combine-coverage.py coverage/
|
||||
displayName: Combine Coverage Data
|
||||
- bash: .azure-pipelines/scripts/report-coverage.sh
|
||||
displayName: Generate Coverage Report
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- task: PublishCodeCoverageResults@1
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
# Azure Pipelines only accepts a single coverage data file.
|
||||
# That means only Python or PowerShell coverage can be uploaded, but not both.
|
||||
# Set the "pipelinesCoverage" variable to determine which type is uploaded.
|
||||
# Use "coverage" for Python and "coverage-powershell" for PowerShell.
|
||||
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
||||
displayName: Publish to Azure Pipelines
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
|
||||
displayName: Publish to codecov.io
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
continueOnError: true
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# This template uses the provided targets and optional groups to generate a matrix which is then passed to the test template.
|
||||
# If this matrix template does not provide the required functionality, consider using the test template directly instead.
|
||||
|
||||
parameters:
|
||||
# A required list of dictionaries, one per test target.
|
||||
# Each item in the list must contain a "test" or "name" key.
|
||||
# Both may be provided. If one is omitted, the other will be used.
|
||||
- name: targets
|
||||
type: object
|
||||
|
||||
# An optional list of values which will be used to multiply the targets list into a matrix.
|
||||
# Values can be strings or numbers.
|
||||
- name: groups
|
||||
type: object
|
||||
default: []
|
||||
|
||||
# An optional format string used to generate the job name.
|
||||
# - {0} is the name of an item in the targets list.
|
||||
- name: nameFormat
|
||||
type: string
|
||||
default: "{0}"
|
||||
|
||||
# An optional format string used to generate the test name.
|
||||
# - {0} is the name of an item in the targets list.
|
||||
- name: testFormat
|
||||
type: string
|
||||
default: "{0}"
|
||||
|
||||
# An optional format string used to add the group to the job name.
|
||||
# {0} is the formatted name of an item in the targets list.
|
||||
# {{1}} is the group -- be sure to include the double "{{" and "}}".
|
||||
- name: nameGroupFormat
|
||||
type: string
|
||||
default: "{0} - {{1}}"
|
||||
|
||||
# An optional format string used to add the group to the test name.
|
||||
# {0} is the formatted test of an item in the targets list.
|
||||
# {{1}} is the group -- be sure to include the double "{{" and "}}".
|
||||
- name: testGroupFormat
|
||||
type: string
|
||||
default: "{0}/{{1}}"
|
||||
|
||||
jobs:
|
||||
- template: test.yml
|
||||
parameters:
|
||||
jobs:
|
||||
- ${{ if eq(length(parameters.groups), 0) }}:
|
||||
- ${{ each target in parameters.targets }}:
|
||||
- name: ${{ format(parameters.nameFormat, coalesce(target.name, target.test)) }}
|
||||
test: ${{ format(parameters.testFormat, coalesce(target.test, target.name)) }}
|
||||
- ${{ if not(eq(length(parameters.groups), 0)) }}:
|
||||
- ${{ each group in parameters.groups }}:
|
||||
- ${{ each target in parameters.targets }}:
|
||||
- name: ${{ format(format(parameters.nameGroupFormat, parameters.nameFormat), coalesce(target.name, target.test), group) }}
|
||||
test: ${{ format(format(parameters.testGroupFormat, parameters.testFormat), coalesce(target.test, target.name), group) }}
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# This template uses the provided list of jobs to create test one or more test jobs.
|
||||
# It can be used directly if needed, or through the matrix template.
|
||||
|
||||
parameters:
|
||||
# A required list of dictionaries, one per test job.
|
||||
# Each item in the list must contain a "job" and "name" key.
|
||||
- name: jobs
|
||||
type: object
|
||||
|
||||
jobs:
|
||||
- ${{ each job in parameters.jobs }}:
|
||||
- job: test_${{ replace(replace(replace(job.test, '/', '_'), '.', '_'), '-', '_') }}
|
||||
displayName: ${{ job.name }}
|
||||
container: default
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: $(fetchDepth)
|
||||
path: $(checkoutPath)
|
||||
- bash: .azure-pipelines/scripts/run-tests.sh "$(entryPoint)" "${{ job.test }}" "$(coverageBranches)"
|
||||
displayName: Run Tests
|
||||
- bash: .azure-pipelines/scripts/process-results.sh
|
||||
condition: succeededOrFailed()
|
||||
displayName: Process Results
|
||||
- bash: .azure-pipelines/scripts/aggregate-coverage.sh "$(Agent.TempDirectory)"
|
||||
condition: eq(variables.haveCoverageData, 'true')
|
||||
displayName: Aggregate Coverage Data
|
||||
- task: PublishTestResults@2
|
||||
condition: eq(variables.haveTestResults, 'true')
|
||||
inputs:
|
||||
testResultsFiles: "$(outputPath)/junit/*.xml"
|
||||
displayName: Publish Test Results
|
||||
- task: PublishPipelineArtifact@1
|
||||
condition: eq(variables.haveBotResults, 'true')
|
||||
displayName: Publish Bot Results
|
||||
inputs:
|
||||
targetPath: "$(outputPath)/bot/"
|
||||
artifactName: "Bot $(System.JobAttempt) $(System.StageDisplayName) $(System.JobDisplayName)"
|
||||
- task: PublishPipelineArtifact@1
|
||||
condition: eq(variables.haveCoverageData, 'true')
|
||||
displayName: Publish Coverage Data
|
||||
inputs:
|
||||
targetPath: "$(Agent.TempDirectory)/coverage/"
|
||||
artifactName: "Coverage $(System.JobAttempt) $(System.StageDisplayName) $(System.JobDisplayName)"
|
||||
51
.github/BOTMETA.yml
vendored
51
.github/BOTMETA.yml
vendored
@@ -241,13 +241,17 @@ files:
|
||||
$lookups/manifold.py:
|
||||
labels: manifold
|
||||
maintainers: galanoff
|
||||
$lookups/merge_variables.py:
|
||||
maintainers: rlenferink m-a-r-k-e
|
||||
$lookups/onepass:
|
||||
labels: onepassword
|
||||
maintainers: samdoran
|
||||
$lookups/onepassword.py:
|
||||
maintainers: azenk scottsb
|
||||
ignore: scottsb
|
||||
maintainers: azenk
|
||||
$lookups/onepassword_raw.py:
|
||||
maintainers: azenk scottsb
|
||||
ignore: scottsb
|
||||
maintainers: azenk
|
||||
$lookups/passwordstore.py: {}
|
||||
$lookups/random_pet.py:
|
||||
maintainers: Akasurde
|
||||
@@ -265,6 +269,8 @@ files:
|
||||
maintainers: delineaKrehl tylerezimmerman
|
||||
$module_utils/:
|
||||
labels: module_utils
|
||||
$module_utils/btrfs.py:
|
||||
maintainers: gnfzdz
|
||||
$module_utils/deps.py:
|
||||
maintainers: russoz
|
||||
$module_utils/gconftool2.py:
|
||||
@@ -294,7 +300,6 @@ files:
|
||||
maintainers: $team_manageiq
|
||||
$module_utils/memset.py:
|
||||
labels: cloud memset
|
||||
maintainers: glitchcrab
|
||||
$module_utils/mh/:
|
||||
labels: module_helper
|
||||
maintainers: russoz
|
||||
@@ -394,6 +399,8 @@ files:
|
||||
maintainers: catcombo
|
||||
$modules/bower.py:
|
||||
maintainers: mwarkentin
|
||||
$modules/btrfs_:
|
||||
maintainers: gnfzdz
|
||||
$modules/bundler.py:
|
||||
maintainers: thoiberg
|
||||
$modules/bzr.py:
|
||||
@@ -522,6 +529,7 @@ files:
|
||||
keywords: gitlab source_control
|
||||
maintainers: $team_gitlab
|
||||
notify: jlozadad
|
||||
ignore: dj-wasabi
|
||||
$modules/gitlab_branch.py:
|
||||
maintainers: paytroff
|
||||
$modules/gitlab_project_variable.py:
|
||||
@@ -588,7 +596,7 @@ files:
|
||||
ignore: jose-delarosa
|
||||
maintainers: $team_redfish
|
||||
$modules/ilo_:
|
||||
ignore: jose-delarosa
|
||||
ignore: jose-delarosa varini-hp
|
||||
maintainers: $team_redfish
|
||||
$modules/imc_rest.py:
|
||||
labels: cisco
|
||||
@@ -664,19 +672,25 @@ files:
|
||||
$modules/jenkins_script.py:
|
||||
maintainers: hogarthj
|
||||
$modules/jira.py:
|
||||
ignore: DWSR
|
||||
ignore: DWSR tarka
|
||||
labels: jira
|
||||
maintainers: Slezhuk tarka pertoft
|
||||
maintainers: Slezhuk pertoft
|
||||
$modules/kdeconfig.py:
|
||||
maintainers: smeso
|
||||
$modules/kernel_blacklist.py:
|
||||
maintainers: matze
|
||||
$modules/keycloak_:
|
||||
maintainers: $team_keycloak
|
||||
$modules/keycloak_authentication.py:
|
||||
maintainers: elfelip Gaetan2907
|
||||
$modules/keycloak_authz_authorization_scope.py:
|
||||
maintainers: mattock
|
||||
$modules/keycloak_client_rolemapping.py:
|
||||
maintainers: Gaetan2907
|
||||
$modules/keycloak_clientscope.py:
|
||||
maintainers: Gaetan2907
|
||||
$modules/keycloak_clientscope_type.py:
|
||||
maintainers: simonpahl
|
||||
$modules/keycloak_clientsecret_info.py:
|
||||
maintainers: fynncfchen johncant
|
||||
$modules/keycloak_clientsecret_regenerate.py:
|
||||
@@ -785,7 +799,7 @@ files:
|
||||
labels: maven_artifact
|
||||
maintainers: tumbl3w33d turb
|
||||
$modules/memset_:
|
||||
maintainers: glitchcrab
|
||||
ignore: glitchcrab
|
||||
$modules/mksysb.py:
|
||||
labels: aix mksysb
|
||||
maintainers: $team_aix
|
||||
@@ -918,7 +932,7 @@ files:
|
||||
$modules/pamd.py:
|
||||
maintainers: kevensen
|
||||
$modules/parted.py:
|
||||
maintainers: ColOfAbRiX rosowiecki jake2184
|
||||
maintainers: ColOfAbRiX jake2184
|
||||
$modules/pear.py:
|
||||
ignore: jle64
|
||||
labels: pear
|
||||
@@ -987,7 +1001,7 @@ files:
|
||||
maintainers: sysadmind
|
||||
$modules/puppet.py:
|
||||
labels: puppet
|
||||
maintainers: nibalizer emonty
|
||||
maintainers: emonty
|
||||
$modules/pushbullet.py:
|
||||
maintainers: willybarro
|
||||
$modules/pushover.py:
|
||||
@@ -1042,7 +1056,8 @@ files:
|
||||
maintainers: $team_redfish TSKushal
|
||||
$modules/redhat_subscription.py:
|
||||
labels: redhat_subscription
|
||||
maintainers: barnabycourt alikins kahowell
|
||||
maintainers: $team_rhsm
|
||||
ignore: barnabycourt alikins kahowell
|
||||
$modules/redis.py:
|
||||
maintainers: slok
|
||||
$modules/redis_data.py:
|
||||
@@ -1065,9 +1080,9 @@ files:
|
||||
labels: rhn_register
|
||||
maintainers: jlaska $team_rhn
|
||||
$modules/rhsm_release.py:
|
||||
maintainers: seandst
|
||||
maintainers: seandst $team_rhsm
|
||||
$modules/rhsm_repository.py:
|
||||
maintainers: giovannisciortino
|
||||
maintainers: giovannisciortino $team_rhsm
|
||||
$modules/riak.py:
|
||||
maintainers: drewkerrigan jsmartin
|
||||
$modules/rocketchat.py:
|
||||
@@ -1320,7 +1335,7 @@ files:
|
||||
labels: m:xml xml
|
||||
maintainers: dagwieers magnus919 tbielawa cmprescott sm4rk0
|
||||
$modules/yarn.py:
|
||||
maintainers: chrishoffman verkaufer
|
||||
ignore: chrishoffman verkaufer
|
||||
$modules/yum_versionlock.py:
|
||||
maintainers: gyptazy aminvakil
|
||||
$modules/zfs:
|
||||
@@ -1345,6 +1360,8 @@ files:
|
||||
ignore: matze
|
||||
labels: zypper
|
||||
maintainers: $team_suse
|
||||
$plugin_utils/unsafe.py:
|
||||
maintainers: felixfontein
|
||||
$tests/a_module.py:
|
||||
maintainers: felixfontein
|
||||
#########################
|
||||
@@ -1364,7 +1381,6 @@ macros:
|
||||
becomes: plugins/become
|
||||
caches: plugins/cache
|
||||
callbacks: plugins/callback
|
||||
cliconfs: plugins/cliconf
|
||||
connections: plugins/connection
|
||||
doc_fragments: plugins/doc_fragments
|
||||
filters: plugins/filter
|
||||
@@ -1372,7 +1388,7 @@ macros:
|
||||
lookups: plugins/lookup
|
||||
module_utils: plugins/module_utils
|
||||
modules: plugins/modules
|
||||
terminals: plugins/terminal
|
||||
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
|
||||
@@ -1381,12 +1397,12 @@ macros:
|
||||
team_cyberark_conjur: jvanderhoof ryanprior
|
||||
team_e_spirit: MatrixCrawler getjack
|
||||
team_flatpak: JayKayy oolongbrothers
|
||||
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
|
||||
team_gitlab: Lunik Shaps marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
|
||||
team_hpux: bcoca davx8342
|
||||
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
||||
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
||||
team_jboss: Wolfant jairojunior wbrefvem
|
||||
team_keycloak: eikef ndclt
|
||||
team_keycloak: eikef ndclt mattock
|
||||
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
||||
team_macos: Akasurde kyleabenson martinm82 danieljaouen indrajitr
|
||||
team_manageiq: abellotti cben gtanzillo yaacov zgalor dkorn evertmulder
|
||||
@@ -1396,6 +1412,7 @@ macros:
|
||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
|
||||
team_rhn: FlossWare alikins barnabycourt vritant
|
||||
team_rhsm: cnsnyder ptoscano
|
||||
team_scaleway: remyleone abarbare
|
||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||
team_suse: commel evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
||||
|
||||
193
.github/workflows/ansible-test.yml
vendored
193
.github/workflows/ansible-test.yml
vendored
@@ -1,193 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# For the comprehensive list of the inputs supported by the ansible-community/ansible-test-gh-action GitHub Action, see
|
||||
# https://github.com/marketplace/actions/ansible-test
|
||||
|
||||
name: EOL CI
|
||||
on:
|
||||
# Run EOL CI against all pushes (direct commits, also merged PRs), Pull Requests
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- stable-*
|
||||
pull_request:
|
||||
# Run EOL CI once per day (at 10:00 UTC)
|
||||
schedule:
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
concurrency:
|
||||
# Make sure there is at most one active run per PR, but do not cancel any non-PR runs
|
||||
group: ${{ github.workflow }}-${{ (github.head_ref && github.event.number) || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
sanity:
|
||||
name: EOL Sanity (Ⓐ${{ matrix.ansible }})
|
||||
strategy:
|
||||
matrix:
|
||||
ansible:
|
||||
- '2.11'
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
|
||||
# image for these stable branches. The list of branches where this is necessary will
|
||||
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
|
||||
# for the latest list.
|
||||
runs-on: >-
|
||||
${{ contains(fromJson(
|
||||
'["2.9", "2.10", "2.11"]'
|
||||
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Perform sanity testing
|
||||
uses: felixfontein/ansible-test-gh-action@main
|
||||
with:
|
||||
ansible-core-github-repository-slug: felixfontein/ansible
|
||||
ansible-core-version: stable-${{ matrix.ansible }}
|
||||
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
|
||||
pull-request-change-detection: 'true'
|
||||
testing-type: sanity
|
||||
|
||||
units:
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
|
||||
# image for these stable branches. The list of branches where this is necessary will
|
||||
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
|
||||
# for the latest list.
|
||||
runs-on: >-
|
||||
${{ contains(fromJson(
|
||||
'["2.9", "2.10", "2.11"]'
|
||||
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
|
||||
name: EOL Units (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }})
|
||||
strategy:
|
||||
# As soon as the first unit test fails, cancel the others to free up the CI queue
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ansible:
|
||||
- ''
|
||||
python:
|
||||
- ''
|
||||
exclude:
|
||||
- ansible: ''
|
||||
include:
|
||||
- ansible: '2.11'
|
||||
python: '2.7'
|
||||
- ansible: '2.11'
|
||||
python: '3.5'
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
Perform unit testing against
|
||||
Ansible version ${{ matrix.ansible }}
|
||||
uses: felixfontein/ansible-test-gh-action@main
|
||||
with:
|
||||
ansible-core-github-repository-slug: felixfontein/ansible
|
||||
ansible-core-version: stable-${{ matrix.ansible }}
|
||||
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
|
||||
pre-test-cmd: >-
|
||||
mkdir -p ../../ansible
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
pull-request-change-detection: 'true'
|
||||
target-python-version: ${{ matrix.python }}
|
||||
testing-type: units
|
||||
|
||||
integration:
|
||||
# Ansible-test on various stable branches does not yet work well with cgroups v2.
|
||||
# Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
|
||||
# image for these stable branches. The list of branches where this is necessary will
|
||||
# shrink over time, check out https://github.com/ansible-collections/news-for-maintainers/issues/28
|
||||
# for the latest list.
|
||||
runs-on: >-
|
||||
${{ contains(fromJson(
|
||||
'["2.9", "2.10", "2.11"]'
|
||||
), matrix.ansible) && 'ubuntu-20.04' || 'ubuntu-latest' }}
|
||||
name: EOL I (Ⓐ${{ matrix.ansible }}+${{ matrix.docker }}+py${{ matrix.python }}:${{ matrix.target }})
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ansible:
|
||||
- ''
|
||||
docker:
|
||||
- ''
|
||||
python:
|
||||
- ''
|
||||
target:
|
||||
- ''
|
||||
exclude:
|
||||
- ansible: ''
|
||||
include:
|
||||
# 2.11
|
||||
- ansible: '2.11'
|
||||
docker: fedora32
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.11'
|
||||
docker: fedora32
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.11'
|
||||
docker: fedora32
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.11'
|
||||
docker: fedora33
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.11'
|
||||
docker: fedora33
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.11'
|
||||
docker: fedora33
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
- ansible: '2.11'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/1/
|
||||
- ansible: '2.11'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/2/
|
||||
- ansible: '2.11'
|
||||
docker: alpine3
|
||||
python: ''
|
||||
target: azp/posix/3/
|
||||
# Right now all generic tests are disabled. Uncomment when at least one of them is re-enabled.
|
||||
# - ansible: '2.11'
|
||||
# docker: default
|
||||
# python: '2.7'
|
||||
# target: azp/generic/1/
|
||||
# - ansible: '2.11'
|
||||
# docker: default
|
||||
# python: '3.5'
|
||||
# target: azp/generic/2/
|
||||
|
||||
steps:
|
||||
- name: >-
|
||||
Perform integration testing against
|
||||
Ansible version ${{ matrix.ansible }}
|
||||
under Python ${{ matrix.python }}
|
||||
uses: felixfontein/ansible-test-gh-action@main
|
||||
with:
|
||||
ansible-core-github-repository-slug: felixfontein/ansible
|
||||
ansible-core-version: stable-${{ matrix.ansible }}
|
||||
coverage: ${{ github.event_name == 'schedule' && 'always' || 'never' }}
|
||||
docker-image: ${{ matrix.docker }}
|
||||
integration-continue-on-error: 'false'
|
||||
integration-diff: 'false'
|
||||
integration-retry-on-error: 'true'
|
||||
pre-test-cmd: >-
|
||||
mkdir -p ../../ansible
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.posix.git ../../ansible/posix
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.crypto.git ../../community/crypto
|
||||
;
|
||||
git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git ../../community/internal_test_tools
|
||||
pull-request-change-detection: 'true'
|
||||
target: ${{ matrix.target }}
|
||||
target-python-version: ${{ matrix.python }}
|
||||
testing-type: integration
|
||||
61
.github/workflows/codeql-analysis.yml
vendored
61
.github/workflows/codeql-analysis.yml
vendored
@@ -1,61 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: "Code scanning - action"
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '26 19 * * 1'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
permissions:
|
||||
actions: read # for github/codeql-action/init to get workflow details
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/autobuild to send a status report
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
35
.github/workflows/reuse.yml
vendored
35
.github/workflows/reuse.yml
vendored
@@ -1,35 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
name: Verify REUSE
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches: [main]
|
||||
# Run CI once per day (at 07:30 UTC)
|
||||
schedule:
|
||||
- cron: '30 7 * * *'
|
||||
|
||||
jobs:
|
||||
check:
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install reuse
|
||||
|
||||
- name: Check REUSE compliance
|
||||
run: |
|
||||
reuse lint
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
# Copyright (c) Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: mixed-line-ending
|
||||
args: [--fix=lf]
|
||||
- id: fix-encoding-pragma
|
||||
- id: check-ast
|
||||
- id: check-merge-conflict
|
||||
- id: check-symlinks
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
hooks:
|
||||
- id: rst-backticks
|
||||
types: [file]
|
||||
files: changelogs/fragments/.*\.(yml|yaml)$
|
||||
955
CHANGELOG.md
Normal file
955
CHANGELOG.md
Normal file
@@ -0,0 +1,955 @@
|
||||
# Community General Release Notes
|
||||
|
||||
**Topics**
|
||||
|
||||
- <a href="#v6-6-9">v6\.6\.9</a>
|
||||
- <a href="#release-summary">Release Summary</a>
|
||||
- <a href="#security-fixes">Security Fixes</a>
|
||||
- <a href="#bugfixes">Bugfixes</a>
|
||||
- <a href="#v6-6-8">v6\.6\.8</a>
|
||||
- <a href="#release-summary-1">Release Summary</a>
|
||||
- <a href="#security-fixes-1">Security Fixes</a>
|
||||
- <a href="#bugfixes-1">Bugfixes</a>
|
||||
- <a href="#v6-6-7">v6\.6\.7</a>
|
||||
- <a href="#release-summary-2">Release Summary</a>
|
||||
- <a href="#bugfixes-2">Bugfixes</a>
|
||||
- <a href="#v6-6-6">v6\.6\.6</a>
|
||||
- <a href="#release-summary-3">Release Summary</a>
|
||||
- <a href="#bugfixes-3">Bugfixes</a>
|
||||
- <a href="#v6-6-5">v6\.6\.5</a>
|
||||
- <a href="#release-summary-4">Release Summary</a>
|
||||
- <a href="#minor-changes">Minor Changes</a>
|
||||
- <a href="#bugfixes-4">Bugfixes</a>
|
||||
- <a href="#v6-6-4">v6\.6\.4</a>
|
||||
- <a href="#release-summary-5">Release Summary</a>
|
||||
- <a href="#minor-changes-1">Minor Changes</a>
|
||||
- <a href="#bugfixes-5">Bugfixes</a>
|
||||
- <a href="#v6-6-3">v6\.6\.3</a>
|
||||
- <a href="#release-summary-6">Release Summary</a>
|
||||
- <a href="#minor-changes-2">Minor Changes</a>
|
||||
- <a href="#bugfixes-6">Bugfixes</a>
|
||||
- <a href="#v6-6-2">v6\.6\.2</a>
|
||||
- <a href="#release-summary-7">Release Summary</a>
|
||||
- <a href="#bugfixes-7">Bugfixes</a>
|
||||
- <a href="#v6-6-1">v6\.6\.1</a>
|
||||
- <a href="#release-summary-8">Release Summary</a>
|
||||
- <a href="#minor-changes-3">Minor Changes</a>
|
||||
- <a href="#bugfixes-8">Bugfixes</a>
|
||||
- <a href="#v6-6-0">v6\.6\.0</a>
|
||||
- <a href="#release-summary-9">Release Summary</a>
|
||||
- <a href="#minor-changes-4">Minor Changes</a>
|
||||
- <a href="#bugfixes-9">Bugfixes</a>
|
||||
- <a href="#new-modules">New Modules</a>
|
||||
- <a href="#v6-5-0">v6\.5\.0</a>
|
||||
- <a href="#release-summary-10">Release Summary</a>
|
||||
- <a href="#minor-changes-5">Minor Changes</a>
|
||||
- <a href="#bugfixes-10">Bugfixes</a>
|
||||
- <a href="#new-plugins">New Plugins</a>
|
||||
- <a href="#lookup">Lookup</a>
|
||||
- <a href="#new-modules-1">New Modules</a>
|
||||
- <a href="#v6-4-0">v6\.4\.0</a>
|
||||
- <a href="#release-summary-11">Release Summary</a>
|
||||
- <a href="#minor-changes-6">Minor Changes</a>
|
||||
- <a href="#deprecated-features">Deprecated Features</a>
|
||||
- <a href="#bugfixes-11">Bugfixes</a>
|
||||
- <a href="#v6-3-0">v6\.3\.0</a>
|
||||
- <a href="#release-summary-12">Release Summary</a>
|
||||
- <a href="#minor-changes-7">Minor Changes</a>
|
||||
- <a href="#breaking-changes--porting-guide">Breaking Changes / Porting Guide</a>
|
||||
- <a href="#deprecated-features-1">Deprecated Features</a>
|
||||
- <a href="#bugfixes-12">Bugfixes</a>
|
||||
- <a href="#new-modules-2">New Modules</a>
|
||||
- <a href="#v6-2-0">v6\.2\.0</a>
|
||||
- <a href="#release-summary-13">Release Summary</a>
|
||||
- <a href="#minor-changes-8">Minor Changes</a>
|
||||
- <a href="#deprecated-features-2">Deprecated Features</a>
|
||||
- <a href="#bugfixes-13">Bugfixes</a>
|
||||
- <a href="#v6-1-0">v6\.1\.0</a>
|
||||
- <a href="#release-summary-14">Release Summary</a>
|
||||
- <a href="#minor-changes-9">Minor Changes</a>
|
||||
- <a href="#deprecated-features-3">Deprecated Features</a>
|
||||
- <a href="#bugfixes-14">Bugfixes</a>
|
||||
- <a href="#new-modules-3">New Modules</a>
|
||||
- <a href="#v6-0-1">v6\.0\.1</a>
|
||||
- <a href="#release-summary-15">Release Summary</a>
|
||||
- <a href="#bugfixes-15">Bugfixes</a>
|
||||
- <a href="#v6-0-0">v6\.0\.0</a>
|
||||
- <a href="#release-summary-16">Release Summary</a>
|
||||
- <a href="#major-changes">Major Changes</a>
|
||||
- <a href="#minor-changes-10">Minor Changes</a>
|
||||
- <a href="#breaking-changes--porting-guide-1">Breaking Changes / Porting Guide</a>
|
||||
- <a href="#deprecated-features-4">Deprecated Features</a>
|
||||
- <a href="#removed-features-previously-deprecated">Removed Features \(previously deprecated\)</a>
|
||||
- <a href="#bugfixes-16">Bugfixes</a>
|
||||
- <a href="#new-plugins-1">New Plugins</a>
|
||||
- <a href="#filter">Filter</a>
|
||||
- <a href="#lookup-1">Lookup</a>
|
||||
- <a href="#new-modules-4">New Modules</a>
|
||||
This changelog describes changes after version 5\.0\.0\.
|
||||
|
||||
<a id="v6-6-9"></a>
|
||||
## v6\.6\.9
|
||||
|
||||
<a id="release-summary"></a>
|
||||
### Release Summary
|
||||
|
||||
Maintenance release\.
|
||||
|
||||
This is the last 6\.x\.y release\. The 6\.x\.y release train is now effectively End of Life\.
|
||||
Thanks to everyone who contributed to the community\.general 6\.x\.y releases\!
|
||||
|
||||
<a id="security-fixes"></a>
|
||||
### Security Fixes
|
||||
|
||||
* keycloak\_identity\_provider \- the client secret was not correctly sanitized by the module\. The return values <code>proposed</code>\, <code>existing</code>\, and <code>end\_state</code>\, as well as the diff\, did contain the client secret unmasked \([https\://github\.com/ansible\-collections/community\.general/pull/8355](https\://github\.com/ansible\-collections/community\.general/pull/8355)\)\.
|
||||
|
||||
<a id="bugfixes"></a>
|
||||
### Bugfixes
|
||||
|
||||
* inventory plugins \- add unsafe wrapper to avoid marking strings that do not contain <code>\{</code> or <code>\}</code> as unsafe\, to work around a bug in AWX \(\([https\://github\.com/ansible\-collections/community\.general/issues/8212](https\://github\.com/ansible\-collections/community\.general/issues/8212)\, [https\://github\.com/ansible\-collections/community\.general/pull/8225](https\://github\.com/ansible\-collections/community\.general/pull/8225)\)\.
|
||||
* xml \- make module work with lxml 5\.1\.1\, which removed some internals that the module was relying on \([https\://github\.com/ansible\-collections/community\.general/pull/8169](https\://github\.com/ansible\-collections/community\.general/pull/8169)\)\.
|
||||
|
||||
<a id="v6-6-8"></a>
|
||||
## v6\.6\.8
|
||||
|
||||
<a id="release-summary-1"></a>
|
||||
### Release Summary
|
||||
|
||||
Security and bugfix release\.
|
||||
|
||||
<a id="security-fixes-1"></a>
|
||||
### Security Fixes
|
||||
|
||||
* cobbler\, gitlab\_runners\, icinga2\, linode\, lxd\, nmap\, online\, opennebula\, proxmox\, scaleway\, stackpath\_compute\, virtualbox\, and xen\_orchestra inventory plugin \- make sure all data received from the remote servers is marked as unsafe\, so remote code execution by obtaining texts that can be evaluated as templates is not possible \([https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/](https\://www\.die\-welt\.net/2024/03/remote\-code\-execution\-in\-ansible\-dynamic\-inventory\-plugins/)\, [https\://github\.com/ansible\-collections/community\.general/pull/8098](https\://github\.com/ansible\-collections/community\.general/pull/8098)\)\.
|
||||
|
||||
<a id="bugfixes-1"></a>
|
||||
### Bugfixes
|
||||
|
||||
* aix\_filesystem \- fix issue with empty list items in crfs logic and option order \([https\://github\.com/ansible\-collections/community\.general/pull/8052](https\://github\.com/ansible\-collections/community\.general/pull/8052)\)\.
|
||||
* pacemaker\_cluster \- actually implement check mode\, which the module claims to support\. This means that until now the module also did changes in check mode \([https\://github\.com/ansible\-collections/community\.general/pull/8081](https\://github\.com/ansible\-collections/community\.general/pull/8081)\)\.
|
||||
* pam\_limits \- when the file does not exist\, do not create it in check mode \([https\://github\.com/ansible\-collections/community\.general/issues/8050](https\://github\.com/ansible\-collections/community\.general/issues/8050)\, [https\://github\.com/ansible\-collections/community\.general/pull/8057](https\://github\.com/ansible\-collections/community\.general/pull/8057)\)\.
|
||||
|
||||
<a id="v6-6-7"></a>
|
||||
## v6\.6\.7
|
||||
|
||||
<a id="release-summary-2"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release\.
|
||||
|
||||
From now on\, community\.general 6\.x\.y will only receive major bugfixes and security fixes anymore\.
|
||||
|
||||
<a id="bugfixes-2"></a>
|
||||
### Bugfixes
|
||||
|
||||
* composer \- fix impossible to run <code>working\_dir</code> dependent commands\. The module was throwing an error when trying to run a <code>working\_dir</code> dependent command\, because it tried to get the command help without passing the <code>working\_dir</code> \([https\://github\.com/ansible\-collections/community\.general/issues/3787](https\://github\.com/ansible\-collections/community\.general/issues/3787)\)\.
|
||||
* github\_deploy\_key \- fix pagination behaviour causing a crash when only a single page of deploy keys exist \([https\://github\.com/ansible\-collections/community\.general/pull/7375](https\://github\.com/ansible\-collections/community\.general/pull/7375)\)\.
|
||||
* gitlab\_group\_members \- fix gitlab constants call in <code>gitlab\_group\_members</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
|
||||
* gitlab\_project\_members \- fix gitlab constants call in <code>gitlab\_project\_members</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
|
||||
* gitlab\_protected\_branches \- fix gitlab constants call in <code>gitlab\_protected\_branches</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
|
||||
* gitlab\_user \- fix gitlab constants call in <code>gitlab\_user</code> module \([https\://github\.com/ansible\-collections/community\.general/issues/7467](https\://github\.com/ansible\-collections/community\.general/issues/7467)\)\.
|
||||
* lxc connection plugin \- properly evaluate options \([https\://github\.com/ansible\-collections/community\.general/pull/7369](https\://github\.com/ansible\-collections/community\.general/pull/7369)\)\.
|
||||
* memset module utils \- make compatible with ansible\-core 2\.17 \([https\://github\.com/ansible\-collections/community\.general/pull/7379](https\://github\.com/ansible\-collections/community\.general/pull/7379)\)\.
|
||||
* redhat\_subscription \- use the right D\-Bus options for the consumer type when
|
||||
registering a RHEL system older than 9 or a RHEL 9 system older than 9\.2
|
||||
and using <code>consumer\_type</code>
|
||||
\([https\://github\.com/ansible\-collections/community\.general/pull/7378](https\://github\.com/ansible\-collections/community\.general/pull/7378)\)\.
|
||||
* selective callback plugin \- fix length of task name lines in output always being 3 characters longer than desired \([https\://github\.com/ansible\-collections/community\.general/pull/7374](https\://github\.com/ansible\-collections/community\.general/pull/7374)\)\.
|
||||
|
||||
<a id="v6-6-6"></a>
|
||||
## v6\.6\.6
|
||||
|
||||
<a id="release-summary-3"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes-3"></a>
|
||||
### Bugfixes
|
||||
|
||||
* mail \- skip headers containing equals characters due to missing <code>maxsplit</code> on header key/value parsing \([https\://github\.com/ansible\-collections/community\.general/pull/7303](https\://github\.com/ansible\-collections/community\.general/pull/7303)\)\.
|
||||
* onepassword \- fix KeyError exception when trying to access value of a field that is not filled out in OnePassword item \([https\://github\.com/ansible\-collections/community\.general/pull/7241](https\://github\.com/ansible\-collections/community\.general/pull/7241)\)\.
|
||||
* terraform \- prevents <code>\-backend\-config</code> option double encapsulating with <code>shlex\_quote</code> function\. \([https\://github\.com/ansible\-collections/community\.general/pull/7301](https\://github\.com/ansible\-collections/community\.general/pull/7301)\)\.
|
||||
|
||||
<a id="v6-6-5"></a>
|
||||
## v6\.6\.5
|
||||
|
||||
<a id="release-summary-4"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes"></a>
|
||||
### Minor Changes
|
||||
|
||||
* make \- allows <code>params</code> to be used without value \([https\://github\.com/ansible\-collections/community\.general/pull/7180](https\://github\.com/ansible\-collections/community\.general/pull/7180)\)\.
|
||||
* pritunl module utils \- ensure <code>validate\_certs</code> parameter is honoured in all methods \([https\://github\.com/ansible\-collections/community\.general/pull/7156](https\://github\.com/ansible\-collections/community\.general/pull/7156)\)\.
|
||||
|
||||
<a id="bugfixes-4"></a>
|
||||
### Bugfixes
|
||||
|
||||
* CmdRunner module utils \- does not attempt to resolve path if executable is a relative or absolute path \([https\://github\.com/ansible\-collections/community\.general/pull/7200](https\://github\.com/ansible\-collections/community\.general/pull/7200)\)\.
|
||||
* lxc connection plugin \- now handles <code>remote\_addr</code> defaulting to <code>inventory\_hostname</code> correctly \([https\://github\.com/ansible\-collections/community\.general/pull/7104](https\://github\.com/ansible\-collections/community\.general/pull/7104)\)\.
|
||||
* nsupdate \- fix a possible <code>list index out of range</code> exception \([https\://github\.com/ansible\-collections/community\.general/issues/836](https\://github\.com/ansible\-collections/community\.general/issues/836)\)\.
|
||||
* oci\_utils module util \- fix inappropriate logical comparison expressions and makes them simpler\. The previous checks had logical short circuits \([https\://github\.com/ansible\-collections/community\.general/pull/7125](https\://github\.com/ansible\-collections/community\.general/pull/7125)\)\.
|
||||
* pritunl module utils \- fix incorrect URL parameter for orgnization add method \([https\://github\.com/ansible\-collections/community\.general/pull/7161](https\://github\.com/ansible\-collections/community\.general/pull/7161)\)\.
|
||||
|
||||
<a id="v6-6-4"></a>
|
||||
## v6\.6\.4
|
||||
|
||||
<a id="release-summary-5"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-1"></a>
|
||||
### Minor Changes
|
||||
|
||||
* redfish\_utils \- use <code>Controllers</code> key in redfish data to obtain Storage controllers properties \([https\://github\.com/ansible\-collections/community\.general/pull/7081](https\://github\.com/ansible\-collections/community\.general/pull/7081)\)\.
|
||||
|
||||
<a id="bugfixes-5"></a>
|
||||
### Bugfixes
|
||||
|
||||
* bitwarden lookup plugin \- the plugin made assumptions about the structure of a Bitwarden JSON object which may have been broken by an update in the Bitwarden API\. Remove assumptions\, and allow queries for general fields such as <code>notes</code> \([https\://github\.com/ansible\-collections/community\.general/pull/7061](https\://github\.com/ansible\-collections/community\.general/pull/7061)\)\.
|
||||
* cmd\_runner module utils \- when a parameter in <code>argument\_spec</code> has no type\, meaning it is implicitly a <code>str</code>\, <code>CmdRunner</code> would fail trying to find the <code>type</code> key in that dictionary \([https\://github\.com/ansible\-collections/community\.general/pull/6968](https\://github\.com/ansible\-collections/community\.general/pull/6968)\)\.
|
||||
* ejabberd\_user \- module was failing to detect whether user was already created and/or password was changed \([https\://github\.com/ansible\-collections/community\.general/pull/7033](https\://github\.com/ansible\-collections/community\.general/pull/7033)\)\.
|
||||
* ejabberd\_user \- provide meaningful error message when the <code>ejabberdctl</code> command is not found \([https\://github\.com/ansible\-collections/community\.general/pull/7028](https\://github\.com/ansible\-collections/community\.general/pull/7028)\, [https\://github\.com/ansible\-collections/community\.general/issues/6949](https\://github\.com/ansible\-collections/community\.general/issues/6949)\)\.
|
||||
* oci\_utils module utils \- avoid direct type comparisons \([https\://github\.com/ansible\-collections/community\.general/pull/7085](https\://github\.com/ansible\-collections/community\.general/pull/7085)\)\.
|
||||
* proxmox module utils \- fix proxmoxer library version check \([https\://github\.com/ansible\-collections/community\.general/issues/6974](https\://github\.com/ansible\-collections/community\.general/issues/6974)\, [https\://github\.com/ansible\-collections/community\.general/issues/6975](https\://github\.com/ansible\-collections/community\.general/issues/6975)\, [https\://github\.com/ansible\-collections/community\.general/pull/6980](https\://github\.com/ansible\-collections/community\.general/pull/6980)\)\.
|
||||
* proxmox\_kvm \- when <code>name</code> option is provided without <code>vmid</code> and VM with that name already exists then no new VM will be created \([https\://github\.com/ansible\-collections/community\.general/issues/6911](https\://github\.com/ansible\-collections/community\.general/issues/6911)\, [https\://github\.com/ansible\-collections/community\.general/pull/6981](https\://github\.com/ansible\-collections/community\.general/pull/6981)\)\.
|
||||
* proxmox\_user\_info \- avoid direct type comparisons \([https\://github\.com/ansible\-collections/community\.general/pull/7085](https\://github\.com/ansible\-collections/community\.general/pull/7085)\)\.
|
||||
* rundeck \- fix <code>TypeError</code> on 404 API response \([https\://github\.com/ansible\-collections/community\.general/pull/6983](https\://github\.com/ansible\-collections/community\.general/pull/6983)\)\.
|
||||
|
||||
<a id="v6-6-3"></a>
|
||||
## v6\.6\.3
|
||||
|
||||
<a id="release-summary-6"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-2"></a>
|
||||
### Minor Changes
|
||||
|
||||
* cobbler inventory plugin \- convert Ansible unicode strings to native Python unicode strings before passing user/password to XMLRPC client \([https\://github\.com/ansible\-collections/community\.general/pull/6923](https\://github\.com/ansible\-collections/community\.general/pull/6923)\)\.
|
||||
* redfish\_info \- fix for <code>GetVolumeInventory</code>\, Controller name was getting populated incorrectly and duplicates were seen in the volumes retrieved \([https\://github\.com/ansible\-collections/community\.general/pull/6719](https\://github\.com/ansible\-collections/community\.general/pull/6719)\)\.
|
||||
|
||||
<a id="bugfixes-6"></a>
|
||||
### Bugfixes
|
||||
|
||||
* datadog\_downtime \- presence of <code>rrule</code> param lead to the Datadog API returning Bad Request due to a missing recurrence type \([https\://github\.com/ansible\-collections/community\.general/pull/6811](https\://github\.com/ansible\-collections/community\.general/pull/6811)\)\.
|
||||
* icinga2\_host \- fix a key error when updating an existing host \([https\://github\.com/ansible\-collections/community\.general/pull/6748](https\://github\.com/ansible\-collections/community\.general/pull/6748)\)\.
|
||||
* ipa\_dnszone \- fix \'idnsallowsyncptr\' key error for reverse zone \([https\://github\.com/ansible\-collections/community\.general/pull/6906](https\://github\.com/ansible\-collections/community\.general/pull/6906)\, [https\://github\.com/ansible\-collections/community\.general/issues/6905](https\://github\.com/ansible\-collections/community\.general/issues/6905)\)\.
|
||||
* locale\_gen \- now works for locales without the underscore character such as <code>C\.UTF\-8</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6774](https\://github\.com/ansible\-collections/community\.general/pull/6774)\, [https\://github\.com/ansible\-collections/community\.general/issues/5142](https\://github\.com/ansible\-collections/community\.general/issues/5142)\, [https\://github\.com/ansible\-collections/community\.general/issues/4305](https\://github\.com/ansible\-collections/community\.general/issues/4305)\)\.
|
||||
* machinectl become plugin \- mark plugin as <code>require\_tty</code> to automatically disable pipelining\, with which this plugin is not compatible \([https\://github\.com/ansible\-collections/community\.general/issues/6932](https\://github\.com/ansible\-collections/community\.general/issues/6932)\, [https\://github\.com/ansible\-collections/community\.general/pull/6935](https\://github\.com/ansible\-collections/community\.general/pull/6935)\)\.
|
||||
* nmcli \- fix support for empty list \(in compare and scrape\) \([https\://github\.com/ansible\-collections/community\.general/pull/6769](https\://github\.com/ansible\-collections/community\.general/pull/6769)\)\.
|
||||
* openbsd\_pkg \- the pkg\_info\(1\) behavior has changed in OpenBSD \>7\.3\. The error message <code>Can\'t find</code> should not lead to an error case \([https\://github\.com/ansible\-collections/community\.general/pull/6785](https\://github\.com/ansible\-collections/community\.general/pull/6785)\)\.
|
||||
* pacman \- module recognizes the output of <code>yay</code> running as <code>root</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6713](https\://github\.com/ansible\-collections/community\.general/pull/6713)\)\.
|
||||
* proxmox \- fix error when a configuration had no <code>template</code> field \([https\://github\.com/ansible\-collections/community\.general/pull/6838](https\://github\.com/ansible\-collections/community\.general/pull/6838)\, [https\://github\.com/ansible\-collections/community\.general/issues/5372](https\://github\.com/ansible\-collections/community\.general/issues/5372)\)\.
|
||||
* proxmox module utils \- add logic to detect whether an old Promoxer complains about the <code>token\_name</code> and <code>token\_value</code> parameters and provide a better error message when that happens \([https\://github\.com/ansible\-collections/community\.general/pull/6839](https\://github\.com/ansible\-collections/community\.general/pull/6839)\, [https\://github\.com/ansible\-collections/community\.general/issues/5371](https\://github\.com/ansible\-collections/community\.general/issues/5371)\)\.
|
||||
* proxmox\_disk \- fix unable to create <code>cdrom</code> media due to <code>size</code> always being appended \([https\://github\.com/ansible\-collections/community\.general/pull/6770](https\://github\.com/ansible\-collections/community\.general/pull/6770)\)\.
|
||||
* proxmox\_kvm \- <code>absent</code> state with <code>force</code> specified failed to stop the VM due to the <code>timeout</code> value not being passed to <code>stop\_vm</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6827](https\://github\.com/ansible\-collections/community\.general/pull/6827)\)\.
|
||||
* redfish\_info \- fix <code>ListUsers</code> to not show empty account slots \([https\://github\.com/ansible\-collections/community\.general/issues/6771](https\://github\.com/ansible\-collections/community\.general/issues/6771)\, [https\://github\.com/ansible\-collections/community\.general/pull/6772](https\://github\.com/ansible\-collections/community\.general/pull/6772)\)\.
|
||||
* refish\_utils module utils \- changing variable names to avoid issues occuring when fetching Volumes data \([https\://github\.com/ansible\-collections/community\.general/pull/6883](https\://github\.com/ansible\-collections/community\.general/pull/6883)\)\.
|
||||
* rhsm\_repository \- when using the <code>purge</code> option\, the <code>repositories</code>
|
||||
dictionary element in the returned JSON is now properly updated according
|
||||
to the pruning operation
|
||||
\([https\://github\.com/ansible\-collections/community\.general/pull/6676](https\://github\.com/ansible\-collections/community\.general/pull/6676)\)\.
|
||||
|
||||
<a id="v6-6-2"></a>
|
||||
## v6\.6\.2
|
||||
|
||||
<a id="release-summary-7"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="bugfixes-7"></a>
|
||||
### Bugfixes
|
||||
|
||||
* csv module utils \- detects and remove unicode BOM markers from incoming CSV content \([https\://github\.com/ansible\-collections/community\.general/pull/6662](https\://github\.com/ansible\-collections/community\.general/pull/6662)\)\.
|
||||
* gitlab\_group \- the module passed parameters to the API call even when not set\. The module is now filtering out <code>None</code> values to remediate this \([https\://github\.com/ansible\-collections/community\.general/pull/6712](https\://github\.com/ansible\-collections/community\.general/pull/6712)\)\.
|
||||
* ini\_file \- fix a bug where the inactive options were not used when possible \([https\://github\.com/ansible\-collections/community\.general/pull/6575](https\://github\.com/ansible\-collections/community\.general/pull/6575)\)\.
|
||||
* keycloak module utils \- fix <code>is\_struct\_included</code> handling of lists of lists/dictionaries \([https\://github\.com/ansible\-collections/community\.general/pull/6688](https\://github\.com/ansible\-collections/community\.general/pull/6688)\)\.
|
||||
* keycloak module utils \- the function <code>get\_user\_by\_username</code> now return the user representation or <code>None</code> as stated in the documentation \([https\://github\.com/ansible\-collections/community\.general/pull/6758](https\://github\.com/ansible\-collections/community\.general/pull/6758)\)\.
|
||||
|
||||
<a id="v6-6-1"></a>
|
||||
## v6\.6\.1
|
||||
|
||||
<a id="release-summary-8"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix release\.
|
||||
|
||||
<a id="minor-changes-3"></a>
|
||||
### Minor Changes
|
||||
|
||||
* dconf \- if <code>gi\.repository\.GLib</code> is missing\, try to respawn in a Python interpreter that has it \([https\://github\.com/ansible\-collections/community\.general/pull/6491](https\://github\.com/ansible\-collections/community\.general/pull/6491)\)\.
|
||||
|
||||
<a id="bugfixes-8"></a>
|
||||
### Bugfixes
|
||||
|
||||
* deps module utils \- do not fail when dependency cannot be found \([https\://github\.com/ansible\-collections/community\.general/pull/6479](https\://github\.com/ansible\-collections/community\.general/pull/6479)\)\.
|
||||
* nmcli \- fix bond option <code>xmit\_hash\_policy</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6527](https\://github\.com/ansible\-collections/community\.general/pull/6527)\)\.
|
||||
* passwordstore lookup plugin \- make compatible with ansible\-core 2\.16 \([https\://github\.com/ansible\-collections/community\.general/pull/6447](https\://github\.com/ansible\-collections/community\.general/pull/6447)\)\.
|
||||
* portage \- fix <code>changed\_use</code> and <code>newuse</code> not triggering rebuilds \([https\://github\.com/ansible\-collections/community\.general/issues/6008](https\://github\.com/ansible\-collections/community\.general/issues/6008)\, [https\://github\.com/ansible\-collections/community\.general/pull/6548](https\://github\.com/ansible\-collections/community\.general/pull/6548)\)\.
|
||||
* portage \- update the logic for generating the emerge command arguments to ensure that <code>withbdeps\: false</code> results in a passing an <code>n</code> argument with the <code>\-\-with\-bdeps</code> emerge flag \([https\://github\.com/ansible\-collections/community\.general/issues/6451](https\://github\.com/ansible\-collections/community\.general/issues/6451)\, [https\://github\.com/ansible\-collections/community\.general/pull/6456](https\://github\.com/ansible\-collections/community\.general/pull/6456)\)\.
|
||||
* proxmox\_tasks\_info \- remove <code>api\_user</code> \+ <code>api\_password</code> constraint from <code>required\_together</code> as it causes to require <code>api\_password</code> even when API token param is used \([https\://github\.com/ansible\-collections/community\.general/issues/6201](https\://github\.com/ansible\-collections/community\.general/issues/6201)\)\.
|
||||
* puppet \- handling <code>noop</code> parameter was not working at all\, now it is has been fixed \([https\://github\.com/ansible\-collections/community\.general/issues/6452](https\://github\.com/ansible\-collections/community\.general/issues/6452)\, [https\://github\.com/ansible\-collections/community\.general/issues/6458](https\://github\.com/ansible\-collections/community\.general/issues/6458)\)\.
|
||||
* terraform \- fix broken <code>warn\(\)</code> call \([https\://github\.com/ansible\-collections/community\.general/pull/6497](https\://github\.com/ansible\-collections/community\.general/pull/6497)\)\.
|
||||
* xfs\_quota \- in case of a project quota\, the call to <code>xfs\_quota</code> did not initialize/reset the project \([https\://github\.com/ansible\-collections/community\.general/issues/5143](https\://github\.com/ansible\-collections/community\.general/issues/5143)\)\.
|
||||
* zypper \- added handling of zypper exitcode 102\. Changed state is set correctly now and rc 102 is still preserved to be evaluated by the playbook \([https\://github\.com/ansible\-collections/community\.general/pull/6534](https\://github\.com/ansible\-collections/community\.general/pull/6534)\)\.
|
||||
|
||||
<a id="v6-6-0"></a>
|
||||
## v6\.6\.0
|
||||
|
||||
<a id="release-summary-9"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-4"></a>
|
||||
### Minor Changes
|
||||
|
||||
* cpanm \- minor change\, use feature from <code>ModuleHelper</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6385](https\://github\.com/ansible\-collections/community\.general/pull/6385)\)\.
|
||||
* dconf \- be forgiving about boolean values\: convert them to GVariant booleans automatically \([https\://github\.com/ansible\-collections/community\.general/pull/6206](https\://github\.com/ansible\-collections/community\.general/pull/6206)\)\.
|
||||
* dconf \- minor refactoring improving parameters and dependencies validation \([https\://github\.com/ansible\-collections/community\.general/pull/6336](https\://github\.com/ansible\-collections/community\.general/pull/6336)\)\.
|
||||
* deps module utils \- add function <code>failed\(\)</code> providing the ability to check the dependency check result without triggering an exception \([https\://github\.com/ansible\-collections/community\.general/pull/6383](https\://github\.com/ansible\-collections/community\.general/pull/6383)\)\.
|
||||
* dig lookup plugin \- Support multiple domains to be queried as indicated in docs \([https\://github\.com/ansible\-collections/community\.general/pull/6334](https\://github\.com/ansible\-collections/community\.general/pull/6334)\)\.
|
||||
* gitlab\_project \- add new option <code>topics</code> for adding topics to GitLab projects \([https\://github\.com/ansible\-collections/community\.general/pull/6278](https\://github\.com/ansible\-collections/community\.general/pull/6278)\)\.
|
||||
* homebrew\_cask \- allows passing <code>\-\-greedy</code> option to <code>upgrade\_all</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6267](https\://github\.com/ansible\-collections/community\.general/pull/6267)\)\.
|
||||
* idrac\_redfish\_command \- add <code>job\_id</code> to <code>CreateBiosConfigJob</code> response \([https\://github\.com/ansible\-collections/community\.general/issues/5603](https\://github\.com/ansible\-collections/community\.general/issues/5603)\)\.
|
||||
* ipa\_hostgroup \- add <code>append</code> parameter for adding a new hosts to existing hostgroups without changing existing hostgroup members \([https\://github\.com/ansible\-collections/community\.general/pull/6203](https\://github\.com/ansible\-collections/community\.general/pull/6203)\)\.
|
||||
* keycloak\_authentication \- add flow type option to sub flows to allow the creation of \'form\-flow\' sub flows like in Keycloak\'s built\-in registration flow \([https\://github\.com/ansible\-collections/community\.general/pull/6318](https\://github\.com/ansible\-collections/community\.general/pull/6318)\)\.
|
||||
* mksysb \- improved the output of the module in case of errors \([https\://github\.com/ansible\-collections/community\.general/issues/6263](https\://github\.com/ansible\-collections/community\.general/issues/6263)\)\.
|
||||
* nmap inventory plugin \- added environment variables for configure <code>address</code> and <code>exclude</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6351](https\://github\.com/ansible\-collections/community\.general/issues/6351)\)\.
|
||||
* nmcli \- add <code>macvlan</code> connection type \([https\://github\.com/ansible\-collections/community\.general/pull/6312](https\://github\.com/ansible\-collections/community\.general/pull/6312)\)\.
|
||||
* pipx \- add <code>system\_site\_packages</code> parameter to give application access to system\-wide packages \([https\://github\.com/ansible\-collections/community\.general/pull/6308](https\://github\.com/ansible\-collections/community\.general/pull/6308)\)\.
|
||||
* pipx \- ensure <code>include\_injected</code> parameter works with <code>state\=upgrade</code> and <code>state\=latest</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6212](https\://github\.com/ansible\-collections/community\.general/pull/6212)\)\.
|
||||
* puppet \- add new options <code>skip\_tags</code> to exclude certain tagged resources during a puppet agent or apply \([https\://github\.com/ansible\-collections/community\.general/pull/6293](https\://github\.com/ansible\-collections/community\.general/pull/6293)\)\.
|
||||
* terraform \- remove state file check condition and error block\, because in the native implementation of terraform will not cause errors due to the non\-existent file \([https\://github\.com/ansible\-collections/community\.general/pull/6296](https\://github\.com/ansible\-collections/community\.general/pull/6296)\)\.
|
||||
* udm\_dns\_record \- minor refactor to the code \([https\://github\.com/ansible\-collections/community\.general/pull/6382](https\://github\.com/ansible\-collections/community\.general/pull/6382)\)\.
|
||||
|
||||
<a id="bugfixes-9"></a>
|
||||
### Bugfixes
|
||||
|
||||
* archive \- reduce RAM usage by generating CRC32 checksum over chunks \([https\://github\.com/ansible\-collections/community\.general/pull/6274](https\://github\.com/ansible\-collections/community\.general/pull/6274)\)\.
|
||||
* flatpak \- fixes idempotency detection issues\. In some cases the module could fail to properly detect already existing Flatpaks because of a parameter witch only checks the installed apps \([https\://github\.com/ansible\-collections/community\.general/pull/6289](https\://github\.com/ansible\-collections/community\.general/pull/6289)\)\.
|
||||
* icinga2\_host \- fix the data structure sent to Icinga to make use of host templates and template vars \([https\://github\.com/ansible\-collections/community\.general/pull/6286](https\://github\.com/ansible\-collections/community\.general/pull/6286)\)\.
|
||||
* idrac\_redfish\_command \- allow user to specify <code>resource\_id</code> for <code>CreateBiosConfigJob</code> to specify an exact manager \([https\://github\.com/ansible\-collections/community\.general/issues/2090](https\://github\.com/ansible\-collections/community\.general/issues/2090)\)\.
|
||||
* ini\_file \- make <code>section</code> parameter not required so it is possible to pass <code>null</code> as a value\. This only was possible in the past due to a bug in ansible\-core that now has been fixed \([https\://github\.com/ansible\-collections/community\.general/pull/6404](https\://github\.com/ansible\-collections/community\.general/pull/6404)\)\.
|
||||
* keycloak \- improve error messages \([https\://github\.com/ansible\-collections/community\.general/pull/6318](https\://github\.com/ansible\-collections/community\.general/pull/6318)\)\.
|
||||
* one\_vm \- fix syntax error when creating VMs with a more complex template \([https\://github\.com/ansible\-collections/community\.general/issues/6225](https\://github\.com/ansible\-collections/community\.general/issues/6225)\)\.
|
||||
* pipx \- fixed handling of <code>install\_deps\=true</code> with <code>state\=latest</code> and <code>state\=upgrade</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6303](https\://github\.com/ansible\-collections/community\.general/pull/6303)\)\.
|
||||
* redhat\_subscription \- do not use D\-Bus for registering when <code>environment</code> is specified\, so it possible to specify again the environment names for registering\, as the D\-Bus APIs work only with IDs \([https\://github\.com/ansible\-collections/community\.general/pull/6319](https\://github\.com/ansible\-collections/community\.general/pull/6319)\)\.
|
||||
* redhat\_subscription \- try to unregister only when already registered when <code>force\_register</code> is specified \([https\://github\.com/ansible\-collections/community\.general/issues/6258](https\://github\.com/ansible\-collections/community\.general/issues/6258)\, [https\://github\.com/ansible\-collections/community\.general/pull/6259](https\://github\.com/ansible\-collections/community\.general/pull/6259)\)\.
|
||||
* redhat\_subscription \- use the right D\-Bus options for environments when registering a CentOS Stream 8 system and using <code>environment</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6275](https\://github\.com/ansible\-collections/community\.general/pull/6275)\)\.
|
||||
* rhsm\_release \- make <code>release</code> parameter not required so it is possible to pass <code>null</code> as a value\. This only was possible in the past due to a bug in ansible\-core that now has been fixed \([https\://github\.com/ansible\-collections/community\.general/pull/6401](https\://github\.com/ansible\-collections/community\.general/pull/6401)\)\.
|
||||
* rundeck module utils \- fix errors caused by the API empty responses \([https\://github\.com/ansible\-collections/community\.general/pull/6300](https\://github\.com/ansible\-collections/community\.general/pull/6300)\)
|
||||
* rundeck\_acl\_policy \- fix <code>TypeError \- byte indices must be integers or slices\, not str</code> error caused by empty API response\. Update the module to use <code>module\_utils\.rundeck</code> functions \([https\://github\.com/ansible\-collections/community\.general/pull/5887](https\://github\.com/ansible\-collections/community\.general/pull/5887)\, [https\://github\.com/ansible\-collections/community\.general/pull/6300](https\://github\.com/ansible\-collections/community\.general/pull/6300)\)\.
|
||||
* rundeck\_project \- update the module to use <code>module\_utils\.rundeck</code> functions \([https\://github\.com/ansible\-collections/community\.general/issues/5742](https\://github\.com/ansible\-collections/community\.general/issues/5742)\) \([https\://github\.com/ansible\-collections/community\.general/pull/6300](https\://github\.com/ansible\-collections/community\.general/pull/6300)\)
|
||||
* snap\_alias \- module would only recognize snap names containing letter\, numbers or the underscore character\, failing to identify valid snap names such as <code>lxd\.lxc</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6361](https\://github\.com/ansible\-collections/community\.general/pull/6361)\)\.
|
||||
|
||||
<a id="new-modules"></a>
|
||||
### New Modules
|
||||
|
||||
* btrfs\_info \- Query btrfs filesystem info
|
||||
* btrfs\_subvolume \- Manage btrfs subvolumes
|
||||
* ilo\_redfish\_command \- Manages Out\-Of\-Band controllers using Redfish APIs
|
||||
* keycloak\_authz\_authorization\_scope \- Allows administration of Keycloak client authorization scopes via Keycloak API
|
||||
* keycloak\_clientscope\_type \- Set the type of aclientscope in realm or client via Keycloak API
|
||||
|
||||
<a id="v6-5-0"></a>
|
||||
## v6\.5\.0
|
||||
|
||||
<a id="release-summary-10"></a>
|
||||
### Release Summary
|
||||
|
||||
Feature and bugfix release\.
|
||||
|
||||
<a id="minor-changes-5"></a>
|
||||
### Minor Changes
|
||||
|
||||
* apt\_rpm \- adds <code>clean</code>\, <code>dist\_upgrade</code> and <code>update\_kernel</code> parameters for clear caches\, complete upgrade system\, and upgrade kernel packages \([https\://github\.com/ansible\-collections/community\.general/pull/5867](https\://github\.com/ansible\-collections/community\.general/pull/5867)\)\.
|
||||
* dconf \- parse GVariants for equality comparison when the Python module <code>gi\.repository</code> is available \([https\://github\.com/ansible\-collections/community\.general/pull/6049](https\://github\.com/ansible\-collections/community\.general/pull/6049)\)\.
|
||||
* gitlab\_runner \- allow to register group runner \([https\://github\.com/ansible\-collections/community\.general/pull/3935](https\://github\.com/ansible\-collections/community\.general/pull/3935)\)\.
|
||||
* jira \- add worklog functionality \([https\://github\.com/ansible\-collections/community\.general/issues/6209](https\://github\.com/ansible\-collections/community\.general/issues/6209)\, [https\://github\.com/ansible\-collections/community\.general/pull/6210](https\://github\.com/ansible\-collections/community\.general/pull/6210)\)\.
|
||||
* ldap modules \- add <code>ca\_path</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/6185](https\://github\.com/ansible\-collections/community\.general/pull/6185)\)\.
|
||||
* make \- add <code>command</code> return value to the module output \([https\://github\.com/ansible\-collections/community\.general/pull/6160](https\://github\.com/ansible\-collections/community\.general/pull/6160)\)\.
|
||||
* nmap inventory plugin \- add new option <code>open</code> for only returning open ports \([https\://github\.com/ansible\-collections/community\.general/pull/6200](https\://github\.com/ansible\-collections/community\.general/pull/6200)\)\.
|
||||
* nmap inventory plugin \- add new option <code>port</code> for port specific scan \([https\://github\.com/ansible\-collections/community\.general/pull/6165](https\://github\.com/ansible\-collections/community\.general/pull/6165)\)\.
|
||||
* nmcli \- add <code>default</code> and <code>default\-or\-eui64</code> to the list of valid choices for <code>addr\_gen\_mode6</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/5974](https\://github\.com/ansible\-collections/community\.general/pull/5974)\)\.
|
||||
* nmcli \- add support for <code>team\.runner\-fast\-rate</code> parameter for <code>team</code> connections \([https\://github\.com/ansible\-collections/community\.general/issues/6065](https\://github\.com/ansible\-collections/community\.general/issues/6065)\)\.
|
||||
* openbsd\_pkg \- set <code>TERM</code> to <code>\'dumb\'</code> in <code>execute\_command\(\)</code> to make module less dependant on the <code>TERM</code> environment variable set on the Ansible controller \([https\://github\.com/ansible\-collections/community\.general/pull/6149](https\://github\.com/ansible\-collections/community\.general/pull/6149)\)\.
|
||||
* pipx \- optional <code>install\_apps</code> parameter added to install applications from injected packages \([https\://github\.com/ansible\-collections/community\.general/pull/6198](https\://github\.com/ansible\-collections/community\.general/pull/6198)\)\.
|
||||
* proxmox\_kvm \- add new <code>archive</code> parameter\. This is needed to create a VM from an archive \(backup\) \([https\://github\.com/ansible\-collections/community\.general/pull/6159](https\://github\.com/ansible\-collections/community\.general/pull/6159)\)\.
|
||||
* redfish\_info \- adds commands to retrieve the HPE ThermalConfiguration and FanPercentMinimum settings from iLO \([https\://github\.com/ansible\-collections/community\.general/pull/6208](https\://github\.com/ansible\-collections/community\.general/pull/6208)\)\.
|
||||
* redhat\_subscription \- credentials \(<code>username</code>\, <code>activationkey</code>\, and so on\) are required now only if a system needs to be registered\, or <code>force\_register</code> is specified \([https\://github\.com/ansible\-collections/community\.general/pull/5664](https\://github\.com/ansible\-collections/community\.general/pull/5664)\)\.
|
||||
* redhat\_subscription \- the registration is done using the D\-Bus <code>rhsm</code> service instead of spawning a <code>subscription\-manager register</code> command\, if possible\; this avoids passing plain\-text credentials as arguments to <code>subscription\-manager register</code>\, which can be seen while that command runs \([https\://github\.com/ansible\-collections/community\.general/pull/6122](https\://github\.com/ansible\-collections/community\.general/pull/6122)\)\.
|
||||
* ssh\_config \- add <code>proxyjump</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/5970](https\://github\.com/ansible\-collections/community\.general/pull/5970)\)\.
|
||||
* ssh\_config \- vendored StormSSH\'s config parser to avoid having to install StormSSH to use the module \([https\://github\.com/ansible\-collections/community\.general/pull/6117](https\://github\.com/ansible\-collections/community\.general/pull/6117)\)\.
|
||||
* znode module \- optional <code>use\_tls</code> parameter added for encrypted communication \([https\://github\.com/ansible\-collections/community\.general/issues/6154](https\://github\.com/ansible\-collections/community\.general/issues/6154)\)\.
|
||||
|
||||
<a id="bugfixes-10"></a>
|
||||
### Bugfixes
|
||||
|
||||
* archive \- avoid deprecated exception class on Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/6180](https\://github\.com/ansible\-collections/community\.general/pull/6180)\)\.
|
||||
* gitlab\_runner \- fix <code>KeyError</code> on runner creation and update \([https\://github\.com/ansible\-collections/community\.general/issues/6112](https\://github\.com/ansible\-collections/community\.general/issues/6112)\)\.
|
||||
* influxdb\_user \- fix running in check mode when the user does not exist yet \([https\://github\.com/ansible\-collections/community\.general/pull/6111](https\://github\.com/ansible\-collections/community\.general/pull/6111)\)\.
|
||||
* interfaces\_file \- fix reading options in lines not starting with a space \([https\://github\.com/ansible\-collections/community\.general/issues/6120](https\://github\.com/ansible\-collections/community\.general/issues/6120)\)\.
|
||||
* jail connection plugin \- add <code>inventory\_hostname</code> to vars under <code>remote\_addr</code>\. This is needed for compatibility with ansible\-core 2\.13 \([https\://github\.com/ansible\-collections/community\.general/pull/6118](https\://github\.com/ansible\-collections/community\.general/pull/6118)\)\.
|
||||
* memset \- fix memset urlerror handling \([https\://github\.com/ansible\-collections/community\.general/pull/6114](https\://github\.com/ansible\-collections/community\.general/pull/6114)\)\.
|
||||
* nmcli \- fixed idempotency issue for bridge connections\. Module forced default value of <code>bridge\.priority</code> to nmcli if not set\; if <code>bridge\.stp</code> is disabled nmcli ignores it and keep default \([https\://github\.com/ansible\-collections/community\.general/issues/3216](https\://github\.com/ansible\-collections/community\.general/issues/3216)\, [https\://github\.com/ansible\-collections/community\.general/issues/4683](https\://github\.com/ansible\-collections/community\.general/issues/4683)\)\.
|
||||
* nmcli \- fixed idempotency issue when module params is set to <code>may\_fail4\=false</code> and <code>method4\=disabled</code>\; in this case nmcli ignores change and keeps their own default value <code>yes</code> \([https\://github\.com/ansible\-collections/community\.general/pull/6106](https\://github\.com/ansible\-collections/community\.general/pull/6106)\)\.
|
||||
* nmcli \- implemented changing mtu value on vlan interfaces \([https\://github\.com/ansible\-collections/community\.general/issues/4387](https\://github\.com/ansible\-collections/community\.general/issues/4387)\)\.
|
||||
* opkg \- fixes bug when using <code>update\_cache\=true</code> \([https\://github\.com/ansible\-collections/community\.general/issues/6004](https\://github\.com/ansible\-collections/community\.general/issues/6004)\)\.
|
||||
* redhat\_subscription\, rhsm\_release\, rhsm\_repository \- cleanly fail when not running as root\, rather than hanging on an interactive <code>console\-helper</code> prompt\; they all interact with <code>subscription\-manager</code>\, which already requires to be run as root \([https\://github\.com/ansible\-collections/community\.general/issues/734](https\://github\.com/ansible\-collections/community\.general/issues/734)\, [https\://github\.com/ansible\-collections/community\.general/pull/6211](https\://github\.com/ansible\-collections/community\.general/pull/6211)\)\.
|
||||
* xenorchestra inventory plugin \- fix failure to receive objects from server due to not checking the id of the response \([https\://github\.com/ansible\-collections/community\.general/pull/6227](https\://github\.com/ansible\-collections/community\.general/pull/6227)\)\.
|
||||
* yarn \- fix <code>global\=true</code> to not fail when <em class="title-reference">executable</em> wasn\'t specified \([https\://github\.com/ansible\-collections/community\.general/pull/6132](https\://github\.com/ansible\-collections/community\.general/pull/6132)\)
|
||||
* yarn \- fixes bug where yarn module tasks would fail when warnings were emitted from Yarn\. The <code>yarn\.list</code> method was not filtering out warnings \([https\://github\.com/ansible\-collections/community\.general/issues/6127](https\://github\.com/ansible\-collections/community\.general/issues/6127)\)\.
|
||||
|
||||
<a id="new-plugins"></a>
|
||||
### New Plugins
|
||||
|
||||
<a id="lookup"></a>
|
||||
#### Lookup
|
||||
|
||||
* merge\_variables \- merge variables with a certain suffix
|
||||
|
||||
<a id="new-modules-1"></a>
|
||||
### New Modules
|
||||
|
||||
* kdeconfig \- Manage KDE configuration files
|
||||
|
||||
<a id="v6-4-0"></a>
|
||||
## v6\.4\.0
|
||||
|
||||
<a id="release-summary-11"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular feature and bugfix release\.
|
||||
|
||||
<a id="minor-changes-6"></a>
|
||||
### Minor Changes
|
||||
|
||||
* dnsimple \- set custom User\-Agent for API requests to DNSimple \([https\://github\.com/ansible\-collections/community\.general/pull/5927](https\://github\.com/ansible\-collections/community\.general/pull/5927)\)\.
|
||||
* flatpak\_remote \- add new boolean option <code>enabled</code>\. It controls\, whether the remote is enabled or not \([https\://github\.com/ansible\-collections/community\.general/pull/5926](https\://github\.com/ansible\-collections/community\.general/pull/5926)\)\.
|
||||
* gitlab\_project \- add <code>releases\_access\_level</code>\, <code>environments\_access\_level</code>\, <code>feature\_flags\_access\_level</code>\, <code>infrastructure\_access\_level</code>\, <code>monitor\_access\_level</code>\, and <code>security\_and\_compliance\_access\_level</code> options \([https\://github\.com/ansible\-collections/community\.general/pull/5986](https\://github\.com/ansible\-collections/community\.general/pull/5986)\)\.
|
||||
* jc filter plugin \- added the ability to use parser plugins \([https\://github\.com/ansible\-collections/community\.general/pull/6043](https\://github\.com/ansible\-collections/community\.general/pull/6043)\)\.
|
||||
* keycloak\_group \- add new optional module parameter <code>parents</code> to properly handle keycloak subgroups \([https\://github\.com/ansible\-collections/community\.general/pull/5814](https\://github\.com/ansible\-collections/community\.general/pull/5814)\)\.
|
||||
* keycloak\_user\_federation \- make <code>org\.keycloak\.storage\.ldap\.mappers\.LDAPStorageMapper</code> the default value for mappers <code>providerType</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5863](https\://github\.com/ansible\-collections/community\.general/pull/5863)\)\.
|
||||
* ldap modules \- add <code>xorder\_discovery</code> option \([https\://github\.com/ansible\-collections/community\.general/issues/6045](https\://github\.com/ansible\-collections/community\.general/issues/6045)\, [https\://github\.com/ansible\-collections/community\.general/pull/6109](https\://github\.com/ansible\-collections/community\.general/pull/6109)\)\.
|
||||
* lxd\_container \- add diff and check mode \([https\://github\.com/ansible\-collections/community\.general/pull/5866](https\://github\.com/ansible\-collections/community\.general/pull/5866)\)\.
|
||||
* mattermost\, rocketchat\, slack \- replace missing default favicon with docs\.ansible\.com favicon \([https\://github\.com/ansible\-collections/community\.general/pull/5928](https\://github\.com/ansible\-collections/community\.general/pull/5928)\)\.
|
||||
* modprobe \- add <code>persistent</code> option \([https\://github\.com/ansible\-collections/community\.general/issues/4028](https\://github\.com/ansible\-collections/community\.general/issues/4028)\, [https\://github\.com/ansible\-collections/community\.general/pull/542](https\://github\.com/ansible\-collections/community\.general/pull/542)\)\.
|
||||
* osx\_defaults \- include stderr in error messages \([https\://github\.com/ansible\-collections/community\.general/pull/6011](https\://github\.com/ansible\-collections/community\.general/pull/6011)\)\.
|
||||
* proxmox \- suppress urllib3 <code>InsecureRequestWarnings</code> when <code>validate\_certs</code> option is <code>false</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5931](https\://github\.com/ansible\-collections/community\.general/pull/5931)\)\.
|
||||
* redfish\_command \- adding <code>EnableSecureBoot</code> functionality \([https\://github\.com/ansible\-collections/community\.general/pull/5899](https\://github\.com/ansible\-collections/community\.general/pull/5899)\)\.
|
||||
* redfish\_command \- adding <code>VerifyBiosAttributes</code> functionality \([https\://github\.com/ansible\-collections/community\.general/pull/5900](https\://github\.com/ansible\-collections/community\.general/pull/5900)\)\.
|
||||
* sefcontext \- add support for path substitutions \([https\://github\.com/ansible\-collections/community\.general/issues/1193](https\://github\.com/ansible\-collections/community\.general/issues/1193)\)\.
|
||||
|
||||
<a id="deprecated-features"></a>
|
||||
### Deprecated Features
|
||||
|
||||
* gitlab\_runner \- the option <code>access\_level</code> will lose its default value in community\.general 8\.0\.0\. From that version on\, you have set this option to <code>ref\_protected</code> explicitly\, if you want to have a protected runner \([https\://github\.com/ansible\-collections/community\.general/issues/5925](https\://github\.com/ansible\-collections/community\.general/issues/5925)\)\.
|
||||
|
||||
<a id="bugfixes-11"></a>
|
||||
### Bugfixes
|
||||
|
||||
* cartesian and flattened lookup plugins \- adjust to parameter deprecation in ansible\-core 2\.14\'s <code>listify\_lookup\_plugin\_terms</code> helper function \([https\://github\.com/ansible\-collections/community\.general/pull/6074](https\://github\.com/ansible\-collections/community\.general/pull/6074)\)\.
|
||||
* cloudflare\_dns \- fixed the idempotency for SRV DNS records \([https\://github\.com/ansible\-collections/community\.general/pull/5972](https\://github\.com/ansible\-collections/community\.general/pull/5972)\)\.
|
||||
* cloudflare\_dns \- fixed the possiblity of setting a root\-level SRV DNS record \([https\://github\.com/ansible\-collections/community\.general/pull/5972](https\://github\.com/ansible\-collections/community\.general/pull/5972)\)\.
|
||||
* github\_webhook \- fix always changed state when no secret is provided \([https\://github\.com/ansible\-collections/community\.general/pull/5994](https\://github\.com/ansible\-collections/community\.general/pull/5994)\)\.
|
||||
* jenkins\_plugin \- fix error due to undefined variable when updates file is not downloaded \([https\://github\.com/ansible\-collections/community\.general/pull/6100](https\://github\.com/ansible\-collections/community\.general/pull/6100)\)\.
|
||||
* keycloak\_client \- fix accidental replacement of value for attribute <code>saml\.signing\.private\.key</code> with <code>no\_log</code> in wrong contexts \([https\://github\.com/ansible\-collections/community\.general/pull/5934](https\://github\.com/ansible\-collections/community\.general/pull/5934)\)\.
|
||||
* lxd\_\* modules\, lxd inventory plugin \- fix TLS/SSL certificate validation problems by using the correct purpose when creating the TLS context \([https\://github\.com/ansible\-collections/community\.general/issues/5616](https\://github\.com/ansible\-collections/community\.general/issues/5616)\, [https\://github\.com/ansible\-collections/community\.general/pull/6034](https\://github\.com/ansible\-collections/community\.general/pull/6034)\)\.
|
||||
* nmcli \- fix change handling of values specified as an integer 0 \([https\://github\.com/ansible\-collections/community\.general/pull/5431](https\://github\.com/ansible\-collections/community\.general/pull/5431)\)\.
|
||||
* nmcli \- fix failure to handle WIFI settings when connection type not specified \([https\://github\.com/ansible\-collections/community\.general/pull/5431](https\://github\.com/ansible\-collections/community\.general/pull/5431)\)\.
|
||||
* nmcli \- fix improper detection of changes to <code>wifi\.wake\-on\-wlan</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5431](https\://github\.com/ansible\-collections/community\.general/pull/5431)\)\.
|
||||
* nmcli \- order is significant for lists of addresses \([https\://github\.com/ansible\-collections/community\.general/pull/6048](https\://github\.com/ansible\-collections/community\.general/pull/6048)\)\.
|
||||
* onepassword lookup plugin \- Changed to ignore errors from \"op account get\" calls\. Previously\, errors would prevent auto\-signin code from executing \([https\://github\.com/ansible\-collections/community\.general/pull/5942](https\://github\.com/ansible\-collections/community\.general/pull/5942)\)\.
|
||||
* terraform and timezone \- slight refactoring to avoid linter reporting potentially undefined variables \([https\://github\.com/ansible\-collections/community\.general/pull/5933](https\://github\.com/ansible\-collections/community\.general/pull/5933)\)\.
|
||||
* various plugins and modules \- remove unnecessary imports \([https\://github\.com/ansible\-collections/community\.general/pull/5940](https\://github\.com/ansible\-collections/community\.general/pull/5940)\)\.
|
||||
* yarn \- fix <code>global\=true</code> to check for the configured global folder instead of assuming the default \([https\://github\.com/ansible\-collections/community\.general/pull/5829](https\://github\.com/ansible\-collections/community\.general/pull/5829)\)
|
||||
* yarn \- fix <code>state\=absent</code> not working with <code>global\=true</code> when the package does not include a binary \([https\://github\.com/ansible\-collections/community\.general/pull/5829](https\://github\.com/ansible\-collections/community\.general/pull/5829)\)
|
||||
* yarn \- fix <code>state\=latest</code> not working with <code>global\=true</code> \([https\://github\.com/ansible\-collections/community\.general/issues/5712](https\://github\.com/ansible\-collections/community\.general/issues/5712)\)\.
|
||||
* zfs\_delegate\_admin \- zfs allow output can now be parsed when uids/gids are not known to the host system \([https\://github\.com/ansible\-collections/community\.general/pull/5943](https\://github\.com/ansible\-collections/community\.general/pull/5943)\)\.
|
||||
* zypper \- make package managing work on readonly filesystem of openSUSE MicroOS \([https\://github\.com/ansible\-collections/community\.general/pull/5615](https\://github\.com/ansible\-collections/community\.general/pull/5615)\)\.
|
||||
|
||||
<a id="v6-3-0"></a>
|
||||
## v6\.3\.0
|
||||
|
||||
<a id="release-summary-12"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-7"></a>
|
||||
### Minor Changes
|
||||
|
||||
* apache2\_module \- add module argument <code>warn\_mpm\_absent</code> to control whether warning are raised in some edge cases \([https\://github\.com/ansible\-collections/community\.general/pull/5793](https\://github\.com/ansible\-collections/community\.general/pull/5793)\)\.
|
||||
* bitwarden lookup plugin \- can now retrieve secrets from custom fields \([https\://github\.com/ansible\-collections/community\.general/pull/5694](https\://github\.com/ansible\-collections/community\.general/pull/5694)\)\.
|
||||
* bitwarden lookup plugin \- implement filtering results by <code>collection\_id</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/5849](https\://github\.com/ansible\-collections/community\.general/issues/5849)\)\.
|
||||
* dig lookup plugin \- support CAA record type \([https\://github\.com/ansible\-collections/community\.general/pull/5913](https\://github\.com/ansible\-collections/community\.general/pull/5913)\)\.
|
||||
* gitlab\_project \- add <code>builds\_access\_level</code>\, <code>container\_registry\_access\_level</code> and <code>forking\_access\_level</code> options \([https\://github\.com/ansible\-collections/community\.general/pull/5706](https\://github\.com/ansible\-collections/community\.general/pull/5706)\)\.
|
||||
* gitlab\_runner \- add new boolean option <code>access\_level\_on\_creation</code>\. It controls\, whether the value of <code>access\_level</code> is used for runner registration or not\. The option <code>access\_level</code> has been ignored on registration so far and was only used on updates \([https\://github\.com/ansible\-collections/community\.general/issues/5907](https\://github\.com/ansible\-collections/community\.general/issues/5907)\, [https\://github\.com/ansible\-collections/community\.general/pull/5908](https\://github\.com/ansible\-collections/community\.general/pull/5908)\)\.
|
||||
* ilo\_redfish\_utils module utils \- change implementation of DNS Server IP and NTP Server IP update \([https\://github\.com/ansible\-collections/community\.general/pull/5804](https\://github\.com/ansible\-collections/community\.general/pull/5804)\)\.
|
||||
* ipa\_group \- allow to add and remove external users with the <code>external\_user</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/5897](https\://github\.com/ansible\-collections/community\.general/pull/5897)\)\.
|
||||
* iptables\_state \- minor refactoring within the module \([https\://github\.com/ansible\-collections/community\.general/pull/5844](https\://github\.com/ansible\-collections/community\.general/pull/5844)\)\.
|
||||
* one\_vm \- add a new <code>updateconf</code> option which implements the <code>one\.vm\.updateconf</code> API call \([https\://github\.com/ansible\-collections/community\.general/pull/5812](https\://github\.com/ansible\-collections/community\.general/pull/5812)\)\.
|
||||
* opkg \- refactored module to use <code>CmdRunner</code> for executing <code>opkg</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5718](https\://github\.com/ansible\-collections/community\.general/pull/5718)\)\.
|
||||
* redhat\_subscription \- adds <code>token</code> parameter for subscription\-manager authentication using Red Hat API token \([https\://github\.com/ansible\-collections/community\.general/pull/5725](https\://github\.com/ansible\-collections/community\.general/pull/5725)\)\.
|
||||
* snap \- minor refactor when executing module \([https\://github\.com/ansible\-collections/community\.general/pull/5773](https\://github\.com/ansible\-collections/community\.general/pull/5773)\)\.
|
||||
* snap\_alias \- refactored module to use <code>CmdRunner</code> to execute <code>snap</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5486](https\://github\.com/ansible\-collections/community\.general/pull/5486)\)\.
|
||||
* sudoers \- add <code>setenv</code> parameters to support passing environment variables via sudo\. \([https\://github\.com/ansible\-collections/community\.general/pull/5883](https\://github\.com/ansible\-collections/community\.general/pull/5883)\)
|
||||
|
||||
<a id="breaking-changes--porting-guide"></a>
|
||||
### Breaking Changes / Porting Guide
|
||||
|
||||
* ModuleHelper module utils \- when the module sets output variables named <code>msg</code>\, <code>exception</code>\, <code>output</code>\, <code>vars</code>\, or <code>changed</code>\, the actual output will prefix those names with <code>\_</code> \(underscore symbol\) only when they clash with output variables generated by ModuleHelper itself\, which only occurs when handling exceptions\. Please note that this breaking change does not require a new major release since before this release\, it was not possible to add such variables to the output [due to a bug](https\://github\.com/ansible\-collections/community\.general/pull/5755) \([https\://github\.com/ansible\-collections/community\.general/pull/5765](https\://github\.com/ansible\-collections/community\.general/pull/5765)\)\.
|
||||
|
||||
<a id="deprecated-features-1"></a>
|
||||
### Deprecated Features
|
||||
|
||||
* consul \- deprecate using parameters unused for <code>state\=absent</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5772](https\://github\.com/ansible\-collections/community\.general/pull/5772)\)\.
|
||||
* gitlab\_runner \- the default of the new option <code>access\_level\_on\_creation</code> will change from <code>false</code> to <code>true</code> in community\.general 7\.0\.0\. This will cause <code>access\_level</code> to be used during runner registration as well\, and not only during updates \([https\://github\.com/ansible\-collections/community\.general/pull/5908](https\://github\.com/ansible\-collections/community\.general/pull/5908)\)\.
|
||||
|
||||
<a id="bugfixes-12"></a>
|
||||
### Bugfixes
|
||||
|
||||
* ModuleHelper \- fix bug when adjusting the name of reserved output variables \([https\://github\.com/ansible\-collections/community\.general/pull/5755](https\://github\.com/ansible\-collections/community\.general/pull/5755)\)\.
|
||||
* alternatives \- support subcommands on Fedora 37\, which uses <code>follower</code> instead of <code>slave</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5794](https\://github\.com/ansible\-collections/community\.general/pull/5794)\)\.
|
||||
* bitwarden lookup plugin \- clarify what to do\, if the bitwarden vault is not unlocked \([https\://github\.com/ansible\-collections/community\.general/pull/5811](https\://github\.com/ansible\-collections/community\.general/pull/5811)\)\.
|
||||
* dig lookup plugin \- correctly handle DNSKEY record type\'s <code>algorithm</code> field \([https\://github\.com/ansible\-collections/community\.general/pull/5914](https\://github\.com/ansible\-collections/community\.general/pull/5914)\)\.
|
||||
* gem \- fix force parameter not being passed to gem command when uninstalling \([https\://github\.com/ansible\-collections/community\.general/pull/5822](https\://github\.com/ansible\-collections/community\.general/pull/5822)\)\.
|
||||
* gem \- fix hang due to interactive prompt for confirmation on specific version uninstall \([https\://github\.com/ansible\-collections/community\.general/pull/5751](https\://github\.com/ansible\-collections/community\.general/pull/5751)\)\.
|
||||
* gitlab\_deploy\_key \- also update <code>title</code> and not just <code>can\_push</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5888](https\://github\.com/ansible\-collections/community\.general/pull/5888)\)\.
|
||||
* keycloak\_user\_federation \- fixes federation creation issue\. When a new federation was created and at the same time a default / standard mapper was also changed / updated the creation process failed as a bad None set variable led to a bad malformed url request \([https\://github\.com/ansible\-collections/community\.general/pull/5750](https\://github\.com/ansible\-collections/community\.general/pull/5750)\)\.
|
||||
* keycloak\_user\_federation \- fixes idempotency detection issues\. In some cases the module could fail to properly detect already existing user federations because of a buggy seemingly superflous extra query parameter \([https\://github\.com/ansible\-collections/community\.general/pull/5732](https\://github\.com/ansible\-collections/community\.general/pull/5732)\)\.
|
||||
* loganalytics callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* logdna callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* logstash callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* nsupdate \- fix zone lookup\. The SOA record for an existing zone is returned as an answer RR and not as an authority RR \([https\://github\.com/ansible\-collections/community\.general/issues/5817](https\://github\.com/ansible\-collections/community\.general/issues/5817)\, [https\://github\.com/ansible\-collections/community\.general/pull/5818](https\://github\.com/ansible\-collections/community\.general/pull/5818)\)\.
|
||||
* proxmox\_disk \- fixed issue with read timeout on import action \([https\://github\.com/ansible\-collections/community\.general/pull/5803](https\://github\.com/ansible\-collections/community\.general/pull/5803)\)\.
|
||||
* redfish\_utils \- removed basic auth HTTP header when performing a GET on the service root resource and when performing a POST to the session collection \([https\://github\.com/ansible\-collections/community\.general/issues/5886](https\://github\.com/ansible\-collections/community\.general/issues/5886)\)\.
|
||||
* splunk callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* sumologic callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* syslog\_json callback plugin \- adjust type of callback to <code>notification</code>\, it was incorrectly classified as <code>aggregate</code> before \([https\://github\.com/ansible\-collections/community\.general/pull/5761](https\://github\.com/ansible\-collections/community\.general/pull/5761)\)\.
|
||||
* terraform \- fix <code>current</code> workspace never getting appended to the <code>all</code> key in the <code>workspace\_ctf</code> object \([https\://github\.com/ansible\-collections/community\.general/pull/5735](https\://github\.com/ansible\-collections/community\.general/pull/5735)\)\.
|
||||
* terraform \- fix <code>terraform init</code> failure when there are multiple workspaces on the remote backend and when <code>default</code> workspace is missing by setting <code>TF\_WORKSPACE</code> environmental variable to the value of <code>workspace</code> when used \([https\://github\.com/ansible\-collections/community\.general/pull/5735](https\://github\.com/ansible\-collections/community\.general/pull/5735)\)\.
|
||||
* terraform module \- disable ANSI escape sequences during validation phase \([https\://github\.com/ansible\-collections/community\.general/pull/5843](https\://github\.com/ansible\-collections/community\.general/pull/5843)\)\.
|
||||
* xml \- fixed a bug where empty <code>children</code> list would not be set \([https\://github\.com/ansible\-collections/community\.general/pull/5808](https\://github\.com/ansible\-collections/community\.general/pull/5808)\)\.
|
||||
|
||||
<a id="new-modules-2"></a>
|
||||
### New Modules
|
||||
|
||||
* ocapi\_command \- Manages Out\-Of\-Band controllers using Open Composable API \(OCAPI\)
|
||||
* ocapi\_info \- Manages Out\-Of\-Band controllers using Open Composable API \(OCAPI\)
|
||||
|
||||
<a id="v6-2-0"></a>
|
||||
## v6\.2\.0
|
||||
|
||||
<a id="release-summary-13"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-8"></a>
|
||||
### Minor Changes
|
||||
|
||||
* opkg \- allow installing a package in a certain version \([https\://github\.com/ansible\-collections/community\.general/pull/5688](https\://github\.com/ansible\-collections/community\.general/pull/5688)\)\.
|
||||
* proxmox \- added new module parameter <code>tags</code> for use with PVE 7\+ \([https\://github\.com/ansible\-collections/community\.general/pull/5714](https\://github\.com/ansible\-collections/community\.general/pull/5714)\)\.
|
||||
* puppet \- refactored module to use <code>CmdRunner</code> for executing <code>puppet</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5612](https\://github\.com/ansible\-collections/community\.general/pull/5612)\)\.
|
||||
* redhat\_subscription \- add a <code>server\_proxy\_scheme</code> parameter to configure the scheme for the proxy server \([https\://github\.com/ansible\-collections/community\.general/pull/5662](https\://github\.com/ansible\-collections/community\.general/pull/5662)\)\.
|
||||
* ssh\_config \- refactor code to module util to fix sanity check \([https\://github\.com/ansible\-collections/community\.general/pull/5720](https\://github\.com/ansible\-collections/community\.general/pull/5720)\)\.
|
||||
* sudoers \- adds <code>host</code> parameter for setting hostname restrictions in sudoers rules \([https\://github\.com/ansible\-collections/community\.general/issues/5702](https\://github\.com/ansible\-collections/community\.general/issues/5702)\)\.
|
||||
|
||||
<a id="deprecated-features-2"></a>
|
||||
### Deprecated Features
|
||||
|
||||
* manageiq\_policies \- deprecate <code>state\=list</code> in favour of using <code>community\.general\.manageiq\_policies\_info</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5721](https\://github\.com/ansible\-collections/community\.general/pull/5721)\)\.
|
||||
* rax \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_cbs \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_cbs\_attachments \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_cdb \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_cdb\_database \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_cdb\_user \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_clb \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_clb\_nodes \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_clb\_ssl \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_dns \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_dns\_record \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_facts \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_files \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_files\_objects \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_identity \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_keypair \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_meta \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_mon\_alarm \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_mon\_check \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_mon\_entity \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_mon\_notification \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_mon\_notification\_plan \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_network \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_queue \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_scaling\_group \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
* rax\_scaling\_policy \- module relies on deprecates library <code>pyrax</code>\. Unless maintainers step up to work on the module\, it will be marked as deprecated in community\.general 7\.0\.0 and removed in version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5733](https\://github\.com/ansible\-collections/community\.general/pull/5733)\)\.
|
||||
|
||||
<a id="bugfixes-13"></a>
|
||||
### Bugfixes
|
||||
|
||||
* ansible\_galaxy\_install \- set default to raise exception if command\'s return code is different from zero \([https\://github\.com/ansible\-collections/community\.general/pull/5680](https\://github\.com/ansible\-collections/community\.general/pull/5680)\)\.
|
||||
* ansible\_galaxy\_install \- try <code>C\.UTF\-8</code> and then fall back to <code>en\_US\.UTF\-8</code> before failing \([https\://github\.com/ansible\-collections/community\.general/pull/5680](https\://github\.com/ansible\-collections/community\.general/pull/5680)\)\.
|
||||
* gitlab\_group\_variables \- fix dropping variables accidentally when GitLab introduced new properties \([https\://github\.com/ansible\-collections/community\.general/pull/5667](https\://github\.com/ansible\-collections/community\.general/pull/5667)\)\.
|
||||
* gitlab\_project\_variables \- fix dropping variables accidentally when GitLab introduced new properties \([https\://github\.com/ansible\-collections/community\.general/pull/5667](https\://github\.com/ansible\-collections/community\.general/pull/5667)\)\.
|
||||
* lxc\_container \- fix the arguments of the lxc command which broke the creation and cloning of containers \([https\://github\.com/ansible\-collections/community\.general/issues/5578](https\://github\.com/ansible\-collections/community\.general/issues/5578)\)\.
|
||||
* opkg \- fix issue that <code>force\=reinstall</code> would not reinstall an existing package \([https\://github\.com/ansible\-collections/community\.general/pull/5705](https\://github\.com/ansible\-collections/community\.general/pull/5705)\)\.
|
||||
* proxmox\_disk \- fixed possible issues with redundant <code>vmid</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/5492](https\://github\.com/ansible\-collections/community\.general/issues/5492)\, [https\://github\.com/ansible\-collections/community\.general/pull/5672](https\://github\.com/ansible\-collections/community\.general/pull/5672)\)\.
|
||||
* proxmox\_nic \- fixed possible issues with redundant <code>vmid</code> parameter \([https\://github\.com/ansible\-collections/community\.general/issues/5492](https\://github\.com/ansible\-collections/community\.general/issues/5492)\, [https\://github\.com/ansible\-collections/community\.general/pull/5672](https\://github\.com/ansible\-collections/community\.general/pull/5672)\)\.
|
||||
* unixy callback plugin \- fix typo introduced when updating to use Ansible\'s configuration manager for handling options \([https\://github\.com/ansible\-collections/community\.general/issues/5600](https\://github\.com/ansible\-collections/community\.general/issues/5600)\)\.
|
||||
|
||||
<a id="v6-1-0"></a>
|
||||
## v6\.1\.0
|
||||
|
||||
<a id="release-summary-14"></a>
|
||||
### Release Summary
|
||||
|
||||
Regular bugfix and feature release\.
|
||||
|
||||
<a id="minor-changes-9"></a>
|
||||
### Minor Changes
|
||||
|
||||
* cmd\_runner module utils \- <code>cmd\_runner\_fmt\.as\_bool\(\)</code> can now take an extra parameter to format when value is false \([https\://github\.com/ansible\-collections/community\.general/pull/5647](https\://github\.com/ansible\-collections/community\.general/pull/5647)\)\.
|
||||
* gconftool2 \- refactor using <code>ModuleHelper</code> and <code>CmdRunner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5545](https\://github\.com/ansible\-collections/community\.general/pull/5545)\)\.
|
||||
* java\_certs \- add more detailed error output when extracting certificate from PKCS12 fails \([https\://github\.com/ansible\-collections/community\.general/pull/5550](https\://github\.com/ansible\-collections/community\.general/pull/5550)\)\.
|
||||
* jenkins\_plugin \- refactor code to module util to fix sanity check \([https\://github\.com/ansible\-collections/community\.general/pull/5565](https\://github\.com/ansible\-collections/community\.general/pull/5565)\)\.
|
||||
* lxd\_project \- refactored code out to module utils to clear sanity check \([https\://github\.com/ansible\-collections/community\.general/pull/5549](https\://github\.com/ansible\-collections/community\.general/pull/5549)\)\.
|
||||
* nmap inventory plugin \- add new options <code>udp\_scan</code>\, <code>icmp\_timestamp</code>\, and <code>dns\_resolve</code> for different types of scans \([https\://github\.com/ansible\-collections/community\.general/pull/5566](https\://github\.com/ansible\-collections/community\.general/pull/5566)\)\.
|
||||
* rax\_scaling\_group \- refactored out code to the <code>rax</code> module utils to clear the sanity check \([https\://github\.com/ansible\-collections/community\.general/pull/5563](https\://github\.com/ansible\-collections/community\.general/pull/5563)\)\.
|
||||
* redfish\_command \- add <code>PerformRequestedOperations</code> command to perform any operations necessary to continue the update flow \([https\://github\.com/ansible\-collections/community\.general/issues/4276](https\://github\.com/ansible\-collections/community\.general/issues/4276)\)\.
|
||||
* redfish\_command \- add <code>update\_apply\_time</code> to <code>SimpleUpdate</code> command \([https\://github\.com/ansible\-collections/community\.general/issues/3910](https\://github\.com/ansible\-collections/community\.general/issues/3910)\)\.
|
||||
* redfish\_command \- add <code>update\_status</code> to output of <code>SimpleUpdate</code> command to allow a user monitor the update in progress \([https\://github\.com/ansible\-collections/community\.general/issues/4276](https\://github\.com/ansible\-collections/community\.general/issues/4276)\)\.
|
||||
* redfish\_info \- add <code>GetUpdateStatus</code> command to check the progress of a previous update request \([https\://github\.com/ansible\-collections/community\.general/issues/4276](https\://github\.com/ansible\-collections/community\.general/issues/4276)\)\.
|
||||
* redfish\_utils module utils \- added PUT \(<code>put\_request\(\)</code>\) functionality \([https\://github\.com/ansible\-collections/community\.general/pull/5490](https\://github\.com/ansible\-collections/community\.general/pull/5490)\)\.
|
||||
* slack \- add option <code>prepend\_hash</code> which allows to control whether a <code>\#</code> is prepended to <code>channel\_id</code>\. The current behavior \(value <code>auto</code>\) is to prepend <code>\#</code> unless some specific prefixes are found\. That list of prefixes is incomplete\, and there does not seem to exist a documented condition on when exactly <code>\#</code> must not be prepended\. We recommend to explicitly set <code>prepend\_hash\=always</code> or <code>prepend\_hash\=never</code> to avoid any ambiguity \([https\://github\.com/ansible\-collections/community\.general/pull/5629](https\://github\.com/ansible\-collections/community\.general/pull/5629)\)\.
|
||||
* spotinst\_aws\_elastigroup \- add <code>elements</code> attribute when missing in <code>list</code> parameters \([https\://github\.com/ansible\-collections/community\.general/pull/5553](https\://github\.com/ansible\-collections/community\.general/pull/5553)\)\.
|
||||
* ssh\_config \- add <code>host\_key\_algorithms</code> option \([https\://github\.com/ansible\-collections/community\.general/pull/5605](https\://github\.com/ansible\-collections/community\.general/pull/5605)\)\.
|
||||
* udm\_share \- added <code>elements</code> attribute to <code>list</code> type parameters \([https\://github\.com/ansible\-collections/community\.general/pull/5557](https\://github\.com/ansible\-collections/community\.general/pull/5557)\)\.
|
||||
* udm\_user \- add <code>elements</code> attribute when missing in <code>list</code> parameters \([https\://github\.com/ansible\-collections/community\.general/pull/5559](https\://github\.com/ansible\-collections/community\.general/pull/5559)\)\.
|
||||
|
||||
<a id="deprecated-features-3"></a>
|
||||
### Deprecated Features
|
||||
|
||||
* The <code>sap</code> modules <code>sapcar\_extract</code>\, <code>sap\_task\_list\_execute</code>\, and <code>hana\_query</code>\, will be removed from this collection in community\.general 7\.0\.0 and replaced with redirects to <code>community\.sap\_libs</code>\. If you want to continue using these modules\, make sure to also install <code>community\.sap\_libs</code> \(it is part of the Ansible package\) \([https\://github\.com/ansible\-collections/community\.general/pull/5614](https\://github\.com/ansible\-collections/community\.general/pull/5614)\)\.
|
||||
|
||||
<a id="bugfixes-14"></a>
|
||||
### Bugfixes
|
||||
|
||||
* chroot connection plugin \- add <code>inventory\_hostname</code> to vars under <code>remote\_addr</code>\. This is needed for compatibility with ansible\-core 2\.13 \([https\://github\.com/ansible\-collections/community\.general/pull/5570](https\://github\.com/ansible\-collections/community\.general/pull/5570)\)\.
|
||||
* cmd\_runner module utils \- fixed bug when handling default cases in <code>cmd\_runner\_fmt\.as\_map\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5538](https\://github\.com/ansible\-collections/community\.general/pull/5538)\)\.
|
||||
* cmd\_runner module utils \- formatting arguments <code>cmd\_runner\_fmt\.as\_fixed\(\)</code> was expecting an non\-existing argument \([https\://github\.com/ansible\-collections/community\.general/pull/5538](https\://github\.com/ansible\-collections/community\.general/pull/5538)\)\.
|
||||
* keycloak\_client\_rolemapping \- calculate <code>proposed</code> and <code>after</code> return values properly \([https\://github\.com/ansible\-collections/community\.general/pull/5619](https\://github\.com/ansible\-collections/community\.general/pull/5619)\)\.
|
||||
* keycloak\_client\_rolemapping \- remove only listed mappings with <code>state\=absent</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5619](https\://github\.com/ansible\-collections/community\.general/pull/5619)\)\.
|
||||
* proxmox inventory plugin \- fix bug while templating when using templates for the <code>url</code>\, <code>user</code>\, <code>password</code>\, <code>token\_id</code>\, or <code>token\_secret</code> options \([https\://github\.com/ansible\-collections/community\.general/pull/5640](https\://github\.com/ansible\-collections/community\.general/pull/5640)\)\.
|
||||
* proxmox inventory plugin \- handle tags delimited by semicolon instead of comma\, which happens from Proxmox 7\.3 on \([https\://github\.com/ansible\-collections/community\.general/pull/5602](https\://github\.com/ansible\-collections/community\.general/pull/5602)\)\.
|
||||
* redhat\_subscription \- do not ignore <code>consumer\_name</code> and other variables if <code>activationkey</code> is specified \([https\://github\.com/ansible\-collections/community\.general/issues/3486](https\://github\.com/ansible\-collections/community\.general/issues/3486)\, [https\://github\.com/ansible\-collections/community\.general/pull/5627](https\://github\.com/ansible\-collections/community\.general/pull/5627)\)\.
|
||||
* redhat\_subscription \- do not pass arguments to <code>subscription\-manager register</code> for things already configured\; now a specified <code>rhsm\_baseurl</code> is properly set for subscription\-manager \([https\://github\.com/ansible\-collections/community\.general/pull/5583](https\://github\.com/ansible\-collections/community\.general/pull/5583)\)\.
|
||||
* unixy callback plugin \- fix plugin to work with ansible\-core 2\.14 by using Ansible\'s configuration manager for handling options \([https\://github\.com/ansible\-collections/community\.general/issues/5600](https\://github\.com/ansible\-collections/community\.general/issues/5600)\)\.
|
||||
* vdo \- now uses <code>yaml\.safe\_load\(\)</code> to parse command output instead of the deprecated <code>yaml\.load\(\)</code> which is potentially unsafe\. Using <code>yaml\.load\(\)</code> without explicitely setting a <code>Loader\=</code> is also an error in pyYAML 6\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5632](https\://github\.com/ansible\-collections/community\.general/pull/5632)\)\.
|
||||
* vmadm \- fix for index out of range error in <code>get\_vm\_uuid</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5628](https\://github\.com/ansible\-collections/community\.general/pull/5628)\)\.
|
||||
|
||||
<a id="new-modules-3"></a>
|
||||
### New Modules
|
||||
|
||||
* gitlab\_project\_badge \- Manage project badges on GitLab Server
|
||||
* keycloak\_clientsecret\_info \- Retrieve client secret via Keycloak API
|
||||
* keycloak\_clientsecret\_regenerate \- Regenerate Keycloak client secret via Keycloak API
|
||||
|
||||
<a id="v6-0-1"></a>
|
||||
## v6\.0\.1
|
||||
|
||||
<a id="release-summary-15"></a>
|
||||
### Release Summary
|
||||
|
||||
Bugfix release for Ansible 7\.0\.0\.
|
||||
|
||||
<a id="bugfixes-15"></a>
|
||||
### Bugfixes
|
||||
|
||||
* dependent lookup plugin \- avoid warning on deprecated parameter for <code>Templar\.template\(\)</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5543](https\://github\.com/ansible\-collections/community\.general/pull/5543)\)\.
|
||||
* jenkins\_build \- fix the logical flaw when deleting a Jenkins build \([https\://github\.com/ansible\-collections/community\.general/pull/5514](https\://github\.com/ansible\-collections/community\.general/pull/5514)\)\.
|
||||
* one\_vm \- avoid splitting labels that are <code>None</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5489](https\://github\.com/ansible\-collections/community\.general/pull/5489)\)\.
|
||||
* onepassword\_raw \- add missing parameter to plugin documentation \([https\://github\.com/ansible\-collections/community\.general/issues/5506](https\://github\.com/ansible\-collections/community\.general/issues/5506)\)\.
|
||||
* proxmox\_disk \- avoid duplicate <code>vmid</code> reference \([https\://github\.com/ansible\-collections/community\.general/issues/5492](https\://github\.com/ansible\-collections/community\.general/issues/5492)\, [https\://github\.com/ansible\-collections/community\.general/pull/5493](https\://github\.com/ansible\-collections/community\.general/pull/5493)\)\.
|
||||
|
||||
<a id="v6-0-0"></a>
|
||||
## v6\.0\.0
|
||||
|
||||
<a id="release-summary-16"></a>
|
||||
### Release Summary
|
||||
|
||||
New major release of community\.general with lots of bugfixes\, new features\, some removed deprecated features\, and some other breaking changes\. Please check the coresponding sections of the changelog for more details\.
|
||||
|
||||
<a id="major-changes"></a>
|
||||
### Major Changes
|
||||
|
||||
* The internal structure of the collection was changed for modules and action plugins\. These no longer live in a directory hierarchy ordered by topic\, but instead are now all in a single \(flat\) directory\. This has no impact on users <em>assuming they did not use internal FQCNs</em>\. These will still work\, but result in deprecation warnings\. They were never officially supported and thus the redirects are kept as a courtsey\, and this is not labelled as a breaking change\. Note that for example the Ansible VScode plugin started recommending these internal names\. If you followed its recommendation\, you will now have to change back to the short names to avoid deprecation warnings\, and potential errors in the future as these redirects will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5461](https\://github\.com/ansible\-collections/community\.general/pull/5461)\)\.
|
||||
* newrelic\_deployment \- removed New Relic v1 API\, added support for v2 API \([https\://github\.com/ansible\-collections/community\.general/pull/5341](https\://github\.com/ansible\-collections/community\.general/pull/5341)\)\.
|
||||
|
||||
<a id="minor-changes-10"></a>
|
||||
### Minor Changes
|
||||
|
||||
* Added MIT license as <code>LICENSES/MIT\.txt</code> for tests/unit/plugins/modules/packaging/language/test\_gem\.py \([https\://github\.com/ansible\-collections/community\.general/pull/5065](https\://github\.com/ansible\-collections/community\.general/pull/5065)\)\.
|
||||
* All software licenses are now in the <code>LICENSES/</code> directory of the collection root \([https\://github\.com/ansible\-collections/community\.general/pull/5065](https\://github\.com/ansible\-collections/community\.general/pull/5065)\, [https\://github\.com/ansible\-collections/community\.general/pull/5079](https\://github\.com/ansible\-collections/community\.general/pull/5079)\, [https\://github\.com/ansible\-collections/community\.general/pull/5080](https\://github\.com/ansible\-collections/community\.general/pull/5080)\, [https\://github\.com/ansible\-collections/community\.general/pull/5083](https\://github\.com/ansible\-collections/community\.general/pull/5083)\, [https\://github\.com/ansible\-collections/community\.general/pull/5087](https\://github\.com/ansible\-collections/community\.general/pull/5087)\, [https\://github\.com/ansible\-collections/community\.general/pull/5095](https\://github\.com/ansible\-collections/community\.general/pull/5095)\, [https\://github\.com/ansible\-collections/community\.general/pull/5098](https\://github\.com/ansible\-collections/community\.general/pull/5098)\, [https\://github\.com/ansible\-collections/community\.general/pull/5106](https\://github\.com/ansible\-collections/community\.general/pull/5106)\)\.
|
||||
* ModuleHelper module utils \- added property <code>verbosity</code> to base class \([https\://github\.com/ansible\-collections/community\.general/pull/5035](https\://github\.com/ansible\-collections/community\.general/pull/5035)\)\.
|
||||
* ModuleHelper module utils \- improved <code>ModuleHelperException</code>\, using <code>to\_native\(\)</code> for the exception message \([https\://github\.com/ansible\-collections/community\.general/pull/4755](https\://github\.com/ansible\-collections/community\.general/pull/4755)\)\.
|
||||
* The collection repository conforms to the [REUSE specification](https\://reuse\.software/spec/) except for the changelog fragments \([https\://github\.com/ansible\-collections/community\.general/pull/5138](https\://github\.com/ansible\-collections/community\.general/pull/5138)\)\.
|
||||
* ali\_instance \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5240](https\://github\.com/ansible\-collections/community\.general/pull/5240)\)\.
|
||||
* ali\_instance\_info \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5240](https\://github\.com/ansible\-collections/community\.general/pull/5240)\)\.
|
||||
* alternatives \- add <code>state\=absent</code> to be able to remove an alternative \([https\://github\.com/ansible\-collections/community\.general/pull/4654](https\://github\.com/ansible\-collections/community\.general/pull/4654)\)\.
|
||||
* alternatives \- add <code>subcommands</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/4654](https\://github\.com/ansible\-collections/community\.general/pull/4654)\)\.
|
||||
* ansible\_galaxy\_install \- minor refactoring using latest <code>ModuleHelper</code> updates \([https\://github\.com/ansible\-collections/community\.general/pull/4752](https\://github\.com/ansible\-collections/community\.general/pull/4752)\)\.
|
||||
* ansible\_galaxy\_install \- refactored module to use <code>CmdRunner</code> to execute <code>ansible\-galaxy</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5477](https\://github\.com/ansible\-collections/community\.general/pull/5477)\)\.
|
||||
* apk \- add <code>world</code> parameter for supporting a custom world file \([https\://github\.com/ansible\-collections/community\.general/pull/4976](https\://github\.com/ansible\-collections/community\.general/pull/4976)\)\.
|
||||
* bitwarden lookup plugin \- add option <code>search</code> to search for other attributes than name \([https\://github\.com/ansible\-collections/community\.general/pull/5297](https\://github\.com/ansible\-collections/community\.general/pull/5297)\)\.
|
||||
* cartesian lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* cmd\_runner module util \- added parameters <code>check\_mode\_skip</code> and <code>check\_mode\_return</code> to <code>CmdRunner\.context\(\)</code>\, so that the command is not executed when <code>check\_mode\=True</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4736](https\://github\.com/ansible\-collections/community\.general/pull/4736)\)\.
|
||||
* cmd\_runner module utils \- add <code>\_\_call\_\_</code> method to invoke context \([https\://github\.com/ansible\-collections/community\.general/pull/4791](https\://github\.com/ansible\-collections/community\.general/pull/4791)\)\.
|
||||
* consul \- adds <code>ttl</code> parameter for session \([https\://github\.com/ansible\-collections/community\.general/pull/4996](https\://github\.com/ansible\-collections/community\.general/pull/4996)\)\.
|
||||
* consul \- minor refactoring \([https\://github\.com/ansible\-collections/community\.general/pull/5367](https\://github\.com/ansible\-collections/community\.general/pull/5367)\)\.
|
||||
* consul\_session \- adds <code>token</code> parameter for session \([https\://github\.com/ansible\-collections/community\.general/pull/5193](https\://github\.com/ansible\-collections/community\.general/pull/5193)\)\.
|
||||
* cpanm \- refactored module to use <code>CmdRunner</code> to execute <code>cpanm</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5485](https\://github\.com/ansible\-collections/community\.general/pull/5485)\)\.
|
||||
* cpanm \- using <code>do\_raise\(\)</code> to raise exceptions in <code>ModuleHelper</code> derived modules \([https\://github\.com/ansible\-collections/community\.general/pull/4674](https\://github\.com/ansible\-collections/community\.general/pull/4674)\)\.
|
||||
* credstash lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* dependent lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* dig lookup plugin \- add option <code>fail\_on\_error</code> to allow stopping execution on lookup failures \([https\://github\.com/ansible\-collections/community\.general/pull/4973](https\://github\.com/ansible\-collections/community\.general/pull/4973)\)\.
|
||||
* dig lookup plugin \- start using Ansible\'s configuration manager to parse options\. All documented options can now also be passed as lookup parameters \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* dnstxt lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* filetree lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* flattened lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* gitlab module util \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_branch \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_deploy\_key \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_group \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_group\_members \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_group\_variable \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_hook \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_hook \- minor refactoring \([https\://github\.com/ansible\-collections/community\.general/pull/5271](https\://github\.com/ansible\-collections/community\.general/pull/5271)\)\.
|
||||
* gitlab\_project \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_project\_members \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_project\_variable \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_protected\_branch \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_runner \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* gitlab\_user \- minor refactor when checking for installed dependency \([https\://github\.com/ansible\-collections/community\.general/pull/5259](https\://github\.com/ansible\-collections/community\.general/pull/5259)\)\.
|
||||
* hiera lookup plugin \- start using Ansible\'s configuration manager to parse options\. The Hiera executable and config file can now also be passed as lookup parameters \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* homebrew\, homebrew\_tap \- added Homebrew on Linux path to defaults \([https\://github\.com/ansible\-collections/community\.general/pull/5241](https\://github\.com/ansible\-collections/community\.general/pull/5241)\)\.
|
||||
* hponcfg \- refactored module to use <code>CmdRunner</code> to execute <code>hponcfg</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5483](https\://github\.com/ansible\-collections/community\.general/pull/5483)\)\.
|
||||
* keycloak\_\* modules \- add <code>http\_agent</code> parameter with default value <code>Ansible</code> \([https\://github\.com/ansible\-collections/community\.general/issues/5023](https\://github\.com/ansible\-collections/community\.general/issues/5023)\)\.
|
||||
* keyring lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* lastpass \- use config manager for handling plugin options \([https\://github\.com/ansible\-collections/community\.general/pull/5022](https\://github\.com/ansible\-collections/community\.general/pull/5022)\)\.
|
||||
* ldap\_attrs \- allow for DNs to have <code>\{x\}</code> prefix on first RDN \([https\://github\.com/ansible\-collections/community\.general/issues/977](https\://github\.com/ansible\-collections/community\.general/issues/977)\, [https\://github\.com/ansible\-collections/community\.general/pull/5450](https\://github\.com/ansible\-collections/community\.general/pull/5450)\)\.
|
||||
* linode inventory plugin \- simplify option handling \([https\://github\.com/ansible\-collections/community\.general/pull/5438](https\://github\.com/ansible\-collections/community\.general/pull/5438)\)\.
|
||||
* listen\_ports\_facts \- add new <code>include\_non\_listening</code> option which adds <code>\-a</code> option to <code>netstat</code> and <code>ss</code>\. This shows both listening and non\-listening \(for TCP this means established connections\) sockets\, and returns <code>state</code> and <code>foreign\_address</code> \([https\://github\.com/ansible\-collections/community\.general/issues/4762](https\://github\.com/ansible\-collections/community\.general/issues/4762)\, [https\://github\.com/ansible\-collections/community\.general/pull/4953](https\://github\.com/ansible\-collections/community\.general/pull/4953)\)\.
|
||||
* lmdb\_kv lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* lxc\_container \- minor refactoring \([https\://github\.com/ansible\-collections/community\.general/pull/5358](https\://github\.com/ansible\-collections/community\.general/pull/5358)\)\.
|
||||
* machinectl become plugin \- can now be used with a password from another user than root\, if a polkit rule is present \([https\://github\.com/ansible\-collections/community\.general/pull/4849](https\://github\.com/ansible\-collections/community\.general/pull/4849)\)\.
|
||||
* machinectl become plugin \- combine the success command when building the become command to be consistent with other become plugins \([https\://github\.com/ansible\-collections/community\.general/pull/5287](https\://github\.com/ansible\-collections/community\.general/pull/5287)\)\.
|
||||
* manifold lookup plugin \- start using Ansible\'s configuration manager to parse options \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* maven\_artifact \- add a new <code>unredirected\_headers</code> option that can be used with ansible\-core 2\.12 and above\. The default value is to not use <code>Authorization</code> and <code>Cookie</code> headers on redirects for security reasons\. With ansible\-core 2\.11\, all headers are still passed on for redirects \([https\://github\.com/ansible\-collections/community\.general/pull/4812](https\://github\.com/ansible\-collections/community\.general/pull/4812)\)\.
|
||||
* mksysb \- refactored module to use <code>CmdRunner</code> to execute <code>mksysb</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5484](https\://github\.com/ansible\-collections/community\.general/pull/5484)\)\.
|
||||
* mksysb \- using <code>do\_raise\(\)</code> to raise exceptions in <code>ModuleHelper</code> derived modules \([https\://github\.com/ansible\-collections/community\.general/pull/4674](https\://github\.com/ansible\-collections/community\.general/pull/4674)\)\.
|
||||
* nagios \- minor refactoring on parameter validation for different actions \([https\://github\.com/ansible\-collections/community\.general/pull/5239](https\://github\.com/ansible\-collections/community\.general/pull/5239)\)\.
|
||||
* netcup\_dnsapi \- add <code>timeout</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/5301](https\://github\.com/ansible\-collections/community\.general/pull/5301)\)\.
|
||||
* nmcli \- add <code>transport\_mode</code> configuration for Infiniband devices \([https\://github\.com/ansible\-collections/community\.general/pull/5361](https\://github\.com/ansible\-collections/community\.general/pull/5361)\)\.
|
||||
* nmcli \- add bond option <code>xmit\_hash\_policy</code> to bond options \([https\://github\.com/ansible\-collections/community\.general/issues/5148](https\://github\.com/ansible\-collections/community\.general/issues/5148)\)\.
|
||||
* nmcli \- adds <code>vpn</code> type and parameter for supporting VPN with service type L2TP and PPTP \([https\://github\.com/ansible\-collections/community\.general/pull/4746](https\://github\.com/ansible\-collections/community\.general/pull/4746)\)\.
|
||||
* nmcli \- honor IP options for VPNs \([https\://github\.com/ansible\-collections/community\.general/pull/5228](https\://github\.com/ansible\-collections/community\.general/pull/5228)\)\.
|
||||
* onepassword \- support version 2 of the OnePassword CLI \([https\://github\.com/ansible\-collections/community\.general/pull/4728](https\://github\.com/ansible\-collections/community\.general/pull/4728)\)
|
||||
* opentelemetry callback plugin \- allow configuring opentelementry callback via config file \([https\://github\.com/ansible\-collections/community\.general/pull/4916](https\://github\.com/ansible\-collections/community\.general/pull/4916)\)\.
|
||||
* opentelemetry callback plugin \- send logs\. This can be disabled by setting <code>disable\_logs\=false</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4175](https\://github\.com/ansible\-collections/community\.general/pull/4175)\)\.
|
||||
* pacman \- added parameters <code>reason</code> and <code>reason\_for</code> to set/change the install reason of packages \([https\://github\.com/ansible\-collections/community\.general/pull/4956](https\://github\.com/ansible\-collections/community\.general/pull/4956)\)\.
|
||||
* passwordstore lookup plugin \- allow options to be passed lookup options instead of being part of the term strings \([https\://github\.com/ansible\-collections/community\.general/pull/5444](https\://github\.com/ansible\-collections/community\.general/pull/5444)\)\.
|
||||
* passwordstore lookup plugin \- allow using alternative password managers by detecting wrapper scripts\, allow explicit configuration of pass and gopass backends \([https\://github\.com/ansible\-collections/community\.general/issues/4766](https\://github\.com/ansible\-collections/community\.general/issues/4766)\)\.
|
||||
* passwordstore lookup plugin \- improve error messages to include stderr \([https\://github\.com/ansible\-collections/community\.general/pull/5436](https\://github\.com/ansible\-collections/community\.general/pull/5436)\)
|
||||
* pipx \- added state <code>latest</code> to the module \([https\://github\.com/ansible\-collections/community\.general/pull/5105](https\://github\.com/ansible\-collections/community\.general/pull/5105)\)\.
|
||||
* pipx \- changed implementation to use <code>cmd\_runner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5085](https\://github\.com/ansible\-collections/community\.general/pull/5085)\)\.
|
||||
* pipx \- module fails faster when <code>name</code> is missing for states <code>upgrade</code> and <code>reinstall</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5100](https\://github\.com/ansible\-collections/community\.general/pull/5100)\)\.
|
||||
* pipx \- using <code>do\_raise\(\)</code> to raise exceptions in <code>ModuleHelper</code> derived modules \([https\://github\.com/ansible\-collections/community\.general/pull/4674](https\://github\.com/ansible\-collections/community\.general/pull/4674)\)\.
|
||||
* pipx module utils \- created new module util <code>pipx</code> providing a <code>cmd\_runner</code> specific for the <code>pipx</code> module \([https\://github\.com/ansible\-collections/community\.general/pull/5085](https\://github\.com/ansible\-collections/community\.general/pull/5085)\)\.
|
||||
* portage \- add knobs for Portage\'s <code>\-\-backtrack</code> and <code>\-\-with\-bdeps</code> options \([https\://github\.com/ansible\-collections/community\.general/pull/5349](https\://github\.com/ansible\-collections/community\.general/pull/5349)\)\.
|
||||
* portage \- use Portage\'s python module instead of calling gentoolkit\-provided program in shell \([https\://github\.com/ansible\-collections/community\.general/pull/5349](https\://github\.com/ansible\-collections/community\.general/pull/5349)\)\.
|
||||
* proxmox inventory plugin \- added new flag <code>qemu\_extended\_statuses</code> and new groups <code>\<group\_prefix\>prelaunch</code>\, <code>\<group\_prefix\>paused</code>\. They will be populated only when <code>want\_facts\=true</code>\, <code>qemu\_extended\_statuses\=true</code> and only for <code>QEMU</code> machines \([https\://github\.com/ansible\-collections/community\.general/pull/4723](https\://github\.com/ansible\-collections/community\.general/pull/4723)\)\.
|
||||
* proxmox inventory plugin \- simplify option handling code \([https\://github\.com/ansible\-collections/community\.general/pull/5437](https\://github\.com/ansible\-collections/community\.general/pull/5437)\)\.
|
||||
* proxmox module utils\, the proxmox\* modules \- add <code>api\_task\_ok</code> helper to standardize API task status checks across all proxmox modules \([https\://github\.com/ansible\-collections/community\.general/pull/5274](https\://github\.com/ansible\-collections/community\.general/pull/5274)\)\.
|
||||
* proxmox\_kvm \- allow <code>agent</code> argument to be a string \([https\://github\.com/ansible\-collections/community\.general/pull/5107](https\://github\.com/ansible\-collections/community\.general/pull/5107)\)\.
|
||||
* proxmox\_snap \- add <code>unbind</code> param to support snapshotting containers with configured mountpoints \([https\://github\.com/ansible\-collections/community\.general/pull/5274](https\://github\.com/ansible\-collections/community\.general/pull/5274)\)\.
|
||||
* puppet \- adds <code>confdir</code> parameter to configure a custom confir location \([https\://github\.com/ansible\-collections/community\.general/pull/4740](https\://github\.com/ansible\-collections/community\.general/pull/4740)\)\.
|
||||
* redfish \- added new command GetVirtualMedia\, VirtualMediaInsert and VirtualMediaEject to Systems category due to Redfish spec changes the virtualMedia resource location from Manager to System \([https\://github\.com/ansible\-collections/community\.general/pull/5124](https\://github\.com/ansible\-collections/community\.general/pull/5124)\)\.
|
||||
* redfish\_config \- add <code>SetSessionService</code> to set default session timeout policy \([https\://github\.com/ansible\-collections/community\.general/issues/5008](https\://github\.com/ansible\-collections/community\.general/issues/5008)\)\.
|
||||
* redfish\_info \- add <code>GetManagerInventory</code> to report list of Manager inventory information \([https\://github\.com/ansible\-collections/community\.general/issues/4899](https\://github\.com/ansible\-collections/community\.general/issues/4899)\)\.
|
||||
* seport \- added new argument <code>local</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5203](https\://github\.com/ansible\-collections/community\.general/pull/5203)\)
|
||||
* snap \- using <code>do\_raise\(\)</code> to raise exceptions in <code>ModuleHelper</code> derived modules \([https\://github\.com/ansible\-collections/community\.general/pull/4674](https\://github\.com/ansible\-collections/community\.general/pull/4674)\)\.
|
||||
* sudoers \- will attempt to validate the proposed sudoers rule using visudo if available\, optionally skipped\, or required \([https\://github\.com/ansible\-collections/community\.general/pull/4794](https\://github\.com/ansible\-collections/community\.general/pull/4794)\, [https\://github\.com/ansible\-collections/community\.general/issues/4745](https\://github\.com/ansible\-collections/community\.general/issues/4745)\)\.
|
||||
* terraform \- adds capability to handle complex variable structures for <code>variables</code> parameter in the module\. This must be enabled with the new <code>complex\_vars</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/4797](https\://github\.com/ansible\-collections/community\.general/pull/4797)\)\.
|
||||
* terraform \- run <code>terraform init</code> with <code>\-no\-color</code> not to mess up the stdout of the task \([https\://github\.com/ansible\-collections/community\.general/pull/5147](https\://github\.com/ansible\-collections/community\.general/pull/5147)\)\.
|
||||
* wdc\_redfish\_command \- add <code>IndicatorLedOn</code> and <code>IndicatorLedOff</code> commands for <code>Chassis</code> category \([https\://github\.com/ansible\-collections/community\.general/pull/5059](https\://github\.com/ansible\-collections/community\.general/pull/5059)\)\.
|
||||
* wdc\_redfish\_command \- add <code>PowerModeLow</code> and <code>PowerModeNormal</code> commands for <code>Chassis</code> category \([https\://github\.com/ansible\-collections/community\.general/pull/5145](https\://github\.com/ansible\-collections/community\.general/pull/5145)\)\.
|
||||
* xfconf \- add <code>stdout</code>\, <code>stderr</code> and <code>cmd</code> to the module results \([https\://github\.com/ansible\-collections/community\.general/pull/5037](https\://github\.com/ansible\-collections/community\.general/pull/5037)\)\.
|
||||
* xfconf \- changed implementation to use <code>cmd\_runner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4776](https\://github\.com/ansible\-collections/community\.general/pull/4776)\)\.
|
||||
* xfconf \- use <code>do\_raise\(\)</code> instead of defining custom exception class \([https\://github\.com/ansible\-collections/community\.general/pull/4975](https\://github\.com/ansible\-collections/community\.general/pull/4975)\)\.
|
||||
* xfconf \- using <code>do\_raise\(\)</code> to raise exceptions in <code>ModuleHelper</code> derived modules \([https\://github\.com/ansible\-collections/community\.general/pull/4674](https\://github\.com/ansible\-collections/community\.general/pull/4674)\)\.
|
||||
* xfconf module utils \- created new module util <code>xfconf</code> providing a <code>cmd\_runner</code> specific for <code>xfconf</code> modules \([https\://github\.com/ansible\-collections/community\.general/pull/4776](https\://github\.com/ansible\-collections/community\.general/pull/4776)\)\.
|
||||
* xfconf\_info \- changed implementation to use <code>cmd\_runner</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4776](https\://github\.com/ansible\-collections/community\.general/pull/4776)\)\.
|
||||
* xfconf\_info \- use <code>do\_raise\(\)</code> instead of defining custom exception class \([https\://github\.com/ansible\-collections/community\.general/pull/4975](https\://github\.com/ansible\-collections/community\.general/pull/4975)\)\.
|
||||
* znode \- possibility to use ZooKeeper ACL authentication \([https\://github\.com/ansible\-collections/community\.general/pull/5306](https\://github\.com/ansible\-collections/community\.general/pull/5306)\)\.
|
||||
|
||||
<a id="breaking-changes--porting-guide-1"></a>
|
||||
### Breaking Changes / Porting Guide
|
||||
|
||||
* newrelic\_deployment \- <code>revision</code> is required for v2 API \([https\://github\.com/ansible\-collections/community\.general/pull/5341](https\://github\.com/ansible\-collections/community\.general/pull/5341)\)\.
|
||||
* scaleway\_container\_registry\_info \- no longer replace <code>secret\_environment\_variables</code> in the output by <code>SENSITIVE\_VALUE</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5497](https\://github\.com/ansible\-collections/community\.general/pull/5497)\)\.
|
||||
|
||||
<a id="deprecated-features-4"></a>
|
||||
### Deprecated Features
|
||||
|
||||
* ArgFormat module utils \- deprecated along <code>CmdMixin</code>\, in favor of the <code>cmd\_runner\_fmt</code> module util \([https\://github\.com/ansible\-collections/community\.general/pull/5370](https\://github\.com/ansible\-collections/community\.general/pull/5370)\)\.
|
||||
* CmdMixin module utils \- deprecated in favor of the <code>CmdRunner</code> module util \([https\://github\.com/ansible\-collections/community\.general/pull/5370](https\://github\.com/ansible\-collections/community\.general/pull/5370)\)\.
|
||||
* CmdModuleHelper module utils \- deprecated in favor of the <code>CmdRunner</code> module util \([https\://github\.com/ansible\-collections/community\.general/pull/5370](https\://github\.com/ansible\-collections/community\.general/pull/5370)\)\.
|
||||
* CmdStateModuleHelper module utils \- deprecated in favor of the <code>CmdRunner</code> module util \([https\://github\.com/ansible\-collections/community\.general/pull/5370](https\://github\.com/ansible\-collections/community\.general/pull/5370)\)\.
|
||||
* cmd\_runner module utils \- deprecated <code>fmt</code> in favour of <code>cmd\_runner\_fmt</code> as the parameter format object \([https\://github\.com/ansible\-collections/community\.general/pull/4777](https\://github\.com/ansible\-collections/community\.general/pull/4777)\)\.
|
||||
* django\_manage \- support for Django releases older than 4\.1 has been deprecated and will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5400](https\://github\.com/ansible\-collections/community\.general/pull/5400)\)\.
|
||||
* django\_manage \- support for the commands <code>cleanup</code>\, <code>syncdb</code> and <code>validate</code> that have been deprecated in Django long time ago will be removed in community\.general 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5400](https\://github\.com/ansible\-collections/community\.general/pull/5400)\)\.
|
||||
* django\_manage \- the behavior of \"creating the virtual environment when missing\" is being deprecated and will be removed in community\.general version 9\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5405](https\://github\.com/ansible\-collections/community\.general/pull/5405)\)\.
|
||||
* gconftool2 \- deprecates <code>state\=get</code> in favor of using the module <code>gconftool2\_info</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4778](https\://github\.com/ansible\-collections/community\.general/pull/4778)\)\.
|
||||
* lxc\_container \- the module will no longer make any effort to support Python 2 \([https\://github\.com/ansible\-collections/community\.general/pull/5304](https\://github\.com/ansible\-collections/community\.general/pull/5304)\)\.
|
||||
* newrelic\_deployment \- <code>appname</code> and <code>environment</code> are no longer valid options in the v2 API\. They will be removed in community\.general 7\.0\.0 \([https\://github\.com/ansible\-collections/community\.general/pull/5341](https\://github\.com/ansible\-collections/community\.general/pull/5341)\)\.
|
||||
* proxmox \- deprecated the current <code>unprivileged</code> default value\, will be changed to <code>true</code> in community\.general 7\.0\.0 \([https\://github\.com/pull/5224](https\://github\.com/pull/5224)\)\.
|
||||
* xfconf \- deprecated parameter <code>disable\_facts</code>\, as since version 4\.0\.0 it only allows value <code>true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4520](https\://github\.com/ansible\-collections/community\.general/pull/4520)\)\.
|
||||
|
||||
<a id="removed-features-previously-deprecated"></a>
|
||||
### Removed Features \(previously deprecated\)
|
||||
|
||||
* bitbucket\* modules \- <code>username</code> is no longer an alias of <code>workspace</code>\, but of <code>user</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* gem \- the default of the <code>norc</code> option changed from <code>false</code> to <code>true</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* gitlab\_group\_members \- <code>gitlab\_group</code> must now always contain the full path\, and no longer just the name or path \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* keycloak\_authentication \- the return value <code>flow</code> has been removed\. Use <code>end\_state</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* keycloak\_group \- the return value <code>group</code> has been removed\. Use <code>end\_state</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* lxd\_container \- the default of the <code>ignore\_volatile\_options</code> option changed from <code>true</code> to <code>false</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* mail callback plugin \- the <code>sender</code> option is now required \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* module\_helper module utils \- remove the <code>VarDict</code> attribute from <code>ModuleHelper</code>\. Import <code>VarDict</code> from <code>ansible\_collections\.community\.general\.plugins\.module\_utils\.mh\.mixins\.vars</code> instead \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* proxmox inventory plugin \- the default of the <code>want\_proxmox\_nodes\_ansible\_host</code> option changed from <code>true</code> to <code>false</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
* vmadm \- the <code>debug</code> option has been removed\. It was not used anyway \([https\://github\.com/ansible\-collections/community\.general/pull/5326](https\://github\.com/ansible\-collections/community\.general/pull/5326)\)\.
|
||||
|
||||
<a id="bugfixes-16"></a>
|
||||
### Bugfixes
|
||||
|
||||
* Include <code>PSF\-license\.txt</code> file for <code>plugins/module\_utils/\_mount\.py</code>\.
|
||||
* Include <code>simplified\_bsd\.txt</code> license file for various module utils\, the <code>lxca\_common</code> docs fragment\, and the <code>utm\_utils</code> unit tests\.
|
||||
* alternatives \- do not set the priority if the priority was not set by the user \([https\://github\.com/ansible\-collections/community\.general/pull/4810](https\://github\.com/ansible\-collections/community\.general/pull/4810)\)\.
|
||||
* alternatives \- only pass subcommands when they are specified as module arguments \([https\://github\.com/ansible\-collections/community\.general/issues/4803](https\://github\.com/ansible\-collections/community\.general/issues/4803)\, [https\://github\.com/ansible\-collections/community\.general/issues/4804](https\://github\.com/ansible\-collections/community\.general/issues/4804)\, [https\://github\.com/ansible\-collections/community\.general/pull/4836](https\://github\.com/ansible\-collections/community\.general/pull/4836)\)\.
|
||||
* alternatives \- when <code>subcommands</code> is specified\, <code>link</code> must be given for every subcommand\. This was already mentioned in the documentation\, but not enforced by the code \([https\://github\.com/ansible\-collections/community\.general/pull/4836](https\://github\.com/ansible\-collections/community\.general/pull/4836)\)\.
|
||||
* apache2\_mod\_proxy \- avoid crash when reporting inability to parse balancer\_member\_page HTML caused by using an undefined variable in the error message \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* archive \- avoid crash when <code>lzma</code> is not present and <code>format</code> is not <code>xz</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5393](https\://github\.com/ansible\-collections/community\.general/pull/5393)\)\.
|
||||
* cmd\_runner module utils \- fix bug caused by using the <code>command</code> variable instead of <code>self\.command</code> when looking for binary path \([https\://github\.com/ansible\-collections/community\.general/pull/4903](https\://github\.com/ansible\-collections/community\.general/pull/4903)\)\.
|
||||
* consul \- fixed bug introduced in PR 4590 \([https\://github\.com/ansible\-collections/community\.general/issues/4680](https\://github\.com/ansible\-collections/community\.general/issues/4680)\)\.
|
||||
* credstash lookup plugin \- pass plugin options to credstash for all terms\, not just for the first \([https\://github\.com/ansible\-collections/community\.general/pull/5440](https\://github\.com/ansible\-collections/community\.general/pull/5440)\)\.
|
||||
* dig lookup plugin \- add option to return empty result without empty strings\, and return empty list instead of <code>NXDOMAIN</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5439](https\://github\.com/ansible\-collections/community\.general/pull/5439)\, [https\://github\.com/ansible\-collections/community\.general/issues/5428](https\://github\.com/ansible\-collections/community\.general/issues/5428)\)\.
|
||||
* dig lookup plugin \- fix evaluation of falsy values for boolean parameters <code>fail\_on\_error</code> and <code>retry\_servfail</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5129](https\://github\.com/ansible\-collections/community\.general/pull/5129)\)\.
|
||||
* dnsimple\_info \- correctly report missing library as <code>requests</code> and not <code>another\_library</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* dnstxt lookup plugin \- add option to return empty result without empty strings\, and return empty list instead of <code>NXDOMAIN</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5457](https\://github\.com/ansible\-collections/community\.general/pull/5457)\, [https\://github\.com/ansible\-collections/community\.general/issues/5428](https\://github\.com/ansible\-collections/community\.general/issues/5428)\)\.
|
||||
* dsv lookup plugin \- do not ignore the <code>tld</code> parameter \([https\://github\.com/ansible\-collections/community\.general/pull/4911](https\://github\.com/ansible\-collections/community\.general/pull/4911)\)\.
|
||||
* filesystem \- handle <code>fatresize \-\-info</code> output lines without <code>\:</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4700](https\://github\.com/ansible\-collections/community\.general/pull/4700)\)\.
|
||||
* filesystem \- improve error messages when output cannot be parsed by including newlines in escaped form \([https\://github\.com/ansible\-collections/community\.general/pull/4700](https\://github\.com/ansible\-collections/community\.general/pull/4700)\)\.
|
||||
* funcd connection plugin \- fix signature of <code>exec\_command</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* ini\_file \- minor refactor fixing a python lint error \([https\://github\.com/ansible\-collections/community\.general/pull/5307](https\://github\.com/ansible\-collections/community\.general/pull/5307)\)\.
|
||||
* iso\_create \- the module somtimes failed to add folders for Joliet and UDF formats \([https\://github\.com/ansible\-collections/community\.general/issues/5275](https\://github\.com/ansible\-collections/community\.general/issues/5275)\)\.
|
||||
* keycloak\_realm \- fix default groups and roles \([https\://github\.com/ansible\-collections/community\.general/issues/4241](https\://github\.com/ansible\-collections/community\.general/issues/4241)\)\.
|
||||
* keyring\_info \- fix the result from the keyring library never getting returned \([https\://github\.com/ansible\-collections/community\.general/pull/4964](https\://github\.com/ansible\-collections/community\.general/pull/4964)\)\.
|
||||
* ldap\_attrs \- fix bug which caused a <code>Bad search filter</code> error\. The error was occuring when the ldap attribute value contained special characters such as <code>\(</code> or <code>\*</code> \([https\://github\.com/ansible\-collections/community\.general/issues/5434](https\://github\.com/ansible\-collections/community\.general/issues/5434)\, [https\://github\.com/ansible\-collections/community\.general/pull/5435](https\://github\.com/ansible\-collections/community\.general/pull/5435)\)\.
|
||||
* ldap\_attrs \- fix ordering issue by ignoring the <code>\{x\}</code> prefix on attribute values \([https\://github\.com/ansible\-collections/community\.general/issues/977](https\://github\.com/ansible\-collections/community\.general/issues/977)\, [https\://github\.com/ansible\-collections/community\.general/pull/5385](https\://github\.com/ansible\-collections/community\.general/pull/5385)\)\.
|
||||
* listen\_ports\_facts \- removed leftover <code>EnvironmentError</code> \. The <code>else</code> clause had a wrong indentation\. The check is now handled in the <code>split\_pid\_name</code> function \([https\://github\.com/ansible\-collections/community\.general/pull/5202](https\://github\.com/ansible\-collections/community\.general/pull/5202)\)\.
|
||||
* locale\_gen \- fix support for Ubuntu \([https\://github\.com/ansible\-collections/community\.general/issues/5281](https\://github\.com/ansible\-collections/community\.general/issues/5281)\)\.
|
||||
* lxc\_container \- the module has been updated to support Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/5304](https\://github\.com/ansible\-collections/community\.general/pull/5304)\)\.
|
||||
* lxd connection plugin \- fix incorrect <code>inventory\_hostname</code> in <code>remote\_addr</code>\. This is needed for compatibility with ansible\-core 2\.13 \([https\://github\.com/ansible\-collections/community\.general/issues/4886](https\://github\.com/ansible\-collections/community\.general/issues/4886)\)\.
|
||||
* manageiq\_alert\_profiles \- avoid crash when reporting unknown profile caused by trying to return an undefined variable \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* nmcli \- avoid changed status for most cases with VPN connections \([https\://github\.com/ansible\-collections/community\.general/pull/5126](https\://github\.com/ansible\-collections/community\.general/pull/5126)\)\.
|
||||
* nmcli \- fix error caused by adding undefined module arguments for list options \([https\://github\.com/ansible\-collections/community\.general/issues/4373](https\://github\.com/ansible\-collections/community\.general/issues/4373)\, [https\://github\.com/ansible\-collections/community\.general/pull/4813](https\://github\.com/ansible\-collections/community\.general/pull/4813)\)\.
|
||||
* nmcli \- fix error when setting previously unset MAC address\, <code>gsm\.apn</code> or <code>vpn\.data</code>\: current values were being normalized without checking if they might be <code>None</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5291](https\://github\.com/ansible\-collections/community\.general/pull/5291)\)\.
|
||||
* nmcli \- fix int options idempotence \([https\://github\.com/ansible\-collections/community\.general/issues/4998](https\://github\.com/ansible\-collections/community\.general/issues/4998)\)\.
|
||||
* nsupdate \- compatibility with NS records \([https\://github\.com/ansible\-collections/community\.general/pull/5112](https\://github\.com/ansible\-collections/community\.general/pull/5112)\)\.
|
||||
* nsupdate \- fix silent failures when updating <code>NS</code> entries from Bind9 managed DNS zones \([https\://github\.com/ansible\-collections/community\.general/issues/4657](https\://github\.com/ansible\-collections/community\.general/issues/4657)\)\.
|
||||
* opentelemetry callback plugin \- support opentelemetry\-api 1\.13\.0 that removed support for <code>\_time\_ns</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5342](https\://github\.com/ansible\-collections/community\.general/pull/5342)\)\.
|
||||
* osx\_defaults \- no longer expand <code>\~</code> in <code>value</code> to the user\'s home directory\, or expand environment variables \([https\://github\.com/ansible\-collections/community\.general/issues/5234](https\://github\.com/ansible\-collections/community\.general/issues/5234)\, [https\://github\.com/ansible\-collections/community\.general/pull/5243](https\://github\.com/ansible\-collections/community\.general/pull/5243)\)\.
|
||||
* packet\_ip\_subnet \- fix error reporting in case of invalid CIDR prefix lengths \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* pacman \- fixed name resolution of URL packages \([https\://github\.com/ansible\-collections/community\.general/pull/4959](https\://github\.com/ansible\-collections/community\.general/pull/4959)\)\.
|
||||
* passwordstore lookup plugin \- fix <code>returnall</code> for gopass \([https\://github\.com/ansible\-collections/community\.general/pull/5027](https\://github\.com/ansible\-collections/community\.general/pull/5027)\)\.
|
||||
* passwordstore lookup plugin \- fix password store path detection for gopass \([https\://github\.com/ansible\-collections/community\.general/pull/4955](https\://github\.com/ansible\-collections/community\.general/pull/4955)\)\.
|
||||
* pfexec become plugin \- remove superflous quotes preventing exe wrap from working as expected \([https\://github\.com/ansible\-collections/community\.general/issues/3671](https\://github\.com/ansible\-collections/community\.general/issues/3671)\, [https\://github\.com/ansible\-collections/community\.general/pull/3889](https\://github\.com/ansible\-collections/community\.general/pull/3889)\)\.
|
||||
* pip\_package\_info \- remove usage of global variable \([https\://github\.com/ansible\-collections/community\.general/pull/5111](https\://github\.com/ansible\-collections/community\.general/pull/5111)\)\.
|
||||
* pkgng \- fix case when <code>pkg</code> fails when trying to upgrade all packages \([https\://github\.com/ansible\-collections/community\.general/issues/5363](https\://github\.com/ansible\-collections/community\.general/issues/5363)\)\.
|
||||
* proxmox \- fix error handling when getting VM by name when <code>state\=absent</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4945](https\://github\.com/ansible\-collections/community\.general/pull/4945)\)\.
|
||||
* proxmox inventory plugin \- fix crash when <code>enabled\=1</code> is used in agent config string \([https\://github\.com/ansible\-collections/community\.general/pull/4910](https\://github\.com/ansible\-collections/community\.general/pull/4910)\)\.
|
||||
* proxmox inventory plugin \- fixed extended status detection for qemu \([https\://github\.com/ansible\-collections/community\.general/pull/4816](https\://github\.com/ansible\-collections/community\.general/pull/4816)\)\.
|
||||
* proxmox\_kvm \- fix <code>agent</code> parameter when boolean value is specified \([https\://github\.com/ansible\-collections/community\.general/pull/5198](https\://github\.com/ansible\-collections/community\.general/pull/5198)\)\.
|
||||
* proxmox\_kvm \- fix error handling when getting VM by name when <code>state\=absent</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4945](https\://github\.com/ansible\-collections/community\.general/pull/4945)\)\.
|
||||
* proxmox\_kvm \- fix exception when no <code>agent</code> argument is specified \([https\://github\.com/ansible\-collections/community\.general/pull/5194](https\://github\.com/ansible\-collections/community\.general/pull/5194)\)\.
|
||||
* proxmox\_kvm \- fix wrong condition \([https\://github\.com/ansible\-collections/community\.general/pull/5108](https\://github\.com/ansible\-collections/community\.general/pull/5108)\)\.
|
||||
* proxmox\_kvm \- replace new condition with proper condition to allow for using <code>vmid</code> on update \([https\://github\.com/ansible\-collections/community\.general/pull/5206](https\://github\.com/ansible\-collections/community\.general/pull/5206)\)\.
|
||||
* rax\_clb\_nodes \- fix code to be compatible with Python 3 \([https\://github\.com/ansible\-collections/community\.general/pull/4933](https\://github\.com/ansible\-collections/community\.general/pull/4933)\)\.
|
||||
* redfish\_command \- fix the check if a virtual media is unmounted to just check for <code>instered\= false</code> caused by Supermicro hardware that does not clear the <code>ImageName</code> \([https\://github\.com/ansible\-collections/community\.general/pull/4839](https\://github\.com/ansible\-collections/community\.general/pull/4839)\)\.
|
||||
* redfish\_command \- the Supermicro Redfish implementation only supports the <code>image\_url</code> parameter in the underlying API calls to <code>VirtualMediaInsert</code> and <code>VirtualMediaEject</code>\. Any values set \(or the defaults\) for <code>write\_protected</code> or <code>inserted</code> will be ignored \([https\://github\.com/ansible\-collections/community\.general/pull/4839](https\://github\.com/ansible\-collections/community\.general/pull/4839)\)\.
|
||||
* redfish\_info \- fix to <code>GetChassisPower</code> to correctly report power information when multiple chassis exist\, but not all chassis report power information \([https\://github\.com/ansible\-collections/community\.general/issues/4901](https\://github\.com/ansible\-collections/community\.general/issues/4901)\)\.
|
||||
* redfish\_utils module utils \- centralize payload checking when performing modification requests to a Redfish service \([https\://github\.com/ansible\-collections/community\.general/issues/5210/](https\://github\.com/ansible\-collections/community\.general/issues/5210/)\)\.
|
||||
* redhat\_subscription \- fix unsubscribing on RHEL 9 \([https\://github\.com/ansible\-collections/community\.general/issues/4741](https\://github\.com/ansible\-collections/community\.general/issues/4741)\)\.
|
||||
* redhat\_subscription \- make module idempotent when <code>pool\_ids</code> are used \([https\://github\.com/ansible\-collections/community\.general/issues/5313](https\://github\.com/ansible\-collections/community\.general/issues/5313)\)\.
|
||||
* redis\* modules \- fix call to <code>module\.fail\_json</code> when failing because of missing Python libraries \([https\://github\.com/ansible\-collections/community\.general/pull/4733](https\://github\.com/ansible\-collections/community\.general/pull/4733)\)\.
|
||||
* slack \- fix incorrect channel prefix <code>\#</code> caused by incomplete pattern detection by adding <code>G0</code> and <code>GF</code> as channel ID patterns \([https\://github\.com/ansible\-collections/community\.general/pull/5019](https\://github\.com/ansible\-collections/community\.general/pull/5019)\)\.
|
||||
* slack \- fix message update for channels which start with <code>CP</code>\. When <code>message\-id</code> was passed it failed for channels which started with <code>CP</code> because the <code>\#</code> symbol was added before the <code>channel\_id</code> \([https\://github\.com/ansible\-collections/community\.general/pull/5249](https\://github\.com/ansible\-collections/community\.general/pull/5249)\)\.
|
||||
* snap \- allow values in the <code>options</code> parameter to contain whitespaces \([https\://github\.com/ansible\-collections/community\.general/pull/5475](https\://github\.com/ansible\-collections/community\.general/pull/5475)\)\.
|
||||
* sudoers \- ensure sudoers config files are created with the permissions requested by sudoers \(0440\) \([https\://github\.com/ansible\-collections/community\.general/pull/4814](https\://github\.com/ansible\-collections/community\.general/pull/4814)\)\.
|
||||
* sudoers \- fix incorrect handling of <code>state\: absent</code> \([https\://github\.com/ansible\-collections/community\.general/issues/4852](https\://github\.com/ansible\-collections/community\.general/issues/4852)\)\.
|
||||
* tss lookup plugin \- adding support for updated Delinea library \([https\://github\.com/DelineaXPM/python\-tss\-sdk/issues/9](https\://github\.com/DelineaXPM/python\-tss\-sdk/issues/9)\, [https\://github\.com/ansible\-collections/community\.general/pull/5151](https\://github\.com/ansible\-collections/community\.general/pull/5151)\)\.
|
||||
* virtualbox inventory plugin \- skip parsing values with keys that have both a value and nested data\. Skip parsing values that are nested more than two keys deep \([https\://github\.com/ansible\-collections/community\.general/issues/5332](https\://github\.com/ansible\-collections/community\.general/issues/5332)\, [https\://github\.com/ansible\-collections/community\.general/pull/5348](https\://github\.com/ansible\-collections/community\.general/pull/5348)\)\.
|
||||
* xcc\_redfish\_command \- for compatibility due to Redfish spec changes the virtualMedia resource location changed from Manager to System \([https\://github\.com/ansible\-collections/community\.general/pull/4682](https\://github\.com/ansible\-collections/community\.general/pull/4682)\)\.
|
||||
* xenserver\_facts \- fix broken <code>AnsibleModule</code> call that prevented the module from working at all \([https\://github\.com/ansible\-collections/community\.general/pull/5383](https\://github\.com/ansible\-collections/community\.general/pull/5383)\)\.
|
||||
* xfconf \- fix setting of boolean values \([https\://github\.com/ansible\-collections/community\.general/issues/4999](https\://github\.com/ansible\-collections/community\.general/issues/4999)\, [https\://github\.com/ansible\-collections/community\.general/pull/5007](https\://github\.com/ansible\-collections/community\.general/pull/5007)\)\.
|
||||
* zfs \- fix wrong quoting of properties \([https\://github\.com/ansible\-collections/community\.general/issues/4707](https\://github\.com/ansible\-collections/community\.general/issues/4707)\, [https\://github\.com/ansible\-collections/community\.general/pull/4726](https\://github\.com/ansible\-collections/community\.general/pull/4726)\)\.
|
||||
|
||||
<a id="new-plugins-1"></a>
|
||||
### New Plugins
|
||||
|
||||
<a id="filter"></a>
|
||||
#### Filter
|
||||
|
||||
* counter \- Counts hashable elements in a sequence
|
||||
|
||||
<a id="lookup-1"></a>
|
||||
#### Lookup
|
||||
|
||||
* bitwarden \- Retrieve secrets from Bitwarden
|
||||
|
||||
<a id="new-modules-4"></a>
|
||||
### New Modules
|
||||
|
||||
* gconftool2\_info \- Retrieve GConf configurations
|
||||
* iso\_customize \- Add/remove/change files in ISO file
|
||||
* keycloak\_user\_rolemapping \- Allows administration of Keycloak user\_rolemapping with the Keycloak API
|
||||
* keyring \- Set or delete a passphrase using the Operating System\'s native keyring
|
||||
* keyring\_info \- Get a passphrase using the Operating System\'s native keyring
|
||||
* manageiq\_policies\_info \- Listing of resource policy\_profiles in ManageIQ
|
||||
* manageiq\_tags\_info \- Retrieve resource tags in ManageIQ
|
||||
* pipx\_info \- Rretrieves information about applications installed with pipx
|
||||
* proxmox\_disk \- Management of a disk of a Qemu\(KVM\) VM in a Proxmox VE cluster\.
|
||||
* scaleway\_compute\_private\_network \- Scaleway compute \- private network management
|
||||
* scaleway\_container \- Scaleway Container management
|
||||
* scaleway\_container\_info \- Retrieve information on Scaleway Container
|
||||
* scaleway\_container\_namespace \- Scaleway Container namespace management
|
||||
* scaleway\_container\_namespace\_info \- Retrieve information on Scaleway Container namespace
|
||||
* scaleway\_container\_registry \- Scaleway Container registry management module
|
||||
* scaleway\_container\_registry\_info \- Scaleway Container registry info module
|
||||
* scaleway\_function \- Scaleway Function management
|
||||
* scaleway\_function\_info \- Retrieve information on Scaleway Function
|
||||
* scaleway\_function\_namespace \- Scaleway Function namespace management
|
||||
* scaleway\_function\_namespace\_info \- Retrieve information on Scaleway Function namespace
|
||||
* wdc\_redfish\_command \- Manages WDC UltraStar Data102 Out\-Of\-Band controllers using Redfish APIs
|
||||
* wdc\_redfish\_info \- Manages WDC UltraStar Data102 Out\-Of\-Band controllers using Redfish APIs
|
||||
3
CHANGELOG.md.license
Normal file
3
CHANGELOG.md.license
Normal file
@@ -0,0 +1,3 @@
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
SPDX-FileCopyrightText: Ansible Project
|
||||
334
CHANGELOG.rst
334
CHANGELOG.rst
@@ -6,6 +6,340 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 5.0.0.
|
||||
|
||||
v6.6.9
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Maintenance release.
|
||||
|
||||
This is the last 6.x.y release. The 6.x.y release train is now effectively End of Life.
|
||||
Thanks to everyone who contributed to the community.general 6.x.y releases!
|
||||
|
||||
Security Fixes
|
||||
--------------
|
||||
|
||||
- keycloak_identity_provider - the client secret was not correctly sanitized by the module. The return values ``proposed``, ``existing``, and ``end_state``, as well as the diff, did contain the client secret unmasked (https://github.com/ansible-collections/community.general/pull/8355).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- inventory plugins - add unsafe wrapper to avoid marking strings that do not contain ``{`` or ``}`` as unsafe, to work around a bug in AWX ((https://github.com/ansible-collections/community.general/issues/8212, https://github.com/ansible-collections/community.general/pull/8225).
|
||||
- xml - make module work with lxml 5.1.1, which removed some internals that the module was relying on (https://github.com/ansible-collections/community.general/pull/8169).
|
||||
|
||||
v6.6.8
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Security and bugfix release.
|
||||
|
||||
Security Fixes
|
||||
--------------
|
||||
|
||||
- cobbler, gitlab_runners, icinga2, linode, lxd, nmap, online, opennebula, proxmox, scaleway, stackpath_compute, virtualbox, and xen_orchestra inventory plugin - make sure all data received from the remote servers is marked as unsafe, so remote code execution by obtaining texts that can be evaluated as templates is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/, https://github.com/ansible-collections/community.general/pull/8098).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- aix_filesystem - fix issue with empty list items in crfs logic and option order (https://github.com/ansible-collections/community.general/pull/8052).
|
||||
- pacemaker_cluster - actually implement check mode, which the module claims to support. This means that until now the module also did changes in check mode (https://github.com/ansible-collections/community.general/pull/8081).
|
||||
- pam_limits - when the file does not exist, do not create it in check mode (https://github.com/ansible-collections/community.general/issues/8050, https://github.com/ansible-collections/community.general/pull/8057).
|
||||
|
||||
v6.6.7
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Bugfix release.
|
||||
|
||||
From now on, community.general 6.x.y will only receive major bugfixes and security fixes anymore.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- composer - fix impossible to run ``working_dir`` dependent commands. The module was throwing an error when trying to run a ``working_dir`` dependent command, because it tried to get the command help without passing the ``working_dir`` (https://github.com/ansible-collections/community.general/issues/3787).
|
||||
- github_deploy_key - fix pagination behaviour causing a crash when only a single page of deploy keys exist (https://github.com/ansible-collections/community.general/pull/7375).
|
||||
- gitlab_group_members - fix gitlab constants call in ``gitlab_group_members`` module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_project_members - fix gitlab constants call in ``gitlab_project_members`` module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_protected_branches - fix gitlab constants call in ``gitlab_protected_branches`` module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_user - fix gitlab constants call in ``gitlab_user`` module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- lxc connection plugin - properly evaluate options (https://github.com/ansible-collections/community.general/pull/7369).
|
||||
- memset module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.general/pull/7379).
|
||||
- redhat_subscription - use the right D-Bus options for the consumer type when
|
||||
registering a RHEL system older than 9 or a RHEL 9 system older than 9.2
|
||||
and using ``consumer_type``
|
||||
(https://github.com/ansible-collections/community.general/pull/7378).
|
||||
- selective callback plugin - fix length of task name lines in output always being 3 characters longer than desired (https://github.com/ansible-collections/community.general/pull/7374).
|
||||
|
||||
v6.6.6
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- mail - skip headers containing equals characters due to missing ``maxsplit`` on header key/value parsing (https://github.com/ansible-collections/community.general/pull/7303).
|
||||
- onepassword - fix KeyError exception when trying to access value of a field that is not filled out in OnePassword item (https://github.com/ansible-collections/community.general/pull/7241).
|
||||
- terraform - prevents ``-backend-config`` option double encapsulating with ``shlex_quote`` function. (https://github.com/ansible-collections/community.general/pull/7301).
|
||||
|
||||
v6.6.5
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- make - allows ``params`` to be used without value (https://github.com/ansible-collections/community.general/pull/7180).
|
||||
- pritunl module utils - ensure ``validate_certs`` parameter is honoured in all methods (https://github.com/ansible-collections/community.general/pull/7156).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- CmdRunner module utils - does not attempt to resolve path if executable is a relative or absolute path (https://github.com/ansible-collections/community.general/pull/7200).
|
||||
- lxc connection plugin - now handles ``remote_addr`` defaulting to ``inventory_hostname`` correctly (https://github.com/ansible-collections/community.general/pull/7104).
|
||||
- nsupdate - fix a possible ``list index out of range`` exception (https://github.com/ansible-collections/community.general/issues/836).
|
||||
- oci_utils module util - fix inappropriate logical comparison expressions and makes them simpler. The previous checks had logical short circuits (https://github.com/ansible-collections/community.general/pull/7125).
|
||||
- pritunl module utils - fix incorrect URL parameter for orgnization add method (https://github.com/ansible-collections/community.general/pull/7161).
|
||||
|
||||
v6.6.4
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- redfish_utils - use ``Controllers`` key in redfish data to obtain Storage controllers properties (https://github.com/ansible-collections/community.general/pull/7081).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- bitwarden lookup plugin - the plugin made assumptions about the structure of a Bitwarden JSON object which may have been broken by an update in the Bitwarden API. Remove assumptions, and allow queries for general fields such as ``notes`` (https://github.com/ansible-collections/community.general/pull/7061).
|
||||
- cmd_runner module utils - when a parameter in ``argument_spec`` has no type, meaning it is implicitly a ``str``, ``CmdRunner`` would fail trying to find the ``type`` key in that dictionary (https://github.com/ansible-collections/community.general/pull/6968).
|
||||
- ejabberd_user - module was failing to detect whether user was already created and/or password was changed (https://github.com/ansible-collections/community.general/pull/7033).
|
||||
- ejabberd_user - provide meaningful error message when the ``ejabberdctl`` command is not found (https://github.com/ansible-collections/community.general/pull/7028, https://github.com/ansible-collections/community.general/issues/6949).
|
||||
- oci_utils module utils - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
|
||||
- proxmox module utils - fix proxmoxer library version check (https://github.com/ansible-collections/community.general/issues/6974, https://github.com/ansible-collections/community.general/issues/6975, https://github.com/ansible-collections/community.general/pull/6980).
|
||||
- proxmox_kvm - when ``name`` option is provided without ``vmid`` and VM with that name already exists then no new VM will be created (https://github.com/ansible-collections/community.general/issues/6911, https://github.com/ansible-collections/community.general/pull/6981).
|
||||
- proxmox_user_info - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
|
||||
- rundeck - fix ``TypeError`` on 404 API response (https://github.com/ansible-collections/community.general/pull/6983).
|
||||
|
||||
v6.6.3
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- cobbler inventory plugin - convert Ansible unicode strings to native Python unicode strings before passing user/password to XMLRPC client (https://github.com/ansible-collections/community.general/pull/6923).
|
||||
- redfish_info - fix for ``GetVolumeInventory``, Controller name was getting populated incorrectly and duplicates were seen in the volumes retrieved (https://github.com/ansible-collections/community.general/pull/6719).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- datadog_downtime - presence of ``rrule`` param lead to the Datadog API returning Bad Request due to a missing recurrence type (https://github.com/ansible-collections/community.general/pull/6811).
|
||||
- icinga2_host - fix a key error when updating an existing host (https://github.com/ansible-collections/community.general/pull/6748).
|
||||
- ipa_dnszone - fix 'idnsallowsyncptr' key error for reverse zone (https://github.com/ansible-collections/community.general/pull/6906, https://github.com/ansible-collections/community.general/issues/6905).
|
||||
- locale_gen - now works for locales without the underscore character such as ``C.UTF-8`` (https://github.com/ansible-collections/community.general/pull/6774, https://github.com/ansible-collections/community.general/issues/5142, https://github.com/ansible-collections/community.general/issues/4305).
|
||||
- machinectl become plugin - mark plugin as ``require_tty`` to automatically disable pipelining, with which this plugin is not compatible (https://github.com/ansible-collections/community.general/issues/6932, https://github.com/ansible-collections/community.general/pull/6935).
|
||||
- nmcli - fix support for empty list (in compare and scrape) (https://github.com/ansible-collections/community.general/pull/6769).
|
||||
- openbsd_pkg - the pkg_info(1) behavior has changed in OpenBSD >7.3. The error message ``Can't find`` should not lead to an error case (https://github.com/ansible-collections/community.general/pull/6785).
|
||||
- pacman - module recognizes the output of ``yay`` running as ``root`` (https://github.com/ansible-collections/community.general/pull/6713).
|
||||
- proxmox - fix error when a configuration had no ``template`` field (https://github.com/ansible-collections/community.general/pull/6838, https://github.com/ansible-collections/community.general/issues/5372).
|
||||
- proxmox module utils - add logic to detect whether an old Promoxer complains about the ``token_name`` and ``token_value`` parameters and provide a better error message when that happens (https://github.com/ansible-collections/community.general/pull/6839, https://github.com/ansible-collections/community.general/issues/5371).
|
||||
- proxmox_disk - fix unable to create ``cdrom`` media due to ``size`` always being appended (https://github.com/ansible-collections/community.general/pull/6770).
|
||||
- proxmox_kvm - ``absent`` state with ``force`` specified failed to stop the VM due to the ``timeout`` value not being passed to ``stop_vm`` (https://github.com/ansible-collections/community.general/pull/6827).
|
||||
- redfish_info - fix ``ListUsers`` to not show empty account slots (https://github.com/ansible-collections/community.general/issues/6771, https://github.com/ansible-collections/community.general/pull/6772).
|
||||
- refish_utils module utils - changing variable names to avoid issues occuring when fetching Volumes data (https://github.com/ansible-collections/community.general/pull/6883).
|
||||
- rhsm_repository - when using the ``purge`` option, the ``repositories``
|
||||
dictionary element in the returned JSON is now properly updated according
|
||||
to the pruning operation
|
||||
(https://github.com/ansible-collections/community.general/pull/6676).
|
||||
|
||||
v6.6.2
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- csv module utils - detects and remove unicode BOM markers from incoming CSV content (https://github.com/ansible-collections/community.general/pull/6662).
|
||||
- gitlab_group - the module passed parameters to the API call even when not set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
|
||||
- ini_file - fix a bug where the inactive options were not used when possible (https://github.com/ansible-collections/community.general/pull/6575).
|
||||
- keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries (https://github.com/ansible-collections/community.general/pull/6688).
|
||||
- keycloak module utils - the function ``get_user_by_username`` now return the user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
|
||||
|
||||
v6.6.1
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- dconf - if ``gi.repository.GLib`` is missing, try to respawn in a Python interpreter that has it (https://github.com/ansible-collections/community.general/pull/6491).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- deps module utils - do not fail when dependency cannot be found (https://github.com/ansible-collections/community.general/pull/6479).
|
||||
- nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
|
||||
- passwordstore lookup plugin - make compatible with ansible-core 2.16 (https://github.com/ansible-collections/community.general/pull/6447).
|
||||
- portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008, https://github.com/ansible-collections/community.general/pull/6548).
|
||||
- portage - update the logic for generating the emerge command arguments to ensure that ``withbdeps: false`` results in a passing an ``n`` argument with the ``--with-bdeps`` emerge flag (https://github.com/ansible-collections/community.general/issues/6451, https://github.com/ansible-collections/community.general/pull/6456).
|
||||
- proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from ``required_together`` as it causes to require ``api_password`` even when API token param is used (https://github.com/ansible-collections/community.general/issues/6201).
|
||||
- puppet - handling ``noop`` parameter was not working at all, now it is has been fixed (https://github.com/ansible-collections/community.general/issues/6452, https://github.com/ansible-collections/community.general/issues/6458).
|
||||
- terraform - fix broken ``warn()`` call (https://github.com/ansible-collections/community.general/pull/6497).
|
||||
- xfs_quota - in case of a project quota, the call to ``xfs_quota`` did not initialize/reset the project (https://github.com/ansible-collections/community.general/issues/5143).
|
||||
- zypper - added handling of zypper exitcode 102. Changed state is set correctly now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
|
||||
|
||||
v6.6.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- cpanm - minor change, use feature from ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/6385).
|
||||
- dconf - be forgiving about boolean values: convert them to GVariant booleans automatically (https://github.com/ansible-collections/community.general/pull/6206).
|
||||
- dconf - minor refactoring improving parameters and dependencies validation (https://github.com/ansible-collections/community.general/pull/6336).
|
||||
- deps module utils - add function ``failed()`` providing the ability to check the dependency check result without triggering an exception (https://github.com/ansible-collections/community.general/pull/6383).
|
||||
- dig lookup plugin - Support multiple domains to be queried as indicated in docs (https://github.com/ansible-collections/community.general/pull/6334).
|
||||
- gitlab_project - add new option ``topics`` for adding topics to GitLab projects (https://github.com/ansible-collections/community.general/pull/6278).
|
||||
- homebrew_cask - allows passing ``--greedy`` option to ``upgrade_all`` (https://github.com/ansible-collections/community.general/pull/6267).
|
||||
- idrac_redfish_command - add ``job_id`` to ``CreateBiosConfigJob`` response (https://github.com/ansible-collections/community.general/issues/5603).
|
||||
- ipa_hostgroup - add ``append`` parameter for adding a new hosts to existing hostgroups without changing existing hostgroup members (https://github.com/ansible-collections/community.general/pull/6203).
|
||||
- keycloak_authentication - add flow type option to sub flows to allow the creation of 'form-flow' sub flows like in Keycloak's built-in registration flow (https://github.com/ansible-collections/community.general/pull/6318).
|
||||
- mksysb - improved the output of the module in case of errors (https://github.com/ansible-collections/community.general/issues/6263).
|
||||
- nmap inventory plugin - added environment variables for configure ``address`` and ``exclude`` (https://github.com/ansible-collections/community.general/issues/6351).
|
||||
- nmcli - add ``macvlan`` connection type (https://github.com/ansible-collections/community.general/pull/6312).
|
||||
- pipx - add ``system_site_packages`` parameter to give application access to system-wide packages (https://github.com/ansible-collections/community.general/pull/6308).
|
||||
- pipx - ensure ``include_injected`` parameter works with ``state=upgrade`` and ``state=latest`` (https://github.com/ansible-collections/community.general/pull/6212).
|
||||
- puppet - add new options ``skip_tags`` to exclude certain tagged resources during a puppet agent or apply (https://github.com/ansible-collections/community.general/pull/6293).
|
||||
- terraform - remove state file check condition and error block, because in the native implementation of terraform will not cause errors due to the non-existent file (https://github.com/ansible-collections/community.general/pull/6296).
|
||||
- udm_dns_record - minor refactor to the code (https://github.com/ansible-collections/community.general/pull/6382).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- archive - reduce RAM usage by generating CRC32 checksum over chunks (https://github.com/ansible-collections/community.general/pull/6274).
|
||||
- flatpak - fixes idempotency detection issues. In some cases the module could fail to properly detect already existing Flatpaks because of a parameter witch only checks the installed apps (https://github.com/ansible-collections/community.general/pull/6289).
|
||||
- icinga2_host - fix the data structure sent to Icinga to make use of host templates and template vars (https://github.com/ansible-collections/community.general/pull/6286).
|
||||
- idrac_redfish_command - allow user to specify ``resource_id`` for ``CreateBiosConfigJob`` to specify an exact manager (https://github.com/ansible-collections/community.general/issues/2090).
|
||||
- ini_file - make ``section`` parameter not required so it is possible to pass ``null`` as a value. This only was possible in the past due to a bug in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6404).
|
||||
- keycloak - improve error messages (https://github.com/ansible-collections/community.general/pull/6318).
|
||||
- one_vm - fix syntax error when creating VMs with a more complex template (https://github.com/ansible-collections/community.general/issues/6225).
|
||||
- pipx - fixed handling of ``install_deps=true`` with ``state=latest`` and ``state=upgrade`` (https://github.com/ansible-collections/community.general/pull/6303).
|
||||
- redhat_subscription - do not use D-Bus for registering when ``environment`` is specified, so it possible to specify again the environment names for registering, as the D-Bus APIs work only with IDs (https://github.com/ansible-collections/community.general/pull/6319).
|
||||
- redhat_subscription - try to unregister only when already registered when ``force_register`` is specified (https://github.com/ansible-collections/community.general/issues/6258, https://github.com/ansible-collections/community.general/pull/6259).
|
||||
- redhat_subscription - use the right D-Bus options for environments when registering a CentOS Stream 8 system and using ``environment`` (https://github.com/ansible-collections/community.general/pull/6275).
|
||||
- rhsm_release - make ``release`` parameter not required so it is possible to pass ``null`` as a value. This only was possible in the past due to a bug in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6401).
|
||||
- rundeck module utils - fix errors caused by the API empty responses (https://github.com/ansible-collections/community.general/pull/6300)
|
||||
- rundeck_acl_policy - fix ``TypeError - byte indices must be integers or slices, not str`` error caused by empty API response. Update the module to use ``module_utils.rundeck`` functions (https://github.com/ansible-collections/community.general/pull/5887, https://github.com/ansible-collections/community.general/pull/6300).
|
||||
- rundeck_project - update the module to use ``module_utils.rundeck`` functions (https://github.com/ansible-collections/community.general/issues/5742) (https://github.com/ansible-collections/community.general/pull/6300)
|
||||
- snap_alias - module would only recognize snap names containing letter, numbers or the underscore character, failing to identify valid snap names such as ``lxd.lxc`` (https://github.com/ansible-collections/community.general/pull/6361).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- btrfs_info - Query btrfs filesystem info
|
||||
- btrfs_subvolume - Manage btrfs subvolumes
|
||||
- ilo_redfish_command - Manages Out-Of-Band controllers using Redfish APIs
|
||||
- keycloak_authz_authorization_scope - Allows administration of Keycloak client authorization scopes via Keycloak API
|
||||
- keycloak_clientscope_type - Set the type of aclientscope in realm or client via Keycloak API
|
||||
|
||||
v6.5.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Feature and bugfix release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- apt_rpm - adds ``clean``, ``dist_upgrade`` and ``update_kernel`` parameters for clear caches, complete upgrade system, and upgrade kernel packages (https://github.com/ansible-collections/community.general/pull/5867).
|
||||
- dconf - parse GVariants for equality comparison when the Python module ``gi.repository`` is available (https://github.com/ansible-collections/community.general/pull/6049).
|
||||
- gitlab_runner - allow to register group runner (https://github.com/ansible-collections/community.general/pull/3935).
|
||||
- jira - add worklog functionality (https://github.com/ansible-collections/community.general/issues/6209, https://github.com/ansible-collections/community.general/pull/6210).
|
||||
- ldap modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/6185).
|
||||
- make - add ``command`` return value to the module output (https://github.com/ansible-collections/community.general/pull/6160).
|
||||
- nmap inventory plugin - add new option ``open`` for only returning open ports (https://github.com/ansible-collections/community.general/pull/6200).
|
||||
- nmap inventory plugin - add new option ``port`` for port specific scan (https://github.com/ansible-collections/community.general/pull/6165).
|
||||
- nmcli - add ``default`` and ``default-or-eui64`` to the list of valid choices for ``addr_gen_mode6`` parameter (https://github.com/ansible-collections/community.general/pull/5974).
|
||||
- nmcli - add support for ``team.runner-fast-rate`` parameter for ``team`` connections (https://github.com/ansible-collections/community.general/issues/6065).
|
||||
- openbsd_pkg - set ``TERM`` to ``'dumb'`` in ``execute_command()`` to make module less dependant on the ``TERM`` environment variable set on the Ansible controller (https://github.com/ansible-collections/community.general/pull/6149).
|
||||
- pipx - optional ``install_apps`` parameter added to install applications from injected packages (https://github.com/ansible-collections/community.general/pull/6198).
|
||||
- proxmox_kvm - add new ``archive`` parameter. This is needed to create a VM from an archive (backup) (https://github.com/ansible-collections/community.general/pull/6159).
|
||||
- redfish_info - adds commands to retrieve the HPE ThermalConfiguration and FanPercentMinimum settings from iLO (https://github.com/ansible-collections/community.general/pull/6208).
|
||||
- redhat_subscription - credentials (``username``, ``activationkey``, and so on) are required now only if a system needs to be registered, or ``force_register`` is specified (https://github.com/ansible-collections/community.general/pull/5664).
|
||||
- redhat_subscription - the registration is done using the D-Bus ``rhsm`` service instead of spawning a ``subscription-manager register`` command, if possible; this avoids passing plain-text credentials as arguments to ``subscription-manager register``, which can be seen while that command runs (https://github.com/ansible-collections/community.general/pull/6122).
|
||||
- ssh_config - add ``proxyjump`` option (https://github.com/ansible-collections/community.general/pull/5970).
|
||||
- ssh_config - vendored StormSSH's config parser to avoid having to install StormSSH to use the module (https://github.com/ansible-collections/community.general/pull/6117).
|
||||
- znode module - optional ``use_tls`` parameter added for encrypted communication (https://github.com/ansible-collections/community.general/issues/6154).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- archive - avoid deprecated exception class on Python 3 (https://github.com/ansible-collections/community.general/pull/6180).
|
||||
- gitlab_runner - fix ``KeyError`` on runner creation and update (https://github.com/ansible-collections/community.general/issues/6112).
|
||||
- influxdb_user - fix running in check mode when the user does not exist yet (https://github.com/ansible-collections/community.general/pull/6111).
|
||||
- interfaces_file - fix reading options in lines not starting with a space (https://github.com/ansible-collections/community.general/issues/6120).
|
||||
- jail connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``. This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/6118).
|
||||
- memset - fix memset urlerror handling (https://github.com/ansible-collections/community.general/pull/6114).
|
||||
- nmcli - fixed idempotency issue for bridge connections. Module forced default value of ``bridge.priority`` to nmcli if not set; if ``bridge.stp`` is disabled nmcli ignores it and keep default (https://github.com/ansible-collections/community.general/issues/3216, https://github.com/ansible-collections/community.general/issues/4683).
|
||||
- nmcli - fixed idempotency issue when module params is set to ``may_fail4=false`` and ``method4=disabled``; in this case nmcli ignores change and keeps their own default value ``yes`` (https://github.com/ansible-collections/community.general/pull/6106).
|
||||
- nmcli - implemented changing mtu value on vlan interfaces (https://github.com/ansible-collections/community.general/issues/4387).
|
||||
- opkg - fixes bug when using ``update_cache=true`` (https://github.com/ansible-collections/community.general/issues/6004).
|
||||
- redhat_subscription, rhsm_release, rhsm_repository - cleanly fail when not running as root, rather than hanging on an interactive ``console-helper`` prompt; they all interact with ``subscription-manager``, which already requires to be run as root (https://github.com/ansible-collections/community.general/issues/734, https://github.com/ansible-collections/community.general/pull/6211).
|
||||
- xenorchestra inventory plugin - fix failure to receive objects from server due to not checking the id of the response (https://github.com/ansible-collections/community.general/pull/6227).
|
||||
- yarn - fix ``global=true`` to not fail when `executable` wasn't specified (https://github.com/ansible-collections/community.general/pull/6132)
|
||||
- yarn - fixes bug where yarn module tasks would fail when warnings were emitted from Yarn. The ``yarn.list`` method was not filtering out warnings (https://github.com/ansible-collections/community.general/issues/6127).
|
||||
|
||||
New Plugins
|
||||
-----------
|
||||
|
||||
Lookup
|
||||
~~~~~~
|
||||
|
||||
- merge_variables - merge variables with a certain suffix
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- kdeconfig - Manage KDE configuration files
|
||||
|
||||
v6.4.0
|
||||
======
|
||||
|
||||
|
||||
@@ -121,19 +121,3 @@ Creating new modules and plugins requires a bit more work than other Pull Reques
|
||||
listed as `maintainers` will be pinged for new issues and PRs that modify the module/plugin or its tests.
|
||||
|
||||
When you add a new plugin/module, we expect that you perform maintainer duty for at least some time after contributing it.
|
||||
|
||||
## pre-commit
|
||||
|
||||
To help ensure high-quality contributions this repository includes a [pre-commit](https://pre-commit.com) configuration which
|
||||
corrects and tests against common issues that would otherwise cause CI to fail. To begin using these pre-commit hooks see
|
||||
the [Installation](#installation) section below.
|
||||
|
||||
This is optional and not required to contribute to this repository.
|
||||
|
||||
### Installation
|
||||
|
||||
Follow the [instructions](https://pre-commit.com/#install) provided with pre-commit and run `pre-commit install` under the repository base. If for any reason you would like to disable the pre-commit hooks run `pre-commit uninstall`.
|
||||
|
||||
This is optional to run it locally.
|
||||
|
||||
You can trigger it locally with `pre-commit run --all-files` or even to run only for a given file `pre-commit run --files YOUR_FILE`.
|
||||
|
||||
11
README.md
11
README.md
@@ -9,6 +9,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://github.com/ansible-collections/community.general/actions)
|
||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||
[](https://api.reuse.software/info/github.com/ansible-collections/community.general)
|
||||
|
||||
This repository contains the `community.general` Ansible Collection. The collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
||||
|
||||
@@ -24,7 +25,7 @@ If you encounter abusive behavior violating the [Ansible Code of Conduct](https:
|
||||
|
||||
## Tested with Ansible
|
||||
|
||||
Tested with the current ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14 releases and the current development version of ansible-core. Ansible-core versions before 2.11.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
Tested with the current ansible-core 2.11, ansible-core 2.12, ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, and ansible-core 2.16 releases. Ansible-core versions before 2.11.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
|
||||
|
||||
Parts of this collection will not work with ansible-core 2.11 on Python 3.12+.
|
||||
|
||||
@@ -34,13 +35,13 @@ Some modules and plugins require external libraries. Please check the requiremen
|
||||
|
||||
## Included content
|
||||
|
||||
Please check the included content on the [Ansible Galaxy page for this collection](https://galaxy.ansible.com/community/general) or the [documentation on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
||||
Please check the included content on the [Ansible Galaxy page for this collection](https://galaxy.ansible.com/ui/repo/published/community/general/) or the [documentation on the Ansible docs site](https://docs.ansible.com/ansible/latest/collections/community/general/).
|
||||
|
||||
## Using this collection
|
||||
|
||||
This collection is shipped with the Ansible package. So if you have it installed, no more action is required.
|
||||
|
||||
If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/community/general) manually with the `ansible-galaxy` command-line tool:
|
||||
If you have a minimal installation (only Ansible Core installed) or you want to use the latest version of the collection along with the whole Ansible package, you need to install the collection from [Ansible Galaxy](https://galaxy.ansible.com/ui/repo/published/community/general/) manually with the `ansible-galaxy` command-line tool:
|
||||
|
||||
ansible-galaxy collection install community.general
|
||||
|
||||
@@ -57,7 +58,7 @@ Note that if you install the collection manually, it will not be upgraded automa
|
||||
ansible-galaxy collection install community.general --upgrade
|
||||
```
|
||||
|
||||
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/community/general):
|
||||
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax where `X.Y.Z` can be any [available version](https://galaxy.ansible.com/ui/repo/published/community/general/):
|
||||
|
||||
```bash
|
||||
ansible-galaxy collection install community.general:==X.Y.Z
|
||||
@@ -117,7 +118,7 @@ See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/ma
|
||||
|
||||
## Release notes
|
||||
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-6/CHANGELOG.rst).
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-6/CHANGELOG.md).
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
@@ -1122,3 +1122,552 @@ releases:
|
||||
- 6100-jenkins_plugin.yml
|
||||
- remove-unneeded-imports.yml
|
||||
release_date: '2023-02-27'
|
||||
6.5.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- archive - avoid deprecated exception class on Python 3 (https://github.com/ansible-collections/community.general/pull/6180).
|
||||
- gitlab_runner - fix ``KeyError`` on runner creation and update (https://github.com/ansible-collections/community.general/issues/6112).
|
||||
- influxdb_user - fix running in check mode when the user does not exist yet
|
||||
(https://github.com/ansible-collections/community.general/pull/6111).
|
||||
- interfaces_file - fix reading options in lines not starting with a space (https://github.com/ansible-collections/community.general/issues/6120).
|
||||
- jail connection plugin - add ``inventory_hostname`` to vars under ``remote_addr``.
|
||||
This is needed for compatibility with ansible-core 2.13 (https://github.com/ansible-collections/community.general/pull/6118).
|
||||
- memset - fix memset urlerror handling (https://github.com/ansible-collections/community.general/pull/6114).
|
||||
- nmcli - fixed idempotency issue for bridge connections. Module forced default
|
||||
value of ``bridge.priority`` to nmcli if not set; if ``bridge.stp`` is disabled
|
||||
nmcli ignores it and keep default (https://github.com/ansible-collections/community.general/issues/3216,
|
||||
https://github.com/ansible-collections/community.general/issues/4683).
|
||||
- nmcli - fixed idempotency issue when module params is set to ``may_fail4=false``
|
||||
and ``method4=disabled``; in this case nmcli ignores change and keeps their
|
||||
own default value ``yes`` (https://github.com/ansible-collections/community.general/pull/6106).
|
||||
- nmcli - implemented changing mtu value on vlan interfaces (https://github.com/ansible-collections/community.general/issues/4387).
|
||||
- opkg - fixes bug when using ``update_cache=true`` (https://github.com/ansible-collections/community.general/issues/6004).
|
||||
- redhat_subscription, rhsm_release, rhsm_repository - cleanly fail when not
|
||||
running as root, rather than hanging on an interactive ``console-helper``
|
||||
prompt; they all interact with ``subscription-manager``, which already requires
|
||||
to be run as root (https://github.com/ansible-collections/community.general/issues/734,
|
||||
https://github.com/ansible-collections/community.general/pull/6211).
|
||||
- xenorchestra inventory plugin - fix failure to receive objects from server
|
||||
due to not checking the id of the response (https://github.com/ansible-collections/community.general/pull/6227).
|
||||
- yarn - fix ``global=true`` to not fail when `executable` wasn't specified
|
||||
(https://github.com/ansible-collections/community.general/pull/6132)
|
||||
- yarn - fixes bug where yarn module tasks would fail when warnings were emitted
|
||||
from Yarn. The ``yarn.list`` method was not filtering out warnings (https://github.com/ansible-collections/community.general/issues/6127).
|
||||
minor_changes:
|
||||
- apt_rpm - adds ``clean``, ``dist_upgrade`` and ``update_kernel`` parameters
|
||||
for clear caches, complete upgrade system, and upgrade kernel packages (https://github.com/ansible-collections/community.general/pull/5867).
|
||||
- dconf - parse GVariants for equality comparison when the Python module ``gi.repository``
|
||||
is available (https://github.com/ansible-collections/community.general/pull/6049).
|
||||
- gitlab_runner - allow to register group runner (https://github.com/ansible-collections/community.general/pull/3935).
|
||||
- jira - add worklog functionality (https://github.com/ansible-collections/community.general/issues/6209,
|
||||
https://github.com/ansible-collections/community.general/pull/6210).
|
||||
- ldap modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/6185).
|
||||
- make - add ``command`` return value to the module output (https://github.com/ansible-collections/community.general/pull/6160).
|
||||
- nmap inventory plugin - add new option ``open`` for only returning open ports
|
||||
(https://github.com/ansible-collections/community.general/pull/6200).
|
||||
- nmap inventory plugin - add new option ``port`` for port specific scan (https://github.com/ansible-collections/community.general/pull/6165).
|
||||
- nmcli - add ``default`` and ``default-or-eui64`` to the list of valid choices
|
||||
for ``addr_gen_mode6`` parameter (https://github.com/ansible-collections/community.general/pull/5974).
|
||||
- nmcli - add support for ``team.runner-fast-rate`` parameter for ``team`` connections
|
||||
(https://github.com/ansible-collections/community.general/issues/6065).
|
||||
- openbsd_pkg - set ``TERM`` to ``'dumb'`` in ``execute_command()`` to make
|
||||
module less dependant on the ``TERM`` environment variable set on the Ansible
|
||||
controller (https://github.com/ansible-collections/community.general/pull/6149).
|
||||
- pipx - optional ``install_apps`` parameter added to install applications from
|
||||
injected packages (https://github.com/ansible-collections/community.general/pull/6198).
|
||||
- proxmox_kvm - add new ``archive`` parameter. This is needed to create a VM
|
||||
from an archive (backup) (https://github.com/ansible-collections/community.general/pull/6159).
|
||||
- redfish_info - adds commands to retrieve the HPE ThermalConfiguration and
|
||||
FanPercentMinimum settings from iLO (https://github.com/ansible-collections/community.general/pull/6208).
|
||||
- redhat_subscription - credentials (``username``, ``activationkey``, and so
|
||||
on) are required now only if a system needs to be registered, or ``force_register``
|
||||
is specified (https://github.com/ansible-collections/community.general/pull/5664).
|
||||
- redhat_subscription - the registration is done using the D-Bus ``rhsm`` service
|
||||
instead of spawning a ``subscription-manager register`` command, if possible;
|
||||
this avoids passing plain-text credentials as arguments to ``subscription-manager
|
||||
register``, which can be seen while that command runs (https://github.com/ansible-collections/community.general/pull/6122).
|
||||
- ssh_config - add ``proxyjump`` option (https://github.com/ansible-collections/community.general/pull/5970).
|
||||
- ssh_config - vendored StormSSH's config parser to avoid having to install
|
||||
StormSSH to use the module (https://github.com/ansible-collections/community.general/pull/6117).
|
||||
- znode module - optional ``use_tls`` parameter added for encrypted communication
|
||||
(https://github.com/ansible-collections/community.general/issues/6154).
|
||||
release_summary: Feature and bugfix release.
|
||||
fragments:
|
||||
- 3216-nmcli-bridge-idempotency-fix.yml
|
||||
- 3935-add-gitlab-group-runner.yml
|
||||
- 4387-nmcli-mtu-for-vlan-connection-fix.yml
|
||||
- 5664-redhat_subscription-credentials-when-needed.yaml
|
||||
- 5867-apt_rpm-add-clean-and-upgrade.yml
|
||||
- 5970-add-proxyjump-option-to-ssh-config.yml
|
||||
- 5974-nmcli_add_new_addr_gen_mode6_options.yml
|
||||
- 6.5.0.yml
|
||||
- 6049-dconf-strings.yml
|
||||
- 6065-nmcli-add-runner-fast-rate-option.yml
|
||||
- 6106-nmcli-ipv4-mayfail-idempotency-fix.yml
|
||||
- 6111-influxdb_user-check-mode.yaml
|
||||
- 6112-fix_key_error_in_gitlab_runner_creation_update.yml
|
||||
- 6114-memset-add-url-error-handling.yml
|
||||
- 6117-remove-stormssh-depend.yml
|
||||
- 6118-jail-plugin-fix-default-inventory_hostname.yml
|
||||
- 6119-opkg-update.yaml
|
||||
- 6122-redhat_subscription-subscribe-via-dbus.yaml
|
||||
- 6127-yarn-ignore-warnings.yml
|
||||
- 6131-fix-interfaces_file-for-no-leading-spaces.yml
|
||||
- 6138-fix-yarn-global.yml
|
||||
- 6149-openbsd_pkg-term.yml
|
||||
- 6154-znode-optional-tls.yml
|
||||
- 6158-create-proxmox-vm-from-archive.yml
|
||||
- 6160-add-command-make-output.yml
|
||||
- 6165-nmap-port.yml
|
||||
- 6180-replace-deprecated-badzipfile.yml
|
||||
- 6198-pipx-inject-install-apps.yml
|
||||
- 6200-adding-open-option-to-nmap.yml
|
||||
- 6208-hpe-thermal-fan-percent.yaml
|
||||
- 6210-add-worklog-functionality-to-jira.yml
|
||||
- 6211-rhsm-require-root.yml
|
||||
- 6227-xen-orchestra-check-response-id.yml
|
||||
- xxxx-ldap-ca-cert-file.yml
|
||||
modules:
|
||||
- description: Manage KDE configuration files
|
||||
name: kdeconfig
|
||||
namespace: ''
|
||||
plugins:
|
||||
lookup:
|
||||
- description: merge variables with a certain suffix
|
||||
name: merge_variables
|
||||
namespace: null
|
||||
release_date: '2023-03-27'
|
||||
6.6.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- archive - reduce RAM usage by generating CRC32 checksum over chunks (https://github.com/ansible-collections/community.general/pull/6274).
|
||||
- flatpak - fixes idempotency detection issues. In some cases the module could
|
||||
fail to properly detect already existing Flatpaks because of a parameter witch
|
||||
only checks the installed apps (https://github.com/ansible-collections/community.general/pull/6289).
|
||||
- icinga2_host - fix the data structure sent to Icinga to make use of host templates
|
||||
and template vars (https://github.com/ansible-collections/community.general/pull/6286).
|
||||
- idrac_redfish_command - allow user to specify ``resource_id`` for ``CreateBiosConfigJob``
|
||||
to specify an exact manager (https://github.com/ansible-collections/community.general/issues/2090).
|
||||
- ini_file - make ``section`` parameter not required so it is possible to pass
|
||||
``null`` as a value. This only was possible in the past due to a bug in ansible-core
|
||||
that now has been fixed (https://github.com/ansible-collections/community.general/pull/6404).
|
||||
- keycloak - improve error messages (https://github.com/ansible-collections/community.general/pull/6318).
|
||||
- one_vm - fix syntax error when creating VMs with a more complex template (https://github.com/ansible-collections/community.general/issues/6225).
|
||||
- pipx - fixed handling of ``install_deps=true`` with ``state=latest`` and ``state=upgrade``
|
||||
(https://github.com/ansible-collections/community.general/pull/6303).
|
||||
- redhat_subscription - do not use D-Bus for registering when ``environment``
|
||||
is specified, so it possible to specify again the environment names for registering,
|
||||
as the D-Bus APIs work only with IDs (https://github.com/ansible-collections/community.general/pull/6319).
|
||||
- redhat_subscription - try to unregister only when already registered when
|
||||
``force_register`` is specified (https://github.com/ansible-collections/community.general/issues/6258,
|
||||
https://github.com/ansible-collections/community.general/pull/6259).
|
||||
- redhat_subscription - use the right D-Bus options for environments when registering
|
||||
a CentOS Stream 8 system and using ``environment`` (https://github.com/ansible-collections/community.general/pull/6275).
|
||||
- rhsm_release - make ``release`` parameter not required so it is possible to
|
||||
pass ``null`` as a value. This only was possible in the past due to a bug
|
||||
in ansible-core that now has been fixed (https://github.com/ansible-collections/community.general/pull/6401).
|
||||
- rundeck module utils - fix errors caused by the API empty responses (https://github.com/ansible-collections/community.general/pull/6300)
|
||||
- rundeck_acl_policy - fix ``TypeError - byte indices must be integers or slices,
|
||||
not str`` error caused by empty API response. Update the module to use ``module_utils.rundeck``
|
||||
functions (https://github.com/ansible-collections/community.general/pull/5887,
|
||||
https://github.com/ansible-collections/community.general/pull/6300).
|
||||
- rundeck_project - update the module to use ``module_utils.rundeck`` functions
|
||||
(https://github.com/ansible-collections/community.general/issues/5742) (https://github.com/ansible-collections/community.general/pull/6300)
|
||||
- snap_alias - module would only recognize snap names containing letter, numbers
|
||||
or the underscore character, failing to identify valid snap names such as
|
||||
``lxd.lxc`` (https://github.com/ansible-collections/community.general/pull/6361).
|
||||
minor_changes:
|
||||
- cpanm - minor change, use feature from ``ModuleHelper`` (https://github.com/ansible-collections/community.general/pull/6385).
|
||||
- 'dconf - be forgiving about boolean values: convert them to GVariant booleans
|
||||
automatically (https://github.com/ansible-collections/community.general/pull/6206).'
|
||||
- dconf - minor refactoring improving parameters and dependencies validation
|
||||
(https://github.com/ansible-collections/community.general/pull/6336).
|
||||
- deps module utils - add function ``failed()`` providing the ability to check
|
||||
the dependency check result without triggering an exception (https://github.com/ansible-collections/community.general/pull/6383).
|
||||
- dig lookup plugin - Support multiple domains to be queried as indicated in
|
||||
docs (https://github.com/ansible-collections/community.general/pull/6334).
|
||||
- gitlab_project - add new option ``topics`` for adding topics to GitLab projects
|
||||
(https://github.com/ansible-collections/community.general/pull/6278).
|
||||
- homebrew_cask - allows passing ``--greedy`` option to ``upgrade_all`` (https://github.com/ansible-collections/community.general/pull/6267).
|
||||
- idrac_redfish_command - add ``job_id`` to ``CreateBiosConfigJob`` response
|
||||
(https://github.com/ansible-collections/community.general/issues/5603).
|
||||
- ipa_hostgroup - add ``append`` parameter for adding a new hosts to existing
|
||||
hostgroups without changing existing hostgroup members (https://github.com/ansible-collections/community.general/pull/6203).
|
||||
- keycloak_authentication - add flow type option to sub flows to allow the creation
|
||||
of 'form-flow' sub flows like in Keycloak's built-in registration flow (https://github.com/ansible-collections/community.general/pull/6318).
|
||||
- mksysb - improved the output of the module in case of errors (https://github.com/ansible-collections/community.general/issues/6263).
|
||||
- nmap inventory plugin - added environment variables for configure ``address``
|
||||
and ``exclude`` (https://github.com/ansible-collections/community.general/issues/6351).
|
||||
- nmcli - add ``macvlan`` connection type (https://github.com/ansible-collections/community.general/pull/6312).
|
||||
- pipx - add ``system_site_packages`` parameter to give application access to
|
||||
system-wide packages (https://github.com/ansible-collections/community.general/pull/6308).
|
||||
- pipx - ensure ``include_injected`` parameter works with ``state=upgrade``
|
||||
and ``state=latest`` (https://github.com/ansible-collections/community.general/pull/6212).
|
||||
- puppet - add new options ``skip_tags`` to exclude certain tagged resources
|
||||
during a puppet agent or apply (https://github.com/ansible-collections/community.general/pull/6293).
|
||||
- terraform - remove state file check condition and error block, because in
|
||||
the native implementation of terraform will not cause errors due to the non-existent
|
||||
file (https://github.com/ansible-collections/community.general/pull/6296).
|
||||
- udm_dns_record - minor refactor to the code (https://github.com/ansible-collections/community.general/pull/6382).
|
||||
release_summary: Bugfix and feature release.
|
||||
fragments:
|
||||
- 2090-idrac-redfish-resource-id-fix.yml
|
||||
- 5603-redfish-idrac-job-id-in-response.yml
|
||||
- 6.6.0.yml
|
||||
- 6199-archive-generate-checksum-in-chunks.yml
|
||||
- 6203-add-append-option-to-ipa-hostgroup.yml
|
||||
- 6206-dconf-booleans.yml
|
||||
- 6212-pipx-include-injected.yml
|
||||
- 6259-redhat_subscription-fix-force.yaml
|
||||
- 6267-homebrew-cask-upgrade-all-greedy.yml
|
||||
- 6269-mksysb-output.yml
|
||||
- 6275-redhat_subscription-fix-environments-centos.yaml
|
||||
- 6277-add-topics-gitlab-project.yml
|
||||
- 6286-icinga2_host-template-and-template-vars.yml
|
||||
- 6289-bugfix-flatpak-check-if-already-installed.yml
|
||||
- 6293-add-puppet-skip-tags-option.yaml
|
||||
- 6294-fix-one_vm-instantiation.yml
|
||||
- 6296-LanceNero-Terraform_statefile_check.yml
|
||||
- 6300-rundeck-modules-fixes-and-improvements.yml
|
||||
- 6303-pipx-fix-state-latest-and-add-system-site-packages.yml
|
||||
- 6308-pipx-add-system-site-packages.yml
|
||||
- 6312-nmcli-add-macvlan-connection-type.yml
|
||||
- 6318-add-form-flow.yml
|
||||
- 6319-redhat_subscription-fix-environment-parameter.yaml
|
||||
- 6334-dig-support-multiple-domains.yml
|
||||
- 6336-dconf-refactor.yml
|
||||
- 6351-support-env-variables-to-nmap-dynamic-inventoiry.yaml
|
||||
- 6361-snap-alias-regex-bugfix.yml
|
||||
- 6382-udm-dns-record-refactor.yml
|
||||
- 6383-deps-failed.yml
|
||||
- 6385-cpan-mh-feat.yml
|
||||
- 6401-rhsm_release-required.yml
|
||||
- 6404-ini_file-section.yml
|
||||
modules:
|
||||
- description: Query btrfs filesystem info
|
||||
name: btrfs_info
|
||||
namespace: ''
|
||||
- description: Manage btrfs subvolumes
|
||||
name: btrfs_subvolume
|
||||
namespace: ''
|
||||
- description: Manages Out-Of-Band controllers using Redfish APIs
|
||||
name: ilo_redfish_command
|
||||
namespace: ''
|
||||
- description: Allows administration of Keycloak client authorization scopes via
|
||||
Keycloak API
|
||||
name: keycloak_authz_authorization_scope
|
||||
namespace: ''
|
||||
- description: Set the type of aclientscope in realm or client via Keycloak API
|
||||
name: keycloak_clientscope_type
|
||||
namespace: ''
|
||||
release_date: '2023-04-24'
|
||||
6.6.1:
|
||||
changes:
|
||||
bugfixes:
|
||||
- deps module utils - do not fail when dependency cannot be found (https://github.com/ansible-collections/community.general/pull/6479).
|
||||
- nmcli - fix bond option ``xmit_hash_policy`` (https://github.com/ansible-collections/community.general/pull/6527).
|
||||
- passwordstore lookup plugin - make compatible with ansible-core 2.16 (https://github.com/ansible-collections/community.general/pull/6447).
|
||||
- portage - fix ``changed_use`` and ``newuse`` not triggering rebuilds (https://github.com/ansible-collections/community.general/issues/6008,
|
||||
https://github.com/ansible-collections/community.general/pull/6548).
|
||||
- 'portage - update the logic for generating the emerge command arguments to
|
||||
ensure that ``withbdeps: false`` results in a passing an ``n`` argument with
|
||||
the ``--with-bdeps`` emerge flag (https://github.com/ansible-collections/community.general/issues/6451,
|
||||
https://github.com/ansible-collections/community.general/pull/6456).'
|
||||
- proxmox_tasks_info - remove ``api_user`` + ``api_password`` constraint from
|
||||
``required_together`` as it causes to require ``api_password`` even when API
|
||||
token param is used (https://github.com/ansible-collections/community.general/issues/6201).
|
||||
- puppet - handling ``noop`` parameter was not working at all, now it is has
|
||||
been fixed (https://github.com/ansible-collections/community.general/issues/6452,
|
||||
https://github.com/ansible-collections/community.general/issues/6458).
|
||||
- terraform - fix broken ``warn()`` call (https://github.com/ansible-collections/community.general/pull/6497).
|
||||
- xfs_quota - in case of a project quota, the call to ``xfs_quota`` did not
|
||||
initialize/reset the project (https://github.com/ansible-collections/community.general/issues/5143).
|
||||
- zypper - added handling of zypper exitcode 102. Changed state is set correctly
|
||||
now and rc 102 is still preserved to be evaluated by the playbook (https://github.com/ansible-collections/community.general/pull/6534).
|
||||
minor_changes:
|
||||
- dconf - if ``gi.repository.GLib`` is missing, try to respawn in a Python interpreter
|
||||
that has it (https://github.com/ansible-collections/community.general/pull/6491).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 5143-fix-xfs-quota-project-init.yml
|
||||
- 6.6.1.yml
|
||||
- 6456-fix-portage-withbdeps-false.yml
|
||||
- 6458-puppet-noop.yml
|
||||
- 6491-dconf-respawn.yml
|
||||
- 6497-terraform-fix.yml
|
||||
- 6527-nmcli-bond-fix-xmit_hash_policy.yml
|
||||
- 6534-zypper-exitcode-102-handled.yaml
|
||||
- 6548-portage-changed_use-newuse.yml
|
||||
- 6554-proxmox-tasks-info-fix-required-password.yaml
|
||||
- deps.yml
|
||||
- passwordstore-lock.yml
|
||||
release_date: '2023-05-22'
|
||||
6.6.2:
|
||||
changes:
|
||||
bugfixes:
|
||||
- csv module utils - detects and remove unicode BOM markers from incoming CSV
|
||||
content (https://github.com/ansible-collections/community.general/pull/6662).
|
||||
- gitlab_group - the module passed parameters to the API call even when not
|
||||
set. The module is now filtering out ``None`` values to remediate this (https://github.com/ansible-collections/community.general/pull/6712).
|
||||
- ini_file - fix a bug where the inactive options were not used when possible
|
||||
(https://github.com/ansible-collections/community.general/pull/6575).
|
||||
- keycloak module utils - fix ``is_struct_included`` handling of lists of lists/dictionaries
|
||||
(https://github.com/ansible-collections/community.general/pull/6688).
|
||||
- keycloak module utils - the function ``get_user_by_username`` now return the
|
||||
user representation or ``None`` as stated in the documentation (https://github.com/ansible-collections/community.general/pull/6758).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 6.6.2.yml
|
||||
- 6568-fix-get-user-by-username-in-keycloak-module-utils.yml
|
||||
- 6662-csv-bom.yml
|
||||
- 6688-is-struct-included-bug-in-keycloak-py.yml
|
||||
- 6712-gitlab_group-filtered-for-none-values.yml
|
||||
- ini_file-use-inactive-options-when-possible.yml
|
||||
release_date: '2023-06-19'
|
||||
6.6.3:
|
||||
changes:
|
||||
bugfixes:
|
||||
- datadog_downtime - presence of ``rrule`` param lead to the Datadog API returning
|
||||
Bad Request due to a missing recurrence type (https://github.com/ansible-collections/community.general/pull/6811).
|
||||
- icinga2_host - fix a key error when updating an existing host (https://github.com/ansible-collections/community.general/pull/6748).
|
||||
- ipa_dnszone - fix 'idnsallowsyncptr' key error for reverse zone (https://github.com/ansible-collections/community.general/pull/6906,
|
||||
https://github.com/ansible-collections/community.general/issues/6905).
|
||||
- locale_gen - now works for locales without the underscore character such as
|
||||
``C.UTF-8`` (https://github.com/ansible-collections/community.general/pull/6774,
|
||||
https://github.com/ansible-collections/community.general/issues/5142, https://github.com/ansible-collections/community.general/issues/4305).
|
||||
- machinectl become plugin - mark plugin as ``require_tty`` to automatically
|
||||
disable pipelining, with which this plugin is not compatible (https://github.com/ansible-collections/community.general/issues/6932,
|
||||
https://github.com/ansible-collections/community.general/pull/6935).
|
||||
- nmcli - fix support for empty list (in compare and scrape) (https://github.com/ansible-collections/community.general/pull/6769).
|
||||
- openbsd_pkg - the pkg_info(1) behavior has changed in OpenBSD >7.3. The error
|
||||
message ``Can't find`` should not lead to an error case (https://github.com/ansible-collections/community.general/pull/6785).
|
||||
- pacman - module recognizes the output of ``yay`` running as ``root`` (https://github.com/ansible-collections/community.general/pull/6713).
|
||||
- proxmox - fix error when a configuration had no ``template`` field (https://github.com/ansible-collections/community.general/pull/6838,
|
||||
https://github.com/ansible-collections/community.general/issues/5372).
|
||||
- proxmox module utils - add logic to detect whether an old Promoxer complains
|
||||
about the ``token_name`` and ``token_value`` parameters and provide a better
|
||||
error message when that happens (https://github.com/ansible-collections/community.general/pull/6839,
|
||||
https://github.com/ansible-collections/community.general/issues/5371).
|
||||
- proxmox_disk - fix unable to create ``cdrom`` media due to ``size`` always
|
||||
being appended (https://github.com/ansible-collections/community.general/pull/6770).
|
||||
- proxmox_kvm - ``absent`` state with ``force`` specified failed to stop the
|
||||
VM due to the ``timeout`` value not being passed to ``stop_vm`` (https://github.com/ansible-collections/community.general/pull/6827).
|
||||
- redfish_info - fix ``ListUsers`` to not show empty account slots (https://github.com/ansible-collections/community.general/issues/6771,
|
||||
https://github.com/ansible-collections/community.general/pull/6772).
|
||||
- refish_utils module utils - changing variable names to avoid issues occuring
|
||||
when fetching Volumes data (https://github.com/ansible-collections/community.general/pull/6883).
|
||||
- 'rhsm_repository - when using the ``purge`` option, the ``repositories``
|
||||
|
||||
dictionary element in the returned JSON is now properly updated according
|
||||
|
||||
to the pruning operation
|
||||
|
||||
(https://github.com/ansible-collections/community.general/pull/6676).
|
||||
|
||||
'
|
||||
minor_changes:
|
||||
- cobbler inventory plugin - convert Ansible unicode strings to native Python
|
||||
unicode strings before passing user/password to XMLRPC client (https://github.com/ansible-collections/community.general/pull/6923).
|
||||
- redfish_info - fix for ``GetVolumeInventory``, Controller name was getting
|
||||
populated incorrectly and duplicates were seen in the volumes retrieved (https://github.com/ansible-collections/community.general/pull/6719).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 6.6.3.yml
|
||||
- 6676-rhsm_repository-fix-returned-repositories-with-purge.yml
|
||||
- 6713-yay-become.yml
|
||||
- 6719-redfish-utils-fix-for-get-volume-inventory.yml
|
||||
- 6748-icinga2_host-datafix.yml
|
||||
- 6769-nmcli-fix-empty-list.yml
|
||||
- 6770-proxmox_disk_create_cdrom.yml
|
||||
- 6771-redfish-filter-empty-account-slots.yml
|
||||
- 6774-locale-gen-fix.yml
|
||||
- 6785-openbsd_pkg_pkg_info_handling.yml
|
||||
- 6811-datadog-downtime-rrule-type.yaml
|
||||
- 6827-proxmox_kvm-force-delete-bug-fix.yaml
|
||||
- 6838-proxmox-dict-template.yml
|
||||
- 6839-promoxer-tokens.yml
|
||||
- 6883-redfish-utils-changing-variable-names-in-get-volume-inventory.yml
|
||||
- 6905-ipa_dnszone-key-error-fix.yml
|
||||
- 6923-cobbler-inventory_unicode.yml
|
||||
- 6935-machinectl-become.yml
|
||||
release_date: '2023-07-16'
|
||||
6.6.4:
|
||||
changes:
|
||||
bugfixes:
|
||||
- bitwarden lookup plugin - the plugin made assumptions about the structure
|
||||
of a Bitwarden JSON object which may have been broken by an update in the
|
||||
Bitwarden API. Remove assumptions, and allow queries for general fields such
|
||||
as ``notes`` (https://github.com/ansible-collections/community.general/pull/7061).
|
||||
- cmd_runner module utils - when a parameter in ``argument_spec`` has no type,
|
||||
meaning it is implicitly a ``str``, ``CmdRunner`` would fail trying to find
|
||||
the ``type`` key in that dictionary (https://github.com/ansible-collections/community.general/pull/6968).
|
||||
- ejabberd_user - module was failing to detect whether user was already created
|
||||
and/or password was changed (https://github.com/ansible-collections/community.general/pull/7033).
|
||||
- ejabberd_user - provide meaningful error message when the ``ejabberdctl``
|
||||
command is not found (https://github.com/ansible-collections/community.general/pull/7028,
|
||||
https://github.com/ansible-collections/community.general/issues/6949).
|
||||
- oci_utils module utils - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
|
||||
- proxmox module utils - fix proxmoxer library version check (https://github.com/ansible-collections/community.general/issues/6974,
|
||||
https://github.com/ansible-collections/community.general/issues/6975, https://github.com/ansible-collections/community.general/pull/6980).
|
||||
- proxmox_kvm - when ``name`` option is provided without ``vmid`` and VM with
|
||||
that name already exists then no new VM will be created (https://github.com/ansible-collections/community.general/issues/6911,
|
||||
https://github.com/ansible-collections/community.general/pull/6981).
|
||||
- proxmox_user_info - avoid direct type comparisons (https://github.com/ansible-collections/community.general/pull/7085).
|
||||
- rundeck - fix ``TypeError`` on 404 API response (https://github.com/ansible-collections/community.general/pull/6983).
|
||||
minor_changes:
|
||||
- redfish_utils - use ``Controllers`` key in redfish data to obtain Storage
|
||||
controllers properties (https://github.com/ansible-collections/community.general/pull/7081).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 6.6.4.yml
|
||||
- 6949-ejabberdctl-error.yml
|
||||
- 6968-cmdrunner-implicit-type.yml
|
||||
- 6980-proxmox-fix-token-auth.yml
|
||||
- 6981-proxmox-fix-vm-creation-when-only-name-provided.yml
|
||||
- 6983-rundeck-fix-typerrror-on-404-api-response.yml
|
||||
- 7033-ejabberd-user-bugs.yml
|
||||
- 7061-fix-bitwarden-get_field.yml
|
||||
- 7081-redfish-utils-fix-for-storagecontrollers-deprecated-key.yaml
|
||||
- 7085-sanity.yml
|
||||
release_date: '2023-08-13'
|
||||
6.6.5:
|
||||
changes:
|
||||
bugfixes:
|
||||
- CmdRunner module utils - does not attempt to resolve path if executable is
|
||||
a relative or absolute path (https://github.com/ansible-collections/community.general/pull/7200).
|
||||
- lxc connection plugin - now handles ``remote_addr`` defaulting to ``inventory_hostname``
|
||||
correctly (https://github.com/ansible-collections/community.general/pull/7104).
|
||||
- nsupdate - fix a possible ``list index out of range`` exception (https://github.com/ansible-collections/community.general/issues/836).
|
||||
- oci_utils module util - fix inappropriate logical comparison expressions and
|
||||
makes them simpler. The previous checks had logical short circuits (https://github.com/ansible-collections/community.general/pull/7125).
|
||||
- pritunl module utils - fix incorrect URL parameter for orgnization add method
|
||||
(https://github.com/ansible-collections/community.general/pull/7161).
|
||||
minor_changes:
|
||||
- make - allows ``params`` to be used without value (https://github.com/ansible-collections/community.general/pull/7180).
|
||||
- pritunl module utils - ensure ``validate_certs`` parameter is honoured in
|
||||
all methods (https://github.com/ansible-collections/community.general/pull/7156).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 6.6.5.yml
|
||||
- 7104_fix_lxc_remoteaddr_default.yml
|
||||
- 7125-fix-inappropriate-comparison.yml
|
||||
- 7156-ensure-validate-certs-parameter-is-honoured.yml
|
||||
- 7161-fix-incorrect-post-parameter.yml
|
||||
- 7180-make_params_without_value.yml
|
||||
- 7200-cmd-runner-abs-path.yml
|
||||
- 7219-fix-nsupdate-cname.yaml
|
||||
release_date: '2023-09-11'
|
||||
6.6.6:
|
||||
changes:
|
||||
bugfixes:
|
||||
- mail - skip headers containing equals characters due to missing ``maxsplit``
|
||||
on header key/value parsing (https://github.com/ansible-collections/community.general/pull/7303).
|
||||
- onepassword - fix KeyError exception when trying to access value of a field
|
||||
that is not filled out in OnePassword item (https://github.com/ansible-collections/community.general/pull/7241).
|
||||
- terraform - prevents ``-backend-config`` option double encapsulating with
|
||||
``shlex_quote`` function. (https://github.com/ansible-collections/community.general/pull/7301).
|
||||
release_summary: Regular bugfix release.
|
||||
fragments:
|
||||
- 6.6.6.yml
|
||||
- 7241-prevent-key-error-when-value-does-not-exist.yml
|
||||
- 7301-fix-backend-config-string-encapsulation.yml
|
||||
- 7303-mail-incorrect-header-parsing.yml
|
||||
release_date: '2023-10-08'
|
||||
6.6.7:
|
||||
changes:
|
||||
bugfixes:
|
||||
- composer - fix impossible to run ``working_dir`` dependent commands. The module
|
||||
was throwing an error when trying to run a ``working_dir`` dependent command,
|
||||
because it tried to get the command help without passing the ``working_dir``
|
||||
(https://github.com/ansible-collections/community.general/issues/3787).
|
||||
- github_deploy_key - fix pagination behaviour causing a crash when only a single
|
||||
page of deploy keys exist (https://github.com/ansible-collections/community.general/pull/7375).
|
||||
- gitlab_group_members - fix gitlab constants call in ``gitlab_group_members``
|
||||
module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_project_members - fix gitlab constants call in ``gitlab_project_members``
|
||||
module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_protected_branches - fix gitlab constants call in ``gitlab_protected_branches``
|
||||
module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- gitlab_user - fix gitlab constants call in ``gitlab_user`` module (https://github.com/ansible-collections/community.general/issues/7467).
|
||||
- lxc connection plugin - properly evaluate options (https://github.com/ansible-collections/community.general/pull/7369).
|
||||
- memset module utils - make compatible with ansible-core 2.17 (https://github.com/ansible-collections/community.general/pull/7379).
|
||||
- 'redhat_subscription - use the right D-Bus options for the consumer type when
|
||||
|
||||
registering a RHEL system older than 9 or a RHEL 9 system older than 9.2
|
||||
|
||||
and using ``consumer_type``
|
||||
|
||||
(https://github.com/ansible-collections/community.general/pull/7378).
|
||||
|
||||
'
|
||||
- selective callback plugin - fix length of task name lines in output always
|
||||
being 3 characters longer than desired (https://github.com/ansible-collections/community.general/pull/7374).
|
||||
release_summary: 'Bugfix release.
|
||||
|
||||
|
||||
From now on, community.general 6.x.y will only receive major bugfixes and
|
||||
security fixes anymore.
|
||||
|
||||
'
|
||||
fragments:
|
||||
- 3787-pass-composer-working-dir.yml
|
||||
- 6.6.7.yml
|
||||
- 7369-fix-lxc-options.yml
|
||||
- 7374-fix-selective-callback-taskname-length.yml
|
||||
- 7375-fix-github-deploy-key-pagination.yml
|
||||
- 7378-redhat_subscription-dbus-consumer-type.yaml
|
||||
- 7379-url.yml
|
||||
- 7467-fix-gitlab-constants-calls.yml
|
||||
release_date: '2023-11-04'
|
||||
6.6.8:
|
||||
changes:
|
||||
bugfixes:
|
||||
- aix_filesystem - fix issue with empty list items in crfs logic and option
|
||||
order (https://github.com/ansible-collections/community.general/pull/8052).
|
||||
- pacemaker_cluster - actually implement check mode, which the module claims
|
||||
to support. This means that until now the module also did changes in check
|
||||
mode (https://github.com/ansible-collections/community.general/pull/8081).
|
||||
- pam_limits - when the file does not exist, do not create it in check mode
|
||||
(https://github.com/ansible-collections/community.general/issues/8050, https://github.com/ansible-collections/community.general/pull/8057).
|
||||
release_summary: Security and bugfix release.
|
||||
security_fixes:
|
||||
- cobbler, gitlab_runners, icinga2, linode, lxd, nmap, online, opennebula, proxmox,
|
||||
scaleway, stackpath_compute, virtualbox, and xen_orchestra inventory plugin
|
||||
- make sure all data received from the remote servers is marked as unsafe,
|
||||
so remote code execution by obtaining texts that can be evaluated as templates
|
||||
is not possible (https://www.die-welt.net/2024/03/remote-code-execution-in-ansible-dynamic-inventory-plugins/,
|
||||
https://github.com/ansible-collections/community.general/pull/8098).
|
||||
fragments:
|
||||
- 6.6.8.yml
|
||||
- 8057-pam_limits-check-mode.yml
|
||||
- aix_filesystem-crfs-issue.yml
|
||||
- inventory-rce.yml
|
||||
- pacemaker-cluster.yml
|
||||
release_date: '2024-03-25'
|
||||
6.6.9:
|
||||
changes:
|
||||
bugfixes:
|
||||
- inventory plugins - add unsafe wrapper to avoid marking strings that do not
|
||||
contain ``{`` or ``}`` as unsafe, to work around a bug in AWX ((https://github.com/ansible-collections/community.general/issues/8212,
|
||||
https://github.com/ansible-collections/community.general/pull/8225).
|
||||
- xml - make module work with lxml 5.1.1, which removed some internals that
|
||||
the module was relying on (https://github.com/ansible-collections/community.general/pull/8169).
|
||||
release_summary: 'Maintenance release.
|
||||
|
||||
|
||||
This is the last 6.x.y release. The 6.x.y release train is now effectively
|
||||
End of Life.
|
||||
|
||||
Thanks to everyone who contributed to the community.general 6.x.y releases!
|
||||
|
||||
'
|
||||
security_fixes:
|
||||
- keycloak_identity_provider - the client secret was not correctly sanitized
|
||||
by the module. The return values ``proposed``, ``existing``, and ``end_state``,
|
||||
as well as the diff, did contain the client secret unmasked (https://github.com/ansible-collections/community.general/pull/8355).
|
||||
fragments:
|
||||
- 6.6.9.yml
|
||||
- 8169-lxml.yml
|
||||
- 8225-unsafe.yml
|
||||
- 8355-keycloak-idp-sanitize.yaml
|
||||
release_date: '2024-05-19'
|
||||
|
||||
@@ -12,6 +12,9 @@ mention_ancestor: true
|
||||
flatmap: true
|
||||
new_plugins_after_name: removed_features
|
||||
notesdir: fragments
|
||||
output_formats:
|
||||
- md
|
||||
- rst
|
||||
prelude_section_name: release_summary
|
||||
prelude_section_title: Release Summary
|
||||
sections:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 6.4.0
|
||||
version: 6.6.9
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -102,6 +102,7 @@ class BecomeModule(BecomeBase):
|
||||
prompt = 'Password: '
|
||||
fail = ('==== AUTHENTICATION FAILED ====',)
|
||||
success = ('==== AUTHENTICATION COMPLETE ====',)
|
||||
require_tty = True # see https://github.com/ansible-collections/community.general/issues/6932
|
||||
|
||||
@staticmethod
|
||||
def remove_ansi_codes(line):
|
||||
|
||||
@@ -115,8 +115,8 @@ class CallbackModule(CallbackBase):
|
||||
line_length = 120
|
||||
if self.last_skipped:
|
||||
print()
|
||||
msg = colorize("# {0} {1}".format(task_name,
|
||||
'*' * (line_length - len(task_name))), 'bold')
|
||||
line = "# {0} ".format(task_name)
|
||||
msg = colorize("{0}{1}".format(line, '*' * (line_length - len(line))), 'bold')
|
||||
print(msg)
|
||||
|
||||
def _indent_text(self, text, indent_level):
|
||||
|
||||
@@ -48,6 +48,27 @@ DOCUMENTATION = '''
|
||||
default: chroot
|
||||
'''
|
||||
|
||||
EXAMPLES = r"""
|
||||
# Plugin requires root privileges for chroot, -E preserves your env (and location of ~/.ansible):
|
||||
# sudo -E ansible-playbook ...
|
||||
#
|
||||
# Static inventory file
|
||||
# [chroots]
|
||||
# /path/to/debootstrap
|
||||
# /path/to/feboostrap
|
||||
# /path/to/lxc-image
|
||||
# /path/to/chroot
|
||||
|
||||
# playbook
|
||||
---
|
||||
- hosts: chroots
|
||||
connection: community.general.chroot
|
||||
tasks:
|
||||
- debug:
|
||||
msg: "This is coming from chroot environment"
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
@@ -22,6 +22,7 @@ DOCUMENTATION = '''
|
||||
- Path to the jail
|
||||
default: inventory_hostname
|
||||
vars:
|
||||
- name: inventory_hostname
|
||||
- name: ansible_host
|
||||
- name: ansible_jail_host
|
||||
remote_user:
|
||||
|
||||
@@ -19,6 +19,7 @@ DOCUMENTATION = '''
|
||||
- Container identifier
|
||||
default: inventory_hostname
|
||||
vars:
|
||||
- name: inventory_hostname
|
||||
- name: ansible_host
|
||||
- name: ansible_lxc_host
|
||||
executable:
|
||||
@@ -59,7 +60,7 @@ class Connection(ConnectionBase):
|
||||
def __init__(self, play_context, new_stdin, *args, **kwargs):
|
||||
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
|
||||
|
||||
self.container_name = self._play_context.remote_addr
|
||||
self.container_name = None
|
||||
self.container = None
|
||||
|
||||
def _connect(self):
|
||||
@@ -67,12 +68,14 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self)._connect()
|
||||
|
||||
if not HAS_LIBLXC:
|
||||
msg = "lxc bindings for python2 are not installed"
|
||||
msg = "lxc python bindings are not installed"
|
||||
raise errors.AnsibleError(msg)
|
||||
|
||||
if self.container:
|
||||
return
|
||||
|
||||
self.container_name = self.get_option('remote_addr')
|
||||
|
||||
self._display.vvv("THIS IS A LOCAL LXC DIR", host=self.container_name)
|
||||
self.container = _lxc.Container(self.container_name)
|
||||
if self.container.state == "STOPPED":
|
||||
@@ -117,7 +120,7 @@ class Connection(ConnectionBase):
|
||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
# python2-lxc needs bytes. python3-lxc needs text.
|
||||
executable = to_native(self._play_context.executable, errors='surrogate_or_strict')
|
||||
executable = to_native(self.get_option('executable'), errors='surrogate_or_strict')
|
||||
local_cmd = [executable, '-c', to_native(cmd, errors='surrogate_or_strict')]
|
||||
|
||||
read_stdout, write_stdout = None, None
|
||||
|
||||
@@ -24,6 +24,11 @@ options:
|
||||
- The password to use with I(bind_dn).
|
||||
type: str
|
||||
default: ''
|
||||
ca_path:
|
||||
description:
|
||||
- Set the path to PEM file with CA certs.
|
||||
type: path
|
||||
version_added: "6.5.0"
|
||||
dn:
|
||||
required: true
|
||||
description:
|
||||
|
||||
@@ -29,11 +29,13 @@ options:
|
||||
api_token_id:
|
||||
description:
|
||||
- Specify the token ID.
|
||||
- Requires C(proxmoxer>=1.1.0) to work.
|
||||
type: str
|
||||
version_added: 1.3.0
|
||||
api_token_secret:
|
||||
description:
|
||||
- Specify the token secret.
|
||||
- Requires C(proxmoxer>=1.1.0) to work.
|
||||
type: str
|
||||
version_added: 1.3.0
|
||||
validate_certs:
|
||||
|
||||
@@ -56,7 +56,7 @@ EXAMPLES = '''
|
||||
- name: Parse a CSV file's contents
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ csv_data | community.genera.from_csv(dialect='unix') }}
|
||||
{{ csv_data | community.general.from_csv(dialect='unix') }}
|
||||
vars:
|
||||
csv_data: |
|
||||
Column 1,Value
|
||||
|
||||
@@ -87,6 +87,9 @@ from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, to_safe_group_name
|
||||
from ansible.module_utils.six import text_type
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
# xmlrpc
|
||||
try:
|
||||
@@ -128,7 +131,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
|
||||
self.connection = xmlrpc_client.Server(self.cobbler_url, allow_none=True)
|
||||
self.token = None
|
||||
if self.get_option('user') is not None:
|
||||
self.token = self.connection.login(self.get_option('user'), self.get_option('password'))
|
||||
self.token = self.connection.login(text_type(self.get_option('user')), text_type(self.get_option('password')))
|
||||
return self.connection
|
||||
|
||||
def _init_cache(self):
|
||||
@@ -238,7 +241,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
|
||||
|
||||
for host in self._get_systems():
|
||||
# Get the FQDN for the host and add it to the right groups
|
||||
hostname = host['hostname'] # None
|
||||
hostname = make_unsafe(host['hostname']) # None
|
||||
interfaces = host['interfaces']
|
||||
|
||||
if self._exclude_profile(host['profile']):
|
||||
@@ -251,7 +254,7 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
|
||||
if ivalue['management'] or not ivalue['static']:
|
||||
this_dns_name = ivalue.get('dns_name', None)
|
||||
if this_dns_name is not None and this_dns_name != "":
|
||||
hostname = this_dns_name
|
||||
hostname = make_unsafe(this_dns_name)
|
||||
self.display.vvvv('Set hostname to %s from %s\n' % (hostname, iname))
|
||||
|
||||
if hostname == '':
|
||||
@@ -282,6 +285,6 @@ class InventoryModule(BaseInventoryPlugin, Cacheable):
|
||||
# Add host variables
|
||||
if self.get_option('want_facts'):
|
||||
try:
|
||||
self.inventory.set_variable(hostname, 'cobbler', host)
|
||||
self.inventory.set_variable(hostname, 'cobbler', make_unsafe(host))
|
||||
except ValueError as e:
|
||||
self.display.warning("Could not set host info for %s: %s" % (hostname, to_text(e)))
|
||||
|
||||
@@ -85,6 +85,8 @@ from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
try:
|
||||
import gitlab
|
||||
HAS_GITLAB = True
|
||||
@@ -106,11 +108,11 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
else:
|
||||
runners = gl.runners.all()
|
||||
for runner in runners:
|
||||
host = str(runner['id'])
|
||||
host = make_unsafe(str(runner['id']))
|
||||
ip_address = runner['ip_address']
|
||||
host_attrs = vars(gl.runners.get(runner['id']))['_attrs']
|
||||
host_attrs = make_unsafe(vars(gl.runners.get(runner['id']))['_attrs'])
|
||||
self.inventory.add_host(host, group='gitlab_runners')
|
||||
self.inventory.set_variable(host, 'ansible_host', ip_address)
|
||||
self.inventory.set_variable(host, 'ansible_host', make_unsafe(ip_address))
|
||||
if self.get_option('verbose_output', True):
|
||||
self.inventory.set_variable(host, 'gitlab_runner_attributes', host_attrs)
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
''' Host inventory parser for ansible using Icinga2 as source. '''
|
||||
@@ -233,15 +235,15 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
"""Convert Icinga2 API data to JSON format for Ansible"""
|
||||
groups_dict = {"_meta": {"hostvars": {}}}
|
||||
for entry in json_data:
|
||||
host_attrs = entry['attrs']
|
||||
host_attrs = make_unsafe(entry['attrs'])
|
||||
if self.inventory_attr == "name":
|
||||
host_name = entry.get('name')
|
||||
host_name = make_unsafe(entry.get('name'))
|
||||
if self.inventory_attr == "address":
|
||||
# When looking for address for inventory, if missing fallback to object name
|
||||
if host_attrs.get('address', '') != '':
|
||||
host_name = host_attrs.get('address')
|
||||
host_name = make_unsafe(host_attrs.get('address'))
|
||||
else:
|
||||
host_name = entry.get('name')
|
||||
host_name = make_unsafe(entry.get('name'))
|
||||
if self.inventory_attr == "display_name":
|
||||
host_name = host_attrs.get('display_name')
|
||||
if host_attrs['state'] == 0:
|
||||
@@ -257,7 +259,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
# If the address attribute is populated, override ansible_host with the value
|
||||
if host_attrs.get('address') != '':
|
||||
self.inventory.set_variable(host_name, 'ansible_host', host_attrs.get('address'))
|
||||
self.inventory.set_variable(host_name, 'hostname', entry.get('name'))
|
||||
self.inventory.set_variable(host_name, 'hostname', make_unsafe(entry.get('name')))
|
||||
self.inventory.set_variable(host_name, 'display_name', host_attrs.get('display_name'))
|
||||
self.inventory.set_variable(host_name, 'state',
|
||||
host_attrs['state'])
|
||||
|
||||
@@ -124,6 +124,8 @@ compose:
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
try:
|
||||
from linode_api4 import LinodeClient
|
||||
@@ -199,20 +201,21 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
def _add_instances_to_groups(self):
|
||||
"""Add instance names to their dynamic inventory groups."""
|
||||
for instance in self.instances:
|
||||
self.inventory.add_host(instance.label, group=instance.group)
|
||||
self.inventory.add_host(make_unsafe(instance.label), group=instance.group)
|
||||
|
||||
def _add_hostvars_for_instances(self):
|
||||
"""Add hostvars for instances in the dynamic inventory."""
|
||||
ip_style = self.get_option('ip_style')
|
||||
for instance in self.instances:
|
||||
hostvars = instance._raw_json
|
||||
hostname = make_unsafe(instance.label)
|
||||
for hostvar_key in hostvars:
|
||||
if ip_style == 'api' and hostvar_key in ['ipv4', 'ipv6']:
|
||||
continue
|
||||
self.inventory.set_variable(
|
||||
instance.label,
|
||||
hostname,
|
||||
hostvar_key,
|
||||
hostvars[hostvar_key]
|
||||
make_unsafe(hostvars[hostvar_key])
|
||||
)
|
||||
if ip_style == 'api':
|
||||
ips = instance.ips.ipv4.public + instance.ips.ipv4.private
|
||||
@@ -221,9 +224,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
for ip_type in set(ip.type for ip in ips):
|
||||
self.inventory.set_variable(
|
||||
instance.label,
|
||||
hostname,
|
||||
ip_type,
|
||||
self._ip_data([ip for ip in ips if ip.type == ip_type])
|
||||
make_unsafe(self._ip_data([ip for ip in ips if ip.type == ip_type]))
|
||||
)
|
||||
|
||||
def _ip_data(self, ip_list):
|
||||
@@ -254,21 +257,22 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self._add_instances_to_groups()
|
||||
self._add_hostvars_for_instances()
|
||||
for instance in self.instances:
|
||||
variables = self.inventory.get_host(instance.label).get_vars()
|
||||
hostname = make_unsafe(instance.label)
|
||||
variables = self.inventory.get_host(hostname).get_vars()
|
||||
self._add_host_to_composed_groups(
|
||||
self.get_option('groups'),
|
||||
variables,
|
||||
instance.label,
|
||||
hostname,
|
||||
strict=strict)
|
||||
self._add_host_to_keyed_groups(
|
||||
self.get_option('keyed_groups'),
|
||||
variables,
|
||||
instance.label,
|
||||
hostname,
|
||||
strict=strict)
|
||||
self._set_composite_vars(
|
||||
self.get_option('compose'),
|
||||
variables,
|
||||
instance.label,
|
||||
hostname,
|
||||
strict=strict)
|
||||
|
||||
def verify_file(self, path):
|
||||
|
||||
@@ -161,6 +161,7 @@ from ansible.module_utils.six import raise_from
|
||||
from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
try:
|
||||
import ipaddress
|
||||
@@ -656,7 +657,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
|
||||
if self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name)): # instance have network interfaces
|
||||
self.inventory.set_variable(instance_name, 'ansible_connection', 'ssh')
|
||||
self.inventory.set_variable(instance_name, 'ansible_host', interface_selection(instance_name))
|
||||
self.inventory.set_variable(instance_name, 'ansible_host', make_unsafe(interface_selection(instance_name)))
|
||||
else:
|
||||
self.inventory.set_variable(instance_name, 'ansible_connection', 'local')
|
||||
|
||||
@@ -682,31 +683,39 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if self.filter.lower() != instance_state:
|
||||
continue
|
||||
# add instance
|
||||
instance_name = make_unsafe(instance_name)
|
||||
self.inventory.add_host(instance_name)
|
||||
# add network informations
|
||||
self.build_inventory_network(instance_name)
|
||||
# add os
|
||||
v = self._get_data_entry('inventory/{0}/os'.format(instance_name))
|
||||
if v:
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_os', v.lower())
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_os', make_unsafe(v.lower()))
|
||||
# add release
|
||||
v = self._get_data_entry('inventory/{0}/release'.format(instance_name))
|
||||
if v:
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_release', v.lower())
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_release', make_unsafe(v.lower()))
|
||||
# add profile
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(instance_name)))
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_profile', make_unsafe(self._get_data_entry('inventory/{0}/profile'.format(instance_name))))
|
||||
# add state
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_state', instance_state)
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_state', make_unsafe(instance_state))
|
||||
# add type
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_type', self._get_data_entry('inventory/{0}/type'.format(instance_name)))
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_type', make_unsafe(self._get_data_entry('inventory/{0}/type'.format(instance_name))))
|
||||
# add location information
|
||||
if self._get_data_entry('inventory/{0}/location'.format(instance_name)) != "none": # wrong type by lxd 'none' != 'None'
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(instance_name)))
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_location', make_unsafe(self._get_data_entry('inventory/{0}/location'.format(instance_name))))
|
||||
# add VLAN_ID information
|
||||
if self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)):
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)))
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_vlan_ids', make_unsafe(self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name))))
|
||||
# add project
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_project', self._get_data_entry('inventory/{0}/project'.format(instance_name)))
|
||||
self.inventory.set_variable(
|
||||
instance_name, 'ansible_lxd_project', make_unsafe(self._get_data_entry('inventory/{0}/project'.format(instance_name))))
|
||||
|
||||
def build_inventory_groups_location(self, group_name):
|
||||
"""create group by attribute: location
|
||||
@@ -979,7 +988,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
for group_name in self.groupby:
|
||||
if not group_name.isalnum():
|
||||
raise AnsibleParserError('Invalid character(s) in groupname: {0}'.format(to_native(group_name)))
|
||||
group_type(group_name)
|
||||
group_type(make_unsafe(group_name))
|
||||
|
||||
def build_inventory(self):
|
||||
"""Build dynamic inventory
|
||||
|
||||
@@ -30,12 +30,27 @@ DOCUMENTATION = '''
|
||||
address:
|
||||
description: Network IP or range of IPs to scan, you can use a simple range (10.2.2.15-25) or CIDR notation.
|
||||
required: true
|
||||
env:
|
||||
- name: ANSIBLE_NMAP_ADDRESS
|
||||
version_added: 6.6.0
|
||||
exclude:
|
||||
description: list of addresses to exclude
|
||||
description:
|
||||
- List of addresses to exclude.
|
||||
- For example C(10.2.2.15-25) or C(10.2.2.15,10.2.2.16).
|
||||
type: list
|
||||
elements: string
|
||||
env:
|
||||
- name: ANSIBLE_NMAP_EXCLUDE
|
||||
version_added: 6.6.0
|
||||
port:
|
||||
description:
|
||||
- Only scan specific port or port range (C(-p)).
|
||||
- For example, you could pass C(22) for a single port, C(1-65535) for a range of ports,
|
||||
or C(U:53,137,T:21-25,139,8080,S:9) to check port 53 with UDP, ports 21-25 with TCP, port 9 with SCTP, and ports 137, 139, and 8080 with all.
|
||||
type: string
|
||||
version_added: 6.5.0
|
||||
ports:
|
||||
description: Enable/disable scanning for open ports
|
||||
description: Enable/disable scanning ports.
|
||||
type: boolean
|
||||
default: true
|
||||
ipv4:
|
||||
@@ -60,6 +75,11 @@ DOCUMENTATION = '''
|
||||
type: boolean
|
||||
default: false
|
||||
version_added: 6.1.0
|
||||
open:
|
||||
description: Only scan for open (or possibly open) ports.
|
||||
type: boolean
|
||||
default: false
|
||||
version_added: 6.5.0
|
||||
dns_resolve:
|
||||
description: Whether to always (C(true)) or never (C(false)) do DNS resolution.
|
||||
type: boolean
|
||||
@@ -81,6 +101,14 @@ plugin: community.general.nmap
|
||||
sudo: true
|
||||
strict: false
|
||||
address: 192.168.0.0/24
|
||||
|
||||
# an nmap scan specifying ports and classifying results to an inventory group
|
||||
plugin: community.general.nmap
|
||||
address: 192.168.0.0/24
|
||||
exclude: 192.168.0.1, web.example.com
|
||||
port: 22, 443
|
||||
groups:
|
||||
web_servers: "ports | selectattr('port', 'equalto', '443')"
|
||||
'''
|
||||
|
||||
import os
|
||||
@@ -94,6 +122,8 @@ from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
from ansible.module_utils.common.process import get_bin_path
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
@@ -110,6 +140,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
strict = self.get_option('strict')
|
||||
|
||||
for host in hosts:
|
||||
host = make_unsafe(host)
|
||||
hostname = host['name']
|
||||
self.inventory.add_host(hostname)
|
||||
for var, value in host.items():
|
||||
@@ -171,6 +202,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
if self._options['sudo']:
|
||||
cmd.insert(0, 'sudo')
|
||||
|
||||
if self._options['port']:
|
||||
cmd.append('-p')
|
||||
cmd.append(self._options['port'])
|
||||
|
||||
if not self._options['ports']:
|
||||
cmd.append('-sP')
|
||||
|
||||
@@ -194,6 +229,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
if self._options['icmp_timestamp']:
|
||||
cmd.append('-PP')
|
||||
|
||||
if self._options['open']:
|
||||
cmd.append('--open')
|
||||
|
||||
cmd.append(self._options['address'])
|
||||
try:
|
||||
# execute
|
||||
|
||||
@@ -69,6 +69,8 @@ from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.ansible_release import __version__ as ansible_version
|
||||
from ansible.module_utils.six.moves.urllib.parse import urljoin
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin):
|
||||
NAME = 'community.general.online'
|
||||
@@ -169,20 +171,20 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
"support"
|
||||
)
|
||||
for attribute in targeted_attributes:
|
||||
self.inventory.set_variable(hostname, attribute, host_infos[attribute])
|
||||
self.inventory.set_variable(hostname, attribute, make_unsafe(host_infos[attribute]))
|
||||
|
||||
if self.extract_public_ipv4(host_infos=host_infos):
|
||||
self.inventory.set_variable(hostname, "public_ipv4", self.extract_public_ipv4(host_infos=host_infos))
|
||||
self.inventory.set_variable(hostname, "ansible_host", self.extract_public_ipv4(host_infos=host_infos))
|
||||
self.inventory.set_variable(hostname, "public_ipv4", make_unsafe(self.extract_public_ipv4(host_infos=host_infos)))
|
||||
self.inventory.set_variable(hostname, "ansible_host", make_unsafe(self.extract_public_ipv4(host_infos=host_infos)))
|
||||
|
||||
if self.extract_private_ipv4(host_infos=host_infos):
|
||||
self.inventory.set_variable(hostname, "public_ipv4", self.extract_private_ipv4(host_infos=host_infos))
|
||||
self.inventory.set_variable(hostname, "public_ipv4", make_unsafe(self.extract_private_ipv4(host_infos=host_infos)))
|
||||
|
||||
if self.extract_os_name(host_infos=host_infos):
|
||||
self.inventory.set_variable(hostname, "os_name", self.extract_os_name(host_infos=host_infos))
|
||||
self.inventory.set_variable(hostname, "os_name", make_unsafe(self.extract_os_name(host_infos=host_infos)))
|
||||
|
||||
if self.extract_os_version(host_infos=host_infos):
|
||||
self.inventory.set_variable(hostname, "os_version", self.extract_os_name(host_infos=host_infos))
|
||||
self.inventory.set_variable(hostname, "os_version", make_unsafe(self.extract_os_name(host_infos=host_infos)))
|
||||
|
||||
def _filter_host(self, host_infos, hostname_preferences):
|
||||
|
||||
@@ -201,6 +203,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if not hostname:
|
||||
return
|
||||
|
||||
hostname = make_unsafe(hostname)
|
||||
|
||||
self.inventory.add_host(host=hostname)
|
||||
self._fill_host_variables(hostname=hostname, host_infos=host_infos)
|
||||
|
||||
@@ -210,6 +214,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if not group:
|
||||
return
|
||||
|
||||
group = make_unsafe(group)
|
||||
|
||||
self.inventory.add_group(group=group)
|
||||
self.inventory.add_host(group=group, host=hostname)
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
from collections import namedtuple
|
||||
import os
|
||||
|
||||
@@ -215,6 +217,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
filter_by_label = self.get_option('filter_by_label')
|
||||
servers = self._retrieve_servers(filter_by_label)
|
||||
for server in servers:
|
||||
server = make_unsafe(server)
|
||||
hostname = server['name']
|
||||
# check for labels
|
||||
if group_by_labels and server['LABELS']:
|
||||
|
||||
@@ -224,6 +224,7 @@ from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.utils.display import Display
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
# 3rd party imports
|
||||
try:
|
||||
@@ -330,7 +331,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
self._cache[self.cache_key][url] = data
|
||||
|
||||
return self._cache[self.cache_key][url]
|
||||
return make_unsafe(self._cache[self.cache_key][url])
|
||||
|
||||
def _get_nodes(self):
|
||||
return self._get_json("%s/api2/json/nodes" % self.proxmox_url)
|
||||
|
||||
@@ -121,6 +121,7 @@ else:
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, parse_pagination_link
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
from ansible.module_utils.six import raise_from
|
||||
@@ -279,7 +280,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
zone_info = SCALEWAY_LOCATION[zone]
|
||||
|
||||
url = _build_server_url(zone_info["api_endpoint"])
|
||||
raw_zone_hosts_infos = _fetch_information(url=url, token=token)
|
||||
raw_zone_hosts_infos = make_unsafe(_fetch_information(url=url, token=token))
|
||||
|
||||
for host_infos in raw_zone_hosts_infos:
|
||||
|
||||
@@ -341,4 +342,4 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
hostname_preference = self.get_option("hostnames")
|
||||
|
||||
for zone in self._get_zones(config_zones):
|
||||
self.do_zone_inventory(zone=zone, token=token, tags=tags, hostname_preferences=hostname_preference)
|
||||
self.do_zone_inventory(zone=make_unsafe(zone), token=token, tags=tags, hostname_preferences=hostname_preference)
|
||||
|
||||
@@ -73,6 +73,8 @@ from ansible.plugins.inventory import (
|
||||
)
|
||||
from ansible.utils.display import Display
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
display = Display()
|
||||
|
||||
@@ -271,7 +273,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
if not cache or cache_needs_update:
|
||||
results = self._query()
|
||||
|
||||
self._populate(results)
|
||||
self._populate(make_unsafe(results))
|
||||
|
||||
# If the cache has expired/doesn't exist or
|
||||
# if refresh_inventory/flush cache is used
|
||||
|
||||
@@ -63,6 +63,8 @@ from ansible.module_utils.common._collections_compat import MutableMapping
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
from ansible.module_utils.common.process import get_bin_path
|
||||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
''' Host inventory parser for ansible using local virtualbox. '''
|
||||
@@ -116,6 +118,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), hostvars[host], host, strict=strict)
|
||||
|
||||
def _populate_from_cache(self, source_data):
|
||||
source_data = make_unsafe(source_data)
|
||||
hostvars = source_data.pop('_meta', {}).get('hostvars', {})
|
||||
for group in source_data:
|
||||
if group == 'all':
|
||||
@@ -162,7 +165,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
v = v.strip()
|
||||
# found host
|
||||
if k.startswith('Name') and ',' not in v: # some setting strings appear in Name
|
||||
current_host = v
|
||||
current_host = make_unsafe(v)
|
||||
if current_host not in hostvars:
|
||||
hostvars[current_host] = {}
|
||||
self.inventory.add_host(current_host)
|
||||
@@ -170,12 +173,13 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
# try to get network info
|
||||
netdata = self._query_vbox_data(current_host, netinfo)
|
||||
if netdata:
|
||||
self.inventory.set_variable(current_host, 'ansible_host', netdata)
|
||||
self.inventory.set_variable(current_host, 'ansible_host', make_unsafe(netdata))
|
||||
|
||||
# found groups
|
||||
elif k == 'Groups':
|
||||
for group in v.split('/'):
|
||||
if group:
|
||||
group = make_unsafe(group)
|
||||
group = self.inventory.add_group(group)
|
||||
self.inventory.add_child(group, current_host)
|
||||
if group not in cacheable_results:
|
||||
@@ -185,17 +189,17 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
else:
|
||||
# found vars, accumulate in hostvars for clean inventory set
|
||||
pref_k = 'vbox_' + k.strip().replace(' ', '_')
|
||||
pref_k = make_unsafe('vbox_' + k.strip().replace(' ', '_'))
|
||||
leading_spaces = len(k) - len(k.lstrip(' '))
|
||||
if 0 < leading_spaces <= 2:
|
||||
if prevkey not in hostvars[current_host] or not isinstance(hostvars[current_host][prevkey], dict):
|
||||
hostvars[current_host][prevkey] = {}
|
||||
hostvars[current_host][prevkey][pref_k] = v
|
||||
hostvars[current_host][prevkey][pref_k] = make_unsafe(v)
|
||||
elif leading_spaces > 2:
|
||||
continue
|
||||
else:
|
||||
if v != '':
|
||||
hostvars[current_host][pref_k] = v
|
||||
hostvars[current_host][pref_k] = make_unsafe(v)
|
||||
if self._ungrouped_host(current_host, cacheable_results):
|
||||
if 'ungrouped' not in cacheable_results:
|
||||
cacheable_results['ungrouped'] = {'hosts': []}
|
||||
|
||||
@@ -78,11 +78,13 @@ compose:
|
||||
|
||||
import json
|
||||
import ssl
|
||||
from time import sleep
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
|
||||
|
||||
# 3rd party imports
|
||||
try:
|
||||
@@ -138,21 +140,42 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self.conn = create_connection(
|
||||
'{0}://{1}/api/'.format(proto, xoa_api_host), sslopt=sslopt)
|
||||
|
||||
CALL_TIMEOUT = 100
|
||||
"""Number of 1/10ths of a second to wait before method call times out."""
|
||||
|
||||
def call(self, method, params):
|
||||
"""Calls a method on the XO server with the provided parameters."""
|
||||
id = self.pointer
|
||||
self.conn.send(json.dumps({
|
||||
'id': id,
|
||||
'jsonrpc': '2.0',
|
||||
'method': method,
|
||||
'params': params
|
||||
}))
|
||||
|
||||
waited = 0
|
||||
while waited < self.CALL_TIMEOUT:
|
||||
response = json.loads(self.conn.recv())
|
||||
if 'id' in response and response['id'] == id:
|
||||
return response
|
||||
else:
|
||||
sleep(0.1)
|
||||
waited += 1
|
||||
|
||||
raise AnsibleError(
|
||||
'Method call {method} timed out after {timeout} seconds.'.format(method=method, timeout=self.CALL_TIMEOUT / 10))
|
||||
|
||||
def login(self, user, password):
|
||||
payload = {'id': self.pointer, 'jsonrpc': '2.0', 'method': 'session.signIn', 'params': {
|
||||
'username': user, 'password': password}}
|
||||
self.conn.send(json.dumps(payload))
|
||||
result = json.loads(self.conn.recv())
|
||||
result = self.call('session.signIn', {
|
||||
'username': user, 'password': password
|
||||
})
|
||||
|
||||
if 'error' in result:
|
||||
raise AnsibleError(
|
||||
'Could not connect: {0}'.format(result['error']))
|
||||
|
||||
def get_object(self, name):
|
||||
payload = {'id': self.pointer, 'jsonrpc': '2.0',
|
||||
'method': 'xo.getAllObjects', 'params': {'filter': {'type': name}}}
|
||||
self.conn.send(json.dumps(payload))
|
||||
answer = json.loads(self.conn.recv())
|
||||
answer = self.call('xo.getAllObjects', {'filter': {'type': name}})
|
||||
|
||||
if 'error' in answer:
|
||||
raise AnsibleError(
|
||||
@@ -325,4 +348,4 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
self.protocol = 'ws'
|
||||
|
||||
objects = self._get_objects()
|
||||
self._populate(objects)
|
||||
self._populate(make_unsafe(objects))
|
||||
|
||||
@@ -12,6 +12,8 @@ DOCUMENTATION = """
|
||||
requirements:
|
||||
- bw (command line utility)
|
||||
- be logged into bitwarden
|
||||
- bitwarden vault unlocked
|
||||
- C(BW_SESSION) environment variable set
|
||||
short_description: Retrieve secrets from Bitwarden
|
||||
version_added: 5.4.0
|
||||
description:
|
||||
@@ -130,20 +132,29 @@ class Bitwarden(object):
|
||||
If field is None, return the whole record for each match.
|
||||
"""
|
||||
matches = self._get_matches(search_value, search_field, collection_id)
|
||||
|
||||
if field in ['autofillOnPageLoad', 'password', 'passwordRevisionDate', 'totp', 'uris', 'username']:
|
||||
return [match['login'][field] for match in matches]
|
||||
elif not field:
|
||||
if not field:
|
||||
return matches
|
||||
else:
|
||||
custom_field_matches = []
|
||||
for match in matches:
|
||||
field_matches = []
|
||||
for match in matches:
|
||||
# if there are no custom fields, then `match` has no key 'fields'
|
||||
if 'fields' in match:
|
||||
custom_field_found = False
|
||||
for custom_field in match['fields']:
|
||||
if custom_field['name'] == field:
|
||||
custom_field_matches.append(custom_field['value'])
|
||||
if matches and not custom_field_matches:
|
||||
raise AnsibleError("Custom field {field} does not exist in {search_value}".format(field=field, search_value=search_value))
|
||||
return custom_field_matches
|
||||
if field == custom_field['name']:
|
||||
field_matches.append(custom_field['value'])
|
||||
custom_field_found = True
|
||||
break
|
||||
if custom_field_found:
|
||||
continue
|
||||
if 'login' in match and field in match['login']:
|
||||
field_matches.append(match['login'][field])
|
||||
continue
|
||||
if field in match:
|
||||
field_matches.append(match[field])
|
||||
continue
|
||||
if matches and not field_matches:
|
||||
raise AnsibleError("field {field} does not exist in {search_value}".format(field=field, search_value=search_value))
|
||||
return field_matches
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
@@ -61,6 +61,7 @@ DOCUMENTATION = '''
|
||||
description:
|
||||
- Return empty result without empty strings, and return empty list instead of C(NXDOMAIN).
|
||||
- The default for this option will likely change to C(true) in the future.
|
||||
- This option will be forced to C(true) if multiple domains to be queried are specified.
|
||||
default: false
|
||||
type: bool
|
||||
version_added: 6.0.0
|
||||
@@ -95,6 +96,21 @@ EXAMPLES = """
|
||||
msg: "MX record for gmail.com {{ item }}"
|
||||
with_items: "{{ lookup('community.general.dig', 'gmail.com./MX', wantlist=true) }}"
|
||||
|
||||
- name: Lookup multiple names at once
|
||||
ansible.builtin.debug:
|
||||
msg: "A record found {{ item }}"
|
||||
loop: "{{ query('community.general.dig', 'example.org.', 'example.com.', 'gmail.com.') }}"
|
||||
|
||||
- name: Lookup multiple names at once (from list variable)
|
||||
ansible.builtin.debug:
|
||||
msg: "A record found {{ item }}"
|
||||
loop: "{{ query('community.general.dig', *hosts) }}"
|
||||
vars:
|
||||
hosts:
|
||||
- example.org.
|
||||
- example.com.
|
||||
- gmail.com.
|
||||
|
||||
- ansible.builtin.debug:
|
||||
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '192.0.2.5/PTR') }}"
|
||||
- ansible.builtin.debug:
|
||||
@@ -308,7 +324,7 @@ class LookupModule(LookupBase):
|
||||
edns_size = 4096
|
||||
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)
|
||||
|
||||
domain = None
|
||||
domains = []
|
||||
qtype = self.get_option('qtype')
|
||||
flat = self.get_option('flat')
|
||||
fail_on_error = self.get_option('fail_on_error')
|
||||
@@ -365,63 +381,71 @@ class LookupModule(LookupBase):
|
||||
if '/' in t:
|
||||
try:
|
||||
domain, qtype = t.split('/')
|
||||
domains.append(domain)
|
||||
except Exception:
|
||||
domain = t
|
||||
domains.append(t)
|
||||
else:
|
||||
domain = t
|
||||
domains.append(t)
|
||||
|
||||
# print "--- domain = {0} qtype={1} rdclass={2}".format(domain, qtype, rdclass)
|
||||
|
||||
if qtype.upper() == 'PTR':
|
||||
reversed_domains = []
|
||||
for domain in domains:
|
||||
try:
|
||||
n = dns.reversename.from_address(domain)
|
||||
reversed_domains.append(n.to_text())
|
||||
except dns.exception.SyntaxError:
|
||||
pass
|
||||
except Exception as e:
|
||||
raise AnsibleError("dns.reversename unhandled exception %s" % to_native(e))
|
||||
domains = reversed_domains
|
||||
|
||||
if len(domains) > 1:
|
||||
real_empty = True
|
||||
|
||||
ret = []
|
||||
|
||||
if qtype.upper() == 'PTR':
|
||||
for domain in domains:
|
||||
try:
|
||||
n = dns.reversename.from_address(domain)
|
||||
domain = n.to_text()
|
||||
except dns.exception.SyntaxError:
|
||||
pass
|
||||
except Exception as e:
|
||||
raise AnsibleError("dns.reversename unhandled exception %s" % to_native(e))
|
||||
answers = myres.query(domain, qtype, rdclass=rdclass)
|
||||
for rdata in answers:
|
||||
s = rdata.to_text()
|
||||
if qtype.upper() == 'TXT':
|
||||
s = s[1:-1] # Strip outside quotes on TXT rdata
|
||||
|
||||
try:
|
||||
answers = myres.query(domain, qtype, rdclass=rdclass)
|
||||
for rdata in answers:
|
||||
s = rdata.to_text()
|
||||
if qtype.upper() == 'TXT':
|
||||
s = s[1:-1] # Strip outside quotes on TXT rdata
|
||||
if flat:
|
||||
ret.append(s)
|
||||
else:
|
||||
try:
|
||||
rd = make_rdata_dict(rdata)
|
||||
rd['owner'] = answers.canonical_name.to_text()
|
||||
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
|
||||
rd['ttl'] = answers.rrset.ttl
|
||||
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)
|
||||
|
||||
if flat:
|
||||
ret.append(s)
|
||||
else:
|
||||
try:
|
||||
rd = make_rdata_dict(rdata)
|
||||
rd['owner'] = answers.canonical_name.to_text()
|
||||
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
|
||||
rd['ttl'] = answers.rrset.ttl
|
||||
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)
|
||||
ret.append(rd)
|
||||
except Exception as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
ret.append(str(err))
|
||||
|
||||
ret.append(rd)
|
||||
except Exception as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
ret.append(str(err))
|
||||
|
||||
except dns.resolver.NXDOMAIN as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append('NXDOMAIN')
|
||||
except dns.resolver.NoAnswer as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append("")
|
||||
except dns.resolver.Timeout as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append("")
|
||||
except dns.exception.DNSException as err:
|
||||
raise AnsibleError("dns.resolver unhandled exception %s" % to_native(err))
|
||||
except dns.resolver.NXDOMAIN as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append('NXDOMAIN')
|
||||
except dns.resolver.NoAnswer as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append("")
|
||||
except dns.resolver.Timeout as err:
|
||||
if fail_on_error:
|
||||
raise AnsibleError("Lookup failed: %s" % str(err))
|
||||
if not real_empty:
|
||||
ret.append("")
|
||||
except dns.exception.DNSException as err:
|
||||
raise AnsibleError("dns.resolver unhandled exception %s" % to_native(err))
|
||||
|
||||
return ret
|
||||
|
||||
212
plugins/lookup/merge_variables.py
Normal file
212
plugins/lookup/merge_variables.py
Normal file
@@ -0,0 +1,212 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Thales Netherlands
|
||||
# Copyright (c) 2021, 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 (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
author:
|
||||
- Roy Lenferink (@rlenferink)
|
||||
- Mark Ettema (@m-a-r-k-e)
|
||||
name: merge_variables
|
||||
short_description: merge variables with a certain suffix
|
||||
description:
|
||||
- This lookup returns the merged result of all variables in scope that match the given prefixes, suffixes, or
|
||||
regular expressions, optionally.
|
||||
version_added: 6.5.0
|
||||
options:
|
||||
_terms:
|
||||
description:
|
||||
- Depending on the value of I(pattern_type), this is a list of prefixes, suffixes, or regular expressions
|
||||
that will be used to match all variables that should be merged.
|
||||
required: true
|
||||
type: list
|
||||
elements: str
|
||||
pattern_type:
|
||||
description:
|
||||
- Change the way of searching for the specified pattern.
|
||||
type: str
|
||||
default: 'regex'
|
||||
choices:
|
||||
- prefix
|
||||
- suffix
|
||||
- regex
|
||||
env:
|
||||
- name: ANSIBLE_MERGE_VARIABLES_PATTERN_TYPE
|
||||
ini:
|
||||
- section: merge_variables_lookup
|
||||
key: pattern_type
|
||||
initial_value:
|
||||
description:
|
||||
- An initial value to start with.
|
||||
type: raw
|
||||
override:
|
||||
description:
|
||||
- Return an error, print a warning or ignore it when a key will be overwritten.
|
||||
- The default behavior C(error) makes the plugin fail when a key would be overwritten.
|
||||
- When C(warn) and C(ignore) are used, note that it is important to know that the variables
|
||||
are sorted by name before being merged. Keys for later variables in this order will overwrite
|
||||
keys of the same name for variables earlier in this order. To avoid potential confusion,
|
||||
better use I(override=error) whenever possible.
|
||||
type: str
|
||||
default: 'error'
|
||||
choices:
|
||||
- error
|
||||
- warn
|
||||
- ignore
|
||||
env:
|
||||
- name: ANSIBLE_MERGE_VARIABLES_OVERRIDE
|
||||
ini:
|
||||
- section: merge_variables_lookup
|
||||
key: override
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Some example variables, they can be defined anywhere as long as they are in scope
|
||||
test_init_list:
|
||||
- "list init item 1"
|
||||
- "list init item 2"
|
||||
|
||||
testa__test_list:
|
||||
- "test a item 1"
|
||||
|
||||
testb__test_list:
|
||||
- "test b item 1"
|
||||
|
||||
testa__test_dict:
|
||||
ports:
|
||||
- 1
|
||||
|
||||
testb__test_dict:
|
||||
ports:
|
||||
- 3
|
||||
|
||||
|
||||
# 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') }}"
|
||||
|
||||
# The variable example_a now contains:
|
||||
# ports:
|
||||
# - 1
|
||||
# - 3
|
||||
|
||||
|
||||
# Merge variables that match the '^.+__test_list$' regular expression, starting with an initial value and store the
|
||||
# result in a variable 'example_b'
|
||||
example_b: "{{ lookup('community.general.merge_variables', '^.+__test_list$', initial_value=test_init_list) }}"
|
||||
|
||||
# The variable example_b now contains:
|
||||
# - "list init item 1"
|
||||
# - "list init item 2"
|
||||
# - "test a item 1"
|
||||
# - "test b item 1"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: In case the search matches list items, a list will be returned. In case the search matches dicts, a
|
||||
dict will be returned.
|
||||
type: raw
|
||||
elements: raw
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.utils.display import Display
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
def _verify_and_get_type(variable):
|
||||
if isinstance(variable, list):
|
||||
return "list"
|
||||
elif isinstance(variable, dict):
|
||||
return "dict"
|
||||
else:
|
||||
raise AnsibleError("Not supported type detected, variable must be a list or a dict")
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
self.set_options(direct=kwargs)
|
||||
initial_value = self.get_option("initial_value", None)
|
||||
self._override = self.get_option('override', 'error')
|
||||
self._pattern_type = self.get_option('pattern_type', 'regex')
|
||||
|
||||
ret = []
|
||||
for term in terms:
|
||||
if not isinstance(term, str):
|
||||
raise AnsibleError("Non-string type '{0}' passed, only 'str' types are allowed!".format(type(term)))
|
||||
|
||||
ret.append(self._merge_vars(term, initial_value, variables))
|
||||
|
||||
return ret
|
||||
|
||||
def _var_matches(self, key, search_pattern):
|
||||
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 False
|
||||
|
||||
def _merge_vars(self, search_pattern, initial_value, variables):
|
||||
display.vvv("Merge variables with {0}: {1}".format(self._pattern_type, search_pattern))
|
||||
var_merge_names = sorted([key for key in variables.keys() if self._var_matches(key, search_pattern)])
|
||||
display.vvv("The following variables will be merged: {0}".format(var_merge_names))
|
||||
|
||||
prev_var_type = None
|
||||
result = None
|
||||
|
||||
if initial_value is not None:
|
||||
prev_var_type = _verify_and_get_type(initial_value)
|
||||
result = initial_value
|
||||
|
||||
for var_name in var_merge_names:
|
||||
var_value = self._templar.template(variables[var_name]) # Render jinja2 templates
|
||||
var_type = _verify_and_get_type(var_value)
|
||||
|
||||
if prev_var_type is None:
|
||||
prev_var_type = var_type
|
||||
elif prev_var_type != var_type:
|
||||
raise AnsibleError("Unable to merge, not all variables are of the same type")
|
||||
|
||||
if result is None:
|
||||
result = var_value
|
||||
continue
|
||||
|
||||
if var_type == "dict":
|
||||
result = self._merge_dict(var_value, result, [var_name])
|
||||
else: # var_type == "list"
|
||||
result += 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
|
||||
else:
|
||||
if (key in dest) and dest[key] != value:
|
||||
msg = "The key '{0}' with value '{1}' will be overwritten with value '{2}' from '{3}.{0}'".format(
|
||||
key, dest[key], value, ".".join(path))
|
||||
|
||||
if self._override == "error":
|
||||
raise AnsibleError(msg)
|
||||
if self._override == "warn":
|
||||
display.warning(msg)
|
||||
|
||||
dest[key] = value
|
||||
|
||||
return dest
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Scott Buchanan <sbuchanan@ri.pn>
|
||||
# Copyright (c) 2018, Scott Buchanan <scott@buchanan.works>
|
||||
# Copyright (c) 2016, Andrew Zenk <azenk@umn.edu> (lastpass.py used as starting point)
|
||||
# Copyright (c) 2018, 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)
|
||||
@@ -74,18 +74,18 @@ EXAMPLES = """
|
||||
|
||||
- name: Retrieve password for HAL when not signed in to 1Password
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.onepassword'
|
||||
'HAL 9000'
|
||||
subdomain='Discovery'
|
||||
var: lookup('community.general.onepassword',
|
||||
'HAL 9000',
|
||||
subdomain='Discovery',
|
||||
master_password=vault_master_password)
|
||||
|
||||
- name: Retrieve password for HAL when never signed in to 1Password
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.onepassword'
|
||||
'HAL 9000'
|
||||
subdomain='Discovery'
|
||||
master_password=vault_master_password
|
||||
username='tweety@acme.com'
|
||||
var: lookup('community.general.onepassword',
|
||||
'HAL 9000',
|
||||
subdomain='Discovery',
|
||||
master_password=vault_master_password,
|
||||
username='tweety@acme.com',
|
||||
secret_key=vault_secret_key)
|
||||
"""
|
||||
|
||||
@@ -451,10 +451,10 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
# If the field name doesn't exist in the section, match on the value of "label"
|
||||
# then "id" and return "value"
|
||||
if field.get("label") == field_name:
|
||||
return field["value"]
|
||||
return field.get("value", "")
|
||||
|
||||
if field.get("id") == field_name:
|
||||
return field["value"]
|
||||
return field.get("value", "")
|
||||
|
||||
# Look at the section data and get an indentifier. The value of 'id' is either a unique ID
|
||||
# or a human-readable string. If a 'label' field exists, prefer that since
|
||||
@@ -464,10 +464,10 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
if section_title == current_section_title:
|
||||
# In the correct section. Check "label" then "id" for the desired field_name
|
||||
if field.get("label") == field_name:
|
||||
return field["value"]
|
||||
return field.get("value", "")
|
||||
|
||||
if field.get("id") == field_name:
|
||||
return field["value"]
|
||||
return field.get("value", "")
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
@@ -209,7 +209,6 @@ import time
|
||||
import yaml
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleAssertionError
|
||||
from ansible.module_utils.common.file import FileLock
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
||||
from ansible.module_utils.parsing.convert_bool import boolean
|
||||
from ansible.utils.display import Display
|
||||
@@ -217,6 +216,8 @@ from ansible.utils.encrypt import random_password
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible import constants as C
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils._filelock import FileLock
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ DOCUMENTATION = r"""
|
||||
version_added: '3.2.0'
|
||||
description:
|
||||
- Generates random string based upon the given constraints.
|
||||
- Uses L(random.SystemRandom,https://docs.python.org/3/library/random.html#random.SystemRandom),
|
||||
so should be strong enough for cryptographic purposes.
|
||||
options:
|
||||
length:
|
||||
description: The length of the string.
|
||||
|
||||
109
plugins/module_utils/_filelock.py
Normal file
109
plugins/module_utils/_filelock.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# Copyright (c) 2018, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
# NOTE:
|
||||
# This has been vendored from ansible.module_utils.common.file. This code has been removed from there for ansible-core 2.16.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
import fcntl
|
||||
import sys
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
class LockTimeout(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FileLock:
|
||||
'''
|
||||
Currently FileLock is implemented via fcntl.flock on a lock file, however this
|
||||
behaviour may change in the future. Avoid mixing lock types fcntl.flock,
|
||||
fcntl.lockf and module_utils.common.file.FileLock as it will certainly cause
|
||||
unwanted and/or unexpected behaviour
|
||||
'''
|
||||
def __init__(self):
|
||||
self.lockfd = None
|
||||
|
||||
@contextmanager
|
||||
def lock_file(self, path, tmpdir, lock_timeout=None):
|
||||
'''
|
||||
Context for lock acquisition
|
||||
'''
|
||||
try:
|
||||
self.set_lock(path, tmpdir, lock_timeout)
|
||||
yield
|
||||
finally:
|
||||
self.unlock()
|
||||
|
||||
def set_lock(self, path, tmpdir, lock_timeout=None):
|
||||
'''
|
||||
Create a lock file based on path with flock to prevent other processes
|
||||
using given path.
|
||||
Please note that currently file locking only works when it's executed by
|
||||
the same user, I.E single user scenarios
|
||||
|
||||
:kw path: Path (file) to lock
|
||||
:kw tmpdir: Path where to place the temporary .lock file
|
||||
:kw lock_timeout:
|
||||
Wait n seconds for lock acquisition, fail if timeout is reached.
|
||||
0 = Do not wait, fail if lock cannot be acquired immediately,
|
||||
Default is None, wait indefinitely until lock is released.
|
||||
:returns: True
|
||||
'''
|
||||
lock_path = os.path.join(tmpdir, 'ansible-{0}.lock'.format(os.path.basename(path)))
|
||||
l_wait = 0.1
|
||||
r_exception = IOError
|
||||
if sys.version_info[0] == 3:
|
||||
r_exception = BlockingIOError
|
||||
|
||||
self.lockfd = open(lock_path, 'w')
|
||||
|
||||
if lock_timeout <= 0:
|
||||
fcntl.flock(self.lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
os.chmod(lock_path, stat.S_IWRITE | stat.S_IREAD)
|
||||
return True
|
||||
|
||||
if lock_timeout:
|
||||
e_secs = 0
|
||||
while e_secs < lock_timeout:
|
||||
try:
|
||||
fcntl.flock(self.lockfd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
os.chmod(lock_path, stat.S_IWRITE | stat.S_IREAD)
|
||||
return True
|
||||
except r_exception:
|
||||
time.sleep(l_wait)
|
||||
e_secs += l_wait
|
||||
continue
|
||||
|
||||
self.lockfd.close()
|
||||
raise LockTimeout('{0} sec'.format(lock_timeout))
|
||||
|
||||
fcntl.flock(self.lockfd, fcntl.LOCK_EX)
|
||||
os.chmod(lock_path, stat.S_IWRITE | stat.S_IREAD)
|
||||
|
||||
return True
|
||||
|
||||
def unlock(self):
|
||||
'''
|
||||
Make sure lock file is available for everyone and Unlock the file descriptor
|
||||
locked by set_lock
|
||||
|
||||
:returns: True
|
||||
'''
|
||||
if not self.lockfd:
|
||||
return True
|
||||
|
||||
try:
|
||||
fcntl.flock(self.lockfd, fcntl.LOCK_UN)
|
||||
self.lockfd.close()
|
||||
except ValueError: # file wasn't opened, let context manager fail gracefully
|
||||
pass
|
||||
|
||||
return True
|
||||
258
plugins/module_utils/_stormssh.py
Normal file
258
plugins/module_utils/_stormssh.py
Normal file
@@ -0,0 +1,258 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This code is part of Ansible, but is an independent component.
|
||||
# This particular file snippet, and this file snippet only, is based on
|
||||
# the config parser from here: https://github.com/emre/storm/blob/master/storm/parsers/ssh_config_parser.py
|
||||
# Copyright (C) <2013> <Emre Yilmaz>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
from operator import itemgetter
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
try:
|
||||
from paramiko.config import SSHConfig
|
||||
except ImportError:
|
||||
SSHConfig = object
|
||||
HAS_PARAMIKO = False
|
||||
PARAMIKO_IMPORT_ERROR = traceback.format_exc()
|
||||
else:
|
||||
HAS_PARAMIKO = True
|
||||
PARAMIKO_IMPORT_ERROR = None
|
||||
|
||||
|
||||
class StormConfig(SSHConfig):
|
||||
def parse(self, file_obj):
|
||||
"""
|
||||
Read an OpenSSH config from the given file object.
|
||||
@param file_obj: a file-like object to read the config file from
|
||||
@type file_obj: file
|
||||
"""
|
||||
order = 1
|
||||
host = {"host": ['*'], "config": {}, }
|
||||
for line in file_obj:
|
||||
line = line.rstrip('\n').lstrip()
|
||||
if line == '':
|
||||
self._config.append({
|
||||
'type': 'empty_line',
|
||||
'value': line,
|
||||
'host': '',
|
||||
'order': order,
|
||||
})
|
||||
order += 1
|
||||
continue
|
||||
|
||||
if line.startswith('#'):
|
||||
self._config.append({
|
||||
'type': 'comment',
|
||||
'value': line,
|
||||
'host': '',
|
||||
'order': order,
|
||||
})
|
||||
order += 1
|
||||
continue
|
||||
|
||||
if '=' in line:
|
||||
# Ensure ProxyCommand gets properly split
|
||||
if line.lower().strip().startswith('proxycommand'):
|
||||
proxy_re = re.compile(r"^(proxycommand)\s*=*\s*(.*)", re.I)
|
||||
match = proxy_re.match(line)
|
||||
key, value = match.group(1).lower(), match.group(2)
|
||||
else:
|
||||
key, value = line.split('=', 1)
|
||||
key = key.strip().lower()
|
||||
else:
|
||||
# find first whitespace, and split there
|
||||
i = 0
|
||||
while (i < len(line)) and not line[i].isspace():
|
||||
i += 1
|
||||
if i == len(line):
|
||||
raise Exception('Unparsable line: %r' % line)
|
||||
key = line[:i].lower()
|
||||
value = line[i:].lstrip()
|
||||
if key == 'host':
|
||||
self._config.append(host)
|
||||
value = value.split()
|
||||
host = {
|
||||
key: value,
|
||||
'config': {},
|
||||
'type': 'entry',
|
||||
'order': order
|
||||
}
|
||||
order += 1
|
||||
elif key in ['identityfile', 'localforward', 'remoteforward']:
|
||||
if key in host['config']:
|
||||
host['config'][key].append(value)
|
||||
else:
|
||||
host['config'][key] = [value]
|
||||
elif key not in host['config']:
|
||||
host['config'].update({key: value})
|
||||
self._config.append(host)
|
||||
|
||||
|
||||
class ConfigParser(object):
|
||||
"""
|
||||
Config parser for ~/.ssh/config files.
|
||||
"""
|
||||
|
||||
def __init__(self, ssh_config_file=None):
|
||||
if not ssh_config_file:
|
||||
ssh_config_file = self.get_default_ssh_config_file()
|
||||
|
||||
self.defaults = {}
|
||||
|
||||
self.ssh_config_file = ssh_config_file
|
||||
|
||||
if not os.path.exists(self.ssh_config_file):
|
||||
if not os.path.exists(os.path.dirname(self.ssh_config_file)):
|
||||
os.makedirs(os.path.dirname(self.ssh_config_file))
|
||||
open(self.ssh_config_file, 'w+').close()
|
||||
os.chmod(self.ssh_config_file, 0o600)
|
||||
|
||||
self.config_data = []
|
||||
|
||||
def get_default_ssh_config_file(self):
|
||||
return os.path.expanduser("~/.ssh/config")
|
||||
|
||||
def load(self):
|
||||
config = StormConfig()
|
||||
|
||||
with open(self.ssh_config_file) as fd:
|
||||
config.parse(fd)
|
||||
|
||||
for entry in config.__dict__.get("_config"):
|
||||
if entry.get("host") == ["*"]:
|
||||
self.defaults.update(entry.get("config"))
|
||||
|
||||
if entry.get("type") in ["comment", "empty_line"]:
|
||||
self.config_data.append(entry)
|
||||
continue
|
||||
|
||||
host_item = {
|
||||
'host': entry["host"][0],
|
||||
'options': entry.get("config"),
|
||||
'type': 'entry',
|
||||
'order': entry.get("order", 0),
|
||||
}
|
||||
|
||||
if len(entry["host"]) > 1:
|
||||
host_item.update({
|
||||
'host': " ".join(entry["host"]),
|
||||
})
|
||||
# minor bug in paramiko.SSHConfig that duplicates
|
||||
# "Host *" entries.
|
||||
if entry.get("config") and len(entry.get("config")) > 0:
|
||||
self.config_data.append(host_item)
|
||||
|
||||
return self.config_data
|
||||
|
||||
def add_host(self, host, options):
|
||||
self.config_data.append({
|
||||
'host': host,
|
||||
'options': options,
|
||||
'order': self.get_last_index(),
|
||||
})
|
||||
|
||||
return self
|
||||
|
||||
def update_host(self, host, options, use_regex=False):
|
||||
for index, host_entry in enumerate(self.config_data):
|
||||
if host_entry.get("host") == host or \
|
||||
(use_regex and re.match(host, host_entry.get("host"))):
|
||||
|
||||
if 'deleted_fields' in options:
|
||||
deleted_fields = options.pop("deleted_fields")
|
||||
for deleted_field in deleted_fields:
|
||||
del self.config_data[index]["options"][deleted_field]
|
||||
|
||||
self.config_data[index]["options"].update(options)
|
||||
|
||||
return self
|
||||
|
||||
def search_host(self, search_string):
|
||||
results = []
|
||||
for host_entry in self.config_data:
|
||||
if host_entry.get("type") != 'entry':
|
||||
continue
|
||||
if host_entry.get("host") == "*":
|
||||
continue
|
||||
|
||||
searchable_information = host_entry.get("host")
|
||||
for key, value in host_entry.get("options").items():
|
||||
if isinstance(value, list):
|
||||
value = " ".join(value)
|
||||
if isinstance(value, int):
|
||||
value = str(value)
|
||||
|
||||
searchable_information += " " + value
|
||||
|
||||
if search_string in searchable_information:
|
||||
results.append(host_entry)
|
||||
|
||||
return results
|
||||
|
||||
def delete_host(self, host):
|
||||
found = 0
|
||||
for index, host_entry in enumerate(self.config_data):
|
||||
if host_entry.get("host") == host:
|
||||
del self.config_data[index]
|
||||
found += 1
|
||||
|
||||
if found == 0:
|
||||
raise ValueError('No host found')
|
||||
return self
|
||||
|
||||
def delete_all_hosts(self):
|
||||
self.config_data = []
|
||||
self.write_to_ssh_config()
|
||||
|
||||
return self
|
||||
|
||||
def dump(self):
|
||||
if len(self.config_data) < 1:
|
||||
return
|
||||
|
||||
file_content = ""
|
||||
self.config_data = sorted(self.config_data, key=itemgetter("order"))
|
||||
|
||||
for host_item in self.config_data:
|
||||
if host_item.get("type") in ['comment', 'empty_line']:
|
||||
file_content += host_item.get("value") + "\n"
|
||||
continue
|
||||
host_item_content = "Host {0}\n".format(host_item.get("host"))
|
||||
for key, value in host_item.get("options").items():
|
||||
if isinstance(value, list):
|
||||
sub_content = ""
|
||||
for value_ in value:
|
||||
sub_content += " {0} {1}\n".format(
|
||||
key, value_
|
||||
)
|
||||
host_item_content += sub_content
|
||||
else:
|
||||
host_item_content += " {0} {1}\n".format(
|
||||
key, value
|
||||
)
|
||||
file_content += host_item_content
|
||||
|
||||
return file_content
|
||||
|
||||
def write_to_ssh_config(self):
|
||||
with open(self.ssh_config_file, 'w+') as f:
|
||||
data = self.dump()
|
||||
if data:
|
||||
f.write(data)
|
||||
return self
|
||||
|
||||
def get_last_index(self):
|
||||
last_index = 0
|
||||
indexes = []
|
||||
for item in self.config_data:
|
||||
if item.get("order"):
|
||||
indexes.append(item.get("order"))
|
||||
if len(indexes) > 0:
|
||||
last_index = max(indexes)
|
||||
|
||||
return last_index
|
||||
464
plugins/module_utils/btrfs.py
Normal file
464
plugins/module_utils/btrfs.py
Normal file
@@ -0,0 +1,464 @@
|
||||
# Copyright (c) 2022, Gregory Furlong <gnfzdz@fzdz.io>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils.common.text.converters import to_bytes
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
def normalize_subvolume_path(path):
|
||||
"""
|
||||
Normalizes btrfs subvolume paths to ensure exactly one leading slash, no trailing slashes and no consecutive slashes.
|
||||
In addition, if the path is prefixed with a leading <FS_TREE>, this value is removed.
|
||||
"""
|
||||
fstree_stripped = re.sub(r'^<FS_TREE>', '', path)
|
||||
result = re.sub(r'/+$', '', re.sub(r'/+', '/', '/' + fstree_stripped))
|
||||
return result if len(result) > 0 else '/'
|
||||
|
||||
|
||||
class BtrfsModuleException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BtrfsCommands(object):
|
||||
|
||||
"""
|
||||
Provides access to a subset of the Btrfs command line
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
self.__module = module
|
||||
self.__btrfs = self.__module.get_bin_path("btrfs", required=True)
|
||||
|
||||
def filesystem_show(self):
|
||||
command = "%s filesystem show -d" % (self.__btrfs)
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
stdout = [x.strip() for x in result[1].splitlines()]
|
||||
filesystems = []
|
||||
current = None
|
||||
for line in stdout:
|
||||
if line.startswith('Label'):
|
||||
current = self.__parse_filesystem(line)
|
||||
filesystems.append(current)
|
||||
elif line.startswith('devid'):
|
||||
current['devices'].append(self.__parse_filesystem_device(line))
|
||||
return filesystems
|
||||
|
||||
def __parse_filesystem(self, line):
|
||||
label = re.sub(r'\s*uuid:.*$', '', re.sub(r'^Label:\s*', '', line))
|
||||
id = re.sub(r'^.*uuid:\s*', '', line)
|
||||
|
||||
filesystem = {}
|
||||
filesystem['label'] = label.strip("'") if label != 'none' else None
|
||||
filesystem['uuid'] = id
|
||||
filesystem['devices'] = []
|
||||
filesystem['mountpoints'] = []
|
||||
filesystem['subvolumes'] = []
|
||||
filesystem['default_subvolid'] = None
|
||||
return filesystem
|
||||
|
||||
def __parse_filesystem_device(self, line):
|
||||
return re.sub(r'^.*path\s', '', line)
|
||||
|
||||
def subvolumes_list(self, filesystem_path):
|
||||
command = "%s subvolume list -tap %s" % (self.__btrfs, filesystem_path)
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
stdout = [x.split('\t') for x in result[1].splitlines()]
|
||||
subvolumes = [{'id': 5, 'parent': None, 'path': '/'}]
|
||||
if len(stdout) > 2:
|
||||
subvolumes.extend([self.__parse_subvolume_list_record(x) for x in stdout[2:]])
|
||||
return subvolumes
|
||||
|
||||
def __parse_subvolume_list_record(self, item):
|
||||
return {
|
||||
'id': int(item[0]),
|
||||
'parent': int(item[2]),
|
||||
'path': normalize_subvolume_path(item[5]),
|
||||
}
|
||||
|
||||
def subvolume_get_default(self, filesystem_path):
|
||||
command = [self.__btrfs, "subvolume", "get-default", to_bytes(filesystem_path)]
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
# ID [n] ...
|
||||
return int(result[1].strip().split()[1])
|
||||
|
||||
def subvolume_set_default(self, filesystem_path, subvolume_id):
|
||||
command = [self.__btrfs, "subvolume", "set-default", str(subvolume_id), to_bytes(filesystem_path)]
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
|
||||
def subvolume_create(self, subvolume_path):
|
||||
command = [self.__btrfs, "subvolume", "create", to_bytes(subvolume_path)]
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
|
||||
def subvolume_snapshot(self, snapshot_source, snapshot_destination):
|
||||
command = [self.__btrfs, "subvolume", "snapshot", to_bytes(snapshot_source), to_bytes(snapshot_destination)]
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
|
||||
def subvolume_delete(self, subvolume_path):
|
||||
command = [self.__btrfs, "subvolume", "delete", to_bytes(subvolume_path)]
|
||||
result = self.__module.run_command(command, check_rc=True)
|
||||
|
||||
|
||||
class BtrfsInfoProvider(object):
|
||||
|
||||
"""
|
||||
Utility providing details of the currently available btrfs filesystems
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
self.__module = module
|
||||
self.__btrfs_api = BtrfsCommands(module)
|
||||
self.__findmnt_path = self.__module.get_bin_path("findmnt", required=True)
|
||||
|
||||
def get_filesystems(self):
|
||||
filesystems = self.__btrfs_api.filesystem_show()
|
||||
mountpoints = self.__find_mountpoints()
|
||||
for filesystem in filesystems:
|
||||
device_mountpoints = self.__filter_mountpoints_for_devices(mountpoints, filesystem['devices'])
|
||||
filesystem['mountpoints'] = device_mountpoints
|
||||
|
||||
if len(device_mountpoints) > 0:
|
||||
|
||||
# any path within the filesystem can be used to query metadata
|
||||
mountpoint = device_mountpoints[0]['mountpoint']
|
||||
filesystem['subvolumes'] = self.get_subvolumes(mountpoint)
|
||||
filesystem['default_subvolid'] = self.get_default_subvolume_id(mountpoint)
|
||||
|
||||
return filesystems
|
||||
|
||||
def get_mountpoints(self, filesystem_devices):
|
||||
mountpoints = self.__find_mountpoints()
|
||||
return self.__filter_mountpoints_for_devices(mountpoints, filesystem_devices)
|
||||
|
||||
def get_subvolumes(self, filesystem_path):
|
||||
return self.__btrfs_api.subvolumes_list(filesystem_path)
|
||||
|
||||
def get_default_subvolume_id(self, filesystem_path):
|
||||
return self.__btrfs_api.subvolume_get_default(filesystem_path)
|
||||
|
||||
def __filter_mountpoints_for_devices(self, mountpoints, devices):
|
||||
return [m for m in mountpoints if (m['device'] in devices)]
|
||||
|
||||
def __find_mountpoints(self):
|
||||
command = "%s -t btrfs -nvP" % self.__findmnt_path
|
||||
result = self.__module.run_command(command)
|
||||
mountpoints = []
|
||||
if result[0] == 0:
|
||||
lines = result[1].splitlines()
|
||||
for line in lines:
|
||||
mountpoint = self.__parse_mountpoint_pairs(line)
|
||||
mountpoints.append(mountpoint)
|
||||
return mountpoints
|
||||
|
||||
def __parse_mountpoint_pairs(self, line):
|
||||
pattern = re.compile(r'^TARGET="(?P<target>.*)"\s+SOURCE="(?P<source>.*)"\s+FSTYPE="(?P<fstype>.*)"\s+OPTIONS="(?P<options>.*)"\s*$')
|
||||
match = pattern.search(line)
|
||||
if match is not None:
|
||||
groups = match.groupdict()
|
||||
|
||||
return {
|
||||
'mountpoint': groups['target'],
|
||||
'device': groups['source'],
|
||||
'subvolid': self.__extract_mount_subvolid(groups['options']),
|
||||
}
|
||||
else:
|
||||
raise BtrfsModuleException("Failed to parse findmnt result for line: '%s'" % line)
|
||||
|
||||
def __extract_mount_subvolid(self, mount_options):
|
||||
for option in mount_options.split(','):
|
||||
if option.startswith('subvolid='):
|
||||
return int(option[len('subvolid='):])
|
||||
raise BtrfsModuleException("Failed to find subvolid for mountpoint in options '%s'" % mount_options)
|
||||
|
||||
|
||||
class BtrfsSubvolume(object):
|
||||
|
||||
"""
|
||||
Wrapper class providing convenience methods for inspection of a btrfs subvolume
|
||||
"""
|
||||
|
||||
def __init__(self, filesystem, subvolume_id):
|
||||
self.__filesystem = filesystem
|
||||
self.__subvolume_id = subvolume_id
|
||||
|
||||
def get_filesystem(self):
|
||||
return self.__filesystem
|
||||
|
||||
def is_mounted(self):
|
||||
mountpoints = self.get_mountpoints()
|
||||
return mountpoints is not None and len(mountpoints) > 0
|
||||
|
||||
def is_filesystem_root(self):
|
||||
return 5 == self.__subvolume_id
|
||||
|
||||
def is_filesystem_default(self):
|
||||
return self.__filesystem.default_subvolid == self.__subvolume_id
|
||||
|
||||
def get_mounted_path(self):
|
||||
mountpoints = self.get_mountpoints()
|
||||
if mountpoints is not None and len(mountpoints) > 0:
|
||||
return mountpoints[0]
|
||||
elif self.parent is not None:
|
||||
parent = self.__filesystem.get_subvolume_by_id(self.parent)
|
||||
parent_path = parent.get_mounted_path()
|
||||
if parent_path is not None:
|
||||
return parent_path + os.path.sep + self.name
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_mountpoints(self):
|
||||
return self.__filesystem.get_mountpoints_by_subvolume_id(self.__subvolume_id)
|
||||
|
||||
def get_child_relative_path(self, absolute_child_path):
|
||||
"""
|
||||
Get the relative path from this subvolume to the named child subvolume.
|
||||
The provided parameter is expected to be normalized as by normalize_subvolume_path.
|
||||
"""
|
||||
path = self.path
|
||||
if absolute_child_path.startswith(path):
|
||||
relative = absolute_child_path[len(path):]
|
||||
return re.sub(r'^/*', '', relative)
|
||||
else:
|
||||
raise BtrfsModuleException("Path '%s' doesn't start with '%s'" % (absolute_child_path, path))
|
||||
|
||||
def get_parent_subvolume(self):
|
||||
parent_id = self.parent
|
||||
return self.__filesystem.get_subvolume_by_id(parent_id) if parent_id is not None else None
|
||||
|
||||
def get_child_subvolumes(self):
|
||||
return self.__filesystem.get_subvolume_children(self.__subvolume_id)
|
||||
|
||||
@property
|
||||
def __info(self):
|
||||
return self.__filesystem.get_subvolume_info_for_id(self.__subvolume_id)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.__subvolume_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.path.split('/').pop()
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self.__info['path']
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self.__info['parent']
|
||||
|
||||
|
||||
class BtrfsFilesystem(object):
|
||||
|
||||
"""
|
||||
Wrapper class providing convenience methods for inspection of a btrfs filesystem
|
||||
"""
|
||||
|
||||
def __init__(self, info, provider, module):
|
||||
self.__provider = provider
|
||||
|
||||
# constant for module execution
|
||||
self.__uuid = info['uuid']
|
||||
self.__label = info['label']
|
||||
self.__devices = info['devices']
|
||||
|
||||
# refreshable
|
||||
self.__default_subvolid = info['default_subvolid'] if 'default_subvolid' in info else None
|
||||
self.__update_mountpoints(info['mountpoints'] if 'mountpoints' in info else [])
|
||||
self.__update_subvolumes(info['subvolumes'] if 'subvolumes' in info else [])
|
||||
|
||||
@property
|
||||
def uuid(self):
|
||||
return self.__uuid
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self.__label
|
||||
|
||||
@property
|
||||
def default_subvolid(self):
|
||||
return self.__default_subvolid
|
||||
|
||||
@property
|
||||
def devices(self):
|
||||
return list(self.__devices)
|
||||
|
||||
def refresh(self):
|
||||
self.refresh_mountpoints()
|
||||
self.refresh_subvolumes()
|
||||
self.refresh_default_subvolume()
|
||||
|
||||
def refresh_mountpoints(self):
|
||||
mountpoints = self.__provider.get_mountpoints(list(self.__devices))
|
||||
self.__update_mountpoints(mountpoints)
|
||||
|
||||
def __update_mountpoints(self, mountpoints):
|
||||
self.__mountpoints = dict()
|
||||
for i in mountpoints:
|
||||
subvolid = i['subvolid']
|
||||
mountpoint = i['mountpoint']
|
||||
if subvolid not in self.__mountpoints:
|
||||
self.__mountpoints[subvolid] = []
|
||||
self.__mountpoints[subvolid].append(mountpoint)
|
||||
|
||||
def refresh_subvolumes(self):
|
||||
filesystem_path = self.get_any_mountpoint()
|
||||
if filesystem_path is not None:
|
||||
subvolumes = self.__provider.get_subvolumes(filesystem_path)
|
||||
self.__update_subvolumes(subvolumes)
|
||||
|
||||
def __update_subvolumes(self, subvolumes):
|
||||
# TODO strategy for retaining information on deleted subvolumes?
|
||||
self.__subvolumes = dict()
|
||||
for subvolume in subvolumes:
|
||||
self.__subvolumes[subvolume['id']] = subvolume
|
||||
|
||||
def refresh_default_subvolume(self):
|
||||
filesystem_path = self.get_any_mountpoint()
|
||||
if filesystem_path is not None:
|
||||
self.__default_subvolid = self.__provider.get_default_subvolume_id(filesystem_path)
|
||||
|
||||
def contains_device(self, device):
|
||||
return device in self.__devices
|
||||
|
||||
def contains_subvolume(self, subvolume):
|
||||
return self.get_subvolume_by_name(subvolume) is not None
|
||||
|
||||
def get_subvolume_by_id(self, subvolume_id):
|
||||
return BtrfsSubvolume(self, subvolume_id) if subvolume_id in self.__subvolumes else None
|
||||
|
||||
def get_subvolume_info_for_id(self, subvolume_id):
|
||||
return self.__subvolumes[subvolume_id] if subvolume_id in self.__subvolumes else None
|
||||
|
||||
def get_subvolume_by_name(self, subvolume):
|
||||
for subvolume_info in self.__subvolumes.values():
|
||||
if subvolume_info['path'] == subvolume:
|
||||
return BtrfsSubvolume(self, subvolume_info['id'])
|
||||
return None
|
||||
|
||||
def get_any_mountpoint(self):
|
||||
for subvol_mountpoints in self.__mountpoints.values():
|
||||
if len(subvol_mountpoints) > 0:
|
||||
return subvol_mountpoints[0]
|
||||
# maybe error?
|
||||
return None
|
||||
|
||||
def get_any_mounted_subvolume(self):
|
||||
for subvolid, subvol_mountpoints in self.__mountpoints.items():
|
||||
if len(subvol_mountpoints) > 0:
|
||||
return self.get_subvolume_by_id(subvolid)
|
||||
return None
|
||||
|
||||
def get_mountpoints_by_subvolume_id(self, subvolume_id):
|
||||
return self.__mountpoints[subvolume_id] if subvolume_id in self.__mountpoints else []
|
||||
|
||||
def get_nearest_subvolume(self, subvolume):
|
||||
"""Return the identified subvolume if existing, else the closest matching parent"""
|
||||
subvolumes_by_path = self.__get_subvolumes_by_path()
|
||||
while len(subvolume) > 1:
|
||||
if subvolume in subvolumes_by_path:
|
||||
return BtrfsSubvolume(self, subvolumes_by_path[subvolume]['id'])
|
||||
else:
|
||||
subvolume = re.sub(r'/[^/]+$', '', subvolume)
|
||||
|
||||
return BtrfsSubvolume(self, 5)
|
||||
|
||||
def get_mountpath_as_child(self, subvolume_name):
|
||||
"""Find a path to the target subvolume through a mounted ancestor"""
|
||||
nearest = self.get_nearest_subvolume(subvolume_name)
|
||||
if nearest.path == subvolume_name:
|
||||
nearest = nearest.get_parent_subvolume()
|
||||
if nearest is None or nearest.get_mounted_path() is None:
|
||||
raise BtrfsModuleException("Failed to find a path '%s' through a mounted parent subvolume" % subvolume_name)
|
||||
else:
|
||||
return nearest.get_mounted_path() + os.path.sep + nearest.get_child_relative_path(subvolume_name)
|
||||
|
||||
def get_subvolume_children(self, subvolume_id):
|
||||
return [BtrfsSubvolume(self, x['id']) for x in self.__subvolumes.values() if x['parent'] == subvolume_id]
|
||||
|
||||
def __get_subvolumes_by_path(self):
|
||||
result = {}
|
||||
for s in self.__subvolumes.values():
|
||||
path = s['path']
|
||||
result[path] = s
|
||||
return result
|
||||
|
||||
def is_mounted(self):
|
||||
return self.__mountpoints is not None and len(self.__mountpoints) > 0
|
||||
|
||||
def get_summary(self):
|
||||
subvolumes = []
|
||||
sources = self.__subvolumes.values() if self.__subvolumes is not None else []
|
||||
for subvolume in sources:
|
||||
id = subvolume['id']
|
||||
subvolumes.append({
|
||||
'id': id,
|
||||
'path': subvolume['path'],
|
||||
'parent': subvolume['parent'],
|
||||
'mountpoints': self.get_mountpoints_by_subvolume_id(id),
|
||||
})
|
||||
|
||||
return {
|
||||
'default_subvolume': self.__default_subvolid,
|
||||
'devices': self.__devices,
|
||||
'label': self.__label,
|
||||
'uuid': self.__uuid,
|
||||
'subvolumes': subvolumes,
|
||||
}
|
||||
|
||||
|
||||
class BtrfsFilesystemsProvider(object):
|
||||
|
||||
"""
|
||||
Provides methods to query available btrfs filesystems
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
self.__module = module
|
||||
self.__provider = BtrfsInfoProvider(module)
|
||||
self.__filesystems = None
|
||||
|
||||
def get_matching_filesystem(self, criteria):
|
||||
if criteria['device'] is not None:
|
||||
criteria['device'] = os.path.realpath(criteria['device'])
|
||||
|
||||
self.__check_init()
|
||||
matching = [f for f in self.__filesystems.values() if self.__filesystem_matches_criteria(f, criteria)]
|
||||
if len(matching) == 1:
|
||||
return matching[0]
|
||||
else:
|
||||
raise BtrfsModuleException("Found %d filesystems matching criteria uuid=%s label=%s device=%s" % (
|
||||
len(matching),
|
||||
criteria['uuid'],
|
||||
criteria['label'],
|
||||
criteria['device']
|
||||
))
|
||||
|
||||
def __filesystem_matches_criteria(self, filesystem, criteria):
|
||||
return ((criteria['uuid'] is None or filesystem.uuid == criteria['uuid']) and
|
||||
(criteria['label'] is None or filesystem.label == criteria['label']) and
|
||||
(criteria['device'] is None or filesystem.contains_device(criteria['device'])))
|
||||
|
||||
def get_filesystem_for_device(self, device):
|
||||
real_device = os.path.realpath(device)
|
||||
self.__check_init()
|
||||
for fs in self.__filesystems.values():
|
||||
if fs.contains_device(real_device):
|
||||
return fs
|
||||
return None
|
||||
|
||||
def get_filesystems(self):
|
||||
self.__check_init()
|
||||
return list(self.__filesystems.values())
|
||||
|
||||
def __check_init(self):
|
||||
if self.__filesystems is None:
|
||||
self.__filesystems = dict()
|
||||
for f in self.__provider.get_filesystems():
|
||||
uuid = f['uuid']
|
||||
self.__filesystems[uuid] = BtrfsFilesystem(f, self.__provider, self.__module)
|
||||
@@ -6,6 +6,7 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
from functools import wraps
|
||||
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
@@ -199,11 +200,16 @@ class CmdRunner(object):
|
||||
environ_update = {}
|
||||
self.environ_update = environ_update
|
||||
|
||||
self.command[0] = module.get_bin_path(self.command[0], opt_dirs=path_prefix, required=True)
|
||||
_cmd = self.command[0]
|
||||
self.command[0] = _cmd if (os.path.isabs(_cmd) or '/' in _cmd) else module.get_bin_path(_cmd, opt_dirs=path_prefix, required=True)
|
||||
|
||||
for mod_param_name, spec in iteritems(module.argument_spec):
|
||||
if mod_param_name not in self.arg_formats:
|
||||
self.arg_formats[mod_param_name] = _Format.as_default_type(spec['type'], mod_param_name)
|
||||
self.arg_formats[mod_param_name] = _Format.as_default_type(spec.get('type', 'str'), mod_param_name)
|
||||
|
||||
@property
|
||||
def binary(self):
|
||||
return self.command[0]
|
||||
|
||||
def __call__(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
|
||||
if output_process is None:
|
||||
|
||||
@@ -55,8 +55,10 @@ def initialize_dialect(dialect, **kwargs):
|
||||
|
||||
|
||||
def read_csv(data, dialect, fieldnames=None):
|
||||
|
||||
BOM = to_native(u'\ufeff')
|
||||
data = to_native(data, errors='surrogate_or_strict')
|
||||
if data.startswith(BOM):
|
||||
data = data[len(BOM):]
|
||||
|
||||
if PY3:
|
||||
fake_fh = StringIO(data)
|
||||
|
||||
@@ -50,7 +50,7 @@ class _Dependency(object):
|
||||
def failed(self):
|
||||
return self.state == 1
|
||||
|
||||
def verify(self, module):
|
||||
def validate(self, module):
|
||||
if self.failed:
|
||||
module.fail_json(msg=self.message, exception=self.trace)
|
||||
|
||||
@@ -71,20 +71,28 @@ def declare(name, *args, **kwargs):
|
||||
_deps[name] = dep
|
||||
|
||||
|
||||
def validate(module, spec=None):
|
||||
def _select_names(spec):
|
||||
dep_names = sorted(_deps)
|
||||
|
||||
if spec is not None:
|
||||
if spec:
|
||||
if spec.startswith("-"):
|
||||
spec_split = spec[1:].split(":")
|
||||
for d in spec_split:
|
||||
dep_names.remove(d)
|
||||
else:
|
||||
spec_split = spec[1:].split(":")
|
||||
spec_split = spec.split(":")
|
||||
dep_names = []
|
||||
for d in spec_split:
|
||||
_deps[d] # ensure it exists
|
||||
dep_names.append(d)
|
||||
|
||||
for dep in dep_names:
|
||||
_deps[dep].verify(module)
|
||||
return dep_names
|
||||
|
||||
|
||||
def validate(module, spec=None):
|
||||
for dep in _select_names(spec):
|
||||
_deps[dep].validate(module)
|
||||
|
||||
|
||||
def failed(spec=None):
|
||||
return any(_deps[d].failed for d in _select_names(spec))
|
||||
|
||||
@@ -49,6 +49,16 @@ URL_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}"
|
||||
URL_CLIENTSCOPE_PROTOCOLMAPPERS = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models"
|
||||
URL_CLIENTSCOPE_PROTOCOLMAPPER = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models/{mapper_id}"
|
||||
|
||||
URL_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-default-client-scopes"
|
||||
URL_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-default-client-scopes/{id}"
|
||||
URL_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-optional-client-scopes"
|
||||
URL_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-optional-client-scopes/{id}"
|
||||
|
||||
URL_CLIENT_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes"
|
||||
URL_CLIENT_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes/{id}"
|
||||
URL_CLIENT_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes"
|
||||
URL_CLIENT_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes/{id}"
|
||||
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}"
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/available"
|
||||
URL_CLIENT_GROUP_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/composite"
|
||||
@@ -80,6 +90,9 @@ URL_IDENTITY_PROVIDER_MAPPER = "{url}/admin/realms/{realm}/identity-provider/ins
|
||||
URL_COMPONENTS = "{url}/admin/realms/{realm}/components"
|
||||
URL_COMPONENT = "{url}/admin/realms/{realm}/components/{id}"
|
||||
|
||||
URL_AUTHZ_AUTHORIZATION_SCOPE = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope/{id}"
|
||||
URL_AUTHZ_AUTHORIZATION_SCOPES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope"
|
||||
|
||||
|
||||
def keycloak_argument_spec():
|
||||
"""
|
||||
@@ -194,24 +207,30 @@ def is_struct_included(struct1, struct2, exclude=None):
|
||||
Return True if all element of dict 1 are present in dict 2, return false otherwise.
|
||||
"""
|
||||
if isinstance(struct1, list) and isinstance(struct2, list):
|
||||
if not struct1 and not struct2:
|
||||
return True
|
||||
for item1 in struct1:
|
||||
if isinstance(item1, (list, dict)):
|
||||
for item2 in struct2:
|
||||
if not is_struct_included(item1, item2, exclude):
|
||||
return False
|
||||
if is_struct_included(item1, item2, exclude):
|
||||
break
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
if item1 not in struct2:
|
||||
return False
|
||||
return True
|
||||
elif isinstance(struct1, dict) and isinstance(struct2, dict):
|
||||
if not struct1 and not struct2:
|
||||
return True
|
||||
try:
|
||||
for key in struct1:
|
||||
if not (exclude and key in exclude):
|
||||
if not is_struct_included(struct1[key], struct2[key], exclude):
|
||||
return False
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
return True
|
||||
elif isinstance(struct1, bool) and isinstance(struct2, bool):
|
||||
return struct1 == struct2
|
||||
else:
|
||||
@@ -734,8 +753,15 @@ class KeycloakAPI(object):
|
||||
users_url = URL_USERS.format(url=self.baseurl, realm=realm)
|
||||
users_url += '?username=%s&exact=true' % username
|
||||
try:
|
||||
return json.loads(to_native(open_url(users_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
userrep = None
|
||||
users = json.loads(to_native(open_url(users_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
for user in users:
|
||||
if user['username'] == username:
|
||||
userrep = user
|
||||
break
|
||||
return userrep
|
||||
|
||||
except ValueError as e:
|
||||
self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the user for realm %s and username %s: %s'
|
||||
% (realm, username, str(e)))
|
||||
@@ -1163,6 +1189,131 @@ class KeycloakAPI(object):
|
||||
self.module.fail_json(msg='Could not update protocolmappers for clientscope %s in realm %s: %s'
|
||||
% (mapper_rep, realm, str(e)))
|
||||
|
||||
def get_default_clientscopes(self, realm, client_id=None):
|
||||
"""Fetch the name and ID of all clientscopes on the Keycloak server.
|
||||
|
||||
To fetch the full data of the client scope, make a subsequent call to
|
||||
get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return.
|
||||
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
:return The default clientscopes of this realm or client
|
||||
"""
|
||||
url = URL_DEFAULT_CLIENTSCOPES if client_id is None else URL_CLIENT_DEFAULT_CLIENTSCOPES
|
||||
return self._get_clientscopes_of_type(realm, url, 'default', client_id)
|
||||
|
||||
def get_optional_clientscopes(self, realm, client_id=None):
|
||||
"""Fetch the name and ID of all clientscopes on the Keycloak server.
|
||||
|
||||
To fetch the full data of the client scope, make a subsequent call to
|
||||
get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return.
|
||||
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
:return The optinal clientscopes of this realm or client
|
||||
"""
|
||||
url = URL_OPTIONAL_CLIENTSCOPES if client_id is None else URL_CLIENT_OPTIONAL_CLIENTSCOPES
|
||||
return self._get_clientscopes_of_type(realm, url, 'optional', client_id)
|
||||
|
||||
def _get_clientscopes_of_type(self, realm, url_template, scope_type, client_id=None):
|
||||
"""Fetch the name and ID of all clientscopes on the Keycloak server.
|
||||
|
||||
To fetch the full data of the client scope, make a subsequent call to
|
||||
get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return.
|
||||
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param url_template the template for the right type
|
||||
:param scope_type this can be either optinal or default
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
:return The clientscopes of the specified type of this realm
|
||||
"""
|
||||
if client_id is None:
|
||||
clientscopes_url = url_template.format(url=self.baseurl, realm=realm)
|
||||
try:
|
||||
return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout, validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch list of %s clientscopes in realm %s: %s" % (scope_type, realm, str(e)))
|
||||
else:
|
||||
cid = self.get_client_id(client_id=client_id, realm=realm)
|
||||
clientscopes_url = url_template.format(url=self.baseurl, realm=realm, cid=cid)
|
||||
try:
|
||||
return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout, validate_certs=self.validate_certs).read()))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Could not fetch list of %s clientscopes in client %s: %s" % (scope_type, client_id, clientscopes_url))
|
||||
|
||||
def _decide_url_type_clientscope(self, client_id=None, scope_type="default"):
|
||||
"""Decides which url to use.
|
||||
:param scope_type this can be either optinal or default
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
"""
|
||||
if client_id is None:
|
||||
if scope_type == "default":
|
||||
return URL_DEFAULT_CLIENTSCOPE
|
||||
if scope_type == "optional":
|
||||
return URL_OPTIONAL_CLIENTSCOPE
|
||||
else:
|
||||
if scope_type == "default":
|
||||
return URL_CLIENT_DEFAULT_CLIENTSCOPE
|
||||
if scope_type == "optional":
|
||||
return URL_CLIENT_OPTIONAL_CLIENTSCOPE
|
||||
|
||||
def add_default_clientscope(self, id, realm="master", client_id=None):
|
||||
"""Add a client scope as default either on realm or client level.
|
||||
|
||||
:param id: Client scope Id.
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
"""
|
||||
self._action_type_clientscope(id, client_id, "default", realm, 'add')
|
||||
|
||||
def add_optional_clientscope(self, id, realm="master", client_id=None):
|
||||
"""Add a client scope as optional either on realm or client level.
|
||||
|
||||
:param id: Client scope Id.
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
"""
|
||||
self._action_type_clientscope(id, client_id, "optional", realm, 'add')
|
||||
|
||||
def delete_default_clientscope(self, id, realm="master", client_id=None):
|
||||
"""Remove a client scope as default either on realm or client level.
|
||||
|
||||
:param id: Client scope Id.
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
"""
|
||||
self._action_type_clientscope(id, client_id, "default", realm, 'delete')
|
||||
|
||||
def delete_optional_clientscope(self, id, realm="master", client_id=None):
|
||||
"""Remove a client scope as optional either on realm or client level.
|
||||
|
||||
:param id: Client scope Id.
|
||||
:param realm: Realm in which the clientscope resides.
|
||||
:param client_id: The client in which the clientscope resides.
|
||||
"""
|
||||
self._action_type_clientscope(id, client_id, "optional", realm, 'delete')
|
||||
|
||||
def _action_type_clientscope(self, id=None, client_id=None, scope_type="default", realm="master", action='add'):
|
||||
""" Delete or add a clientscope of type.
|
||||
:param name: The name of the clientscope. A lookup will be performed to retrieve the clientscope ID.
|
||||
:param client_id: The ID of the clientscope (preferred to name).
|
||||
:param scope_type 'default' or 'optional'
|
||||
:param realm: The realm in which this group resides, default "master".
|
||||
"""
|
||||
cid = None if client_id is None else self.get_client_id(client_id=client_id, realm=realm)
|
||||
# should have a good cid by here.
|
||||
clientscope_type_url = self._decide_url_type_clientscope(client_id, scope_type).format(realm=realm, id=id, cid=cid, url=self.baseurl)
|
||||
try:
|
||||
method = 'PUT' if action == "add" else 'DELETE'
|
||||
return open_url(clientscope_type_url, method=method, http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs)
|
||||
|
||||
except Exception as e:
|
||||
place = 'realm' if client_id is None else 'client ' + client_id
|
||||
self.module.fail_json(msg="Unable to %s %s clientscope %s @ %s : %s" % (action, scope_type, id, place, str(e)))
|
||||
|
||||
def create_clientsecret(self, id, realm="master"):
|
||||
""" Generate a new client secret by id
|
||||
|
||||
@@ -1795,6 +1946,9 @@ class KeycloakAPI(object):
|
||||
data=json.dumps(updatedExec),
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs)
|
||||
except HTTPError as e:
|
||||
self.module.fail_json(msg="Unable to update execution '%s': %s: %s %s" %
|
||||
(flowAlias, repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(updatedExec)))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Unable to update executions %s: %s" % (updatedExec, str(e)))
|
||||
|
||||
@@ -1819,7 +1973,7 @@ class KeycloakAPI(object):
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e)))
|
||||
|
||||
def create_subflow(self, subflowName, flowAlias, realm='master'):
|
||||
def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'):
|
||||
""" Create new sublow on the flow
|
||||
|
||||
:param subflowName: name of the subflow to create
|
||||
@@ -1830,7 +1984,7 @@ class KeycloakAPI(object):
|
||||
newSubFlow = {}
|
||||
newSubFlow["alias"] = subflowName
|
||||
newSubFlow["provider"] = "registration-page-form"
|
||||
newSubFlow["type"] = "basic-flow"
|
||||
newSubFlow["type"] = flowType
|
||||
open_url(
|
||||
URL_AUTHENTICATION_FLOW_EXECUTIONS_FLOW.format(
|
||||
url=self.baseurl,
|
||||
@@ -1865,8 +2019,11 @@ class KeycloakAPI(object):
|
||||
data=json.dumps(newExec),
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs)
|
||||
except HTTPError as e:
|
||||
self.module.fail_json(msg="Unable to create new execution '%s' %s: %s: %s %s" %
|
||||
(flowAlias, execution["providerId"], repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(newExec)))
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Unable to create new execution %s: %s" % (execution["provider"], str(e)))
|
||||
self.module.fail_json(msg="Unable to create new execution '%s' %s: %s" % (flowAlias, execution["providerId"], repr(e)))
|
||||
|
||||
def change_execution_priority(self, executionId, diff, realm='master'):
|
||||
""" Raise or lower execution priority of diff time
|
||||
@@ -2190,3 +2347,44 @@ class KeycloakAPI(object):
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Unable to delete component %s in realm %s: %s'
|
||||
% (cid, realm, str(e)))
|
||||
|
||||
def get_authz_authorization_scope_by_name(self, name, client_id, realm):
|
||||
url = URL_AUTHZ_AUTHORIZATION_SCOPES.format(url=self.baseurl, client_id=client_id, realm=realm)
|
||||
search_url = "%s/search?name=%s" % (url, quote(name))
|
||||
|
||||
try:
|
||||
return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders,
|
||||
timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs).read()))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def create_authz_authorization_scope(self, payload, client_id, realm):
|
||||
"""Create an authorization scope for a Keycloak client"""
|
||||
url = URL_AUTHZ_AUTHORIZATION_SCOPES.format(url=self.baseurl, client_id=client_id, realm=realm)
|
||||
|
||||
try:
|
||||
return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
|
||||
data=json.dumps(payload), validate_certs=self.validate_certs)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Could not create authorization scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
|
||||
|
||||
def update_authz_authorization_scope(self, payload, id, client_id, realm):
|
||||
"""Update an authorization scope for a Keycloak client"""
|
||||
url = URL_AUTHZ_AUTHORIZATION_SCOPE.format(url=self.baseurl, id=id, client_id=client_id, realm=realm)
|
||||
|
||||
try:
|
||||
return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
|
||||
data=json.dumps(payload), validate_certs=self.validate_certs)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Could not create update scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e)))
|
||||
|
||||
def remove_authz_authorization_scope(self, id, client_id, realm):
|
||||
"""Remove an authorization scope from a Keycloak client"""
|
||||
url = URL_AUTHZ_AUTHORIZATION_SCOPE.format(url=self.baseurl, id=id, client_id=client_id, realm=realm)
|
||||
|
||||
try:
|
||||
return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
|
||||
validate_certs=self.validate_certs)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg='Could not delete scope %s for client %s in realm %s: %s' % (id, client_id, realm, str(e)))
|
||||
|
||||
@@ -8,6 +8,7 @@ from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
|
||||
import time
|
||||
|
||||
|
||||
class iLORedfishUtils(RedfishUtils):
|
||||
@@ -228,3 +229,79 @@ class iLORedfishUtils(RedfishUtils):
|
||||
if not response['ret']:
|
||||
return response
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgrattr['mgr_attr_name']}
|
||||
|
||||
def get_server_poststate(self):
|
||||
# Get server details
|
||||
response = self.get_request(self.root_uri + self.systems_uri)
|
||||
if not response["ret"]:
|
||||
return response
|
||||
server_data = response["data"]
|
||||
|
||||
if "Hpe" in server_data["Oem"]:
|
||||
return {
|
||||
"ret": True,
|
||||
"server_poststate": server_data["Oem"]["Hpe"]["PostState"]
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"ret": True,
|
||||
"server_poststate": server_data["Oem"]["Hp"]["PostState"]
|
||||
}
|
||||
|
||||
def wait_for_ilo_reboot_completion(self, polling_interval=60, max_polling_time=1800):
|
||||
# This method checks if OOB controller reboot is completed
|
||||
time.sleep(10)
|
||||
|
||||
# Check server poststate
|
||||
state = self.get_server_poststate()
|
||||
if not state["ret"]:
|
||||
return state
|
||||
|
||||
count = int(max_polling_time / polling_interval)
|
||||
times = 0
|
||||
|
||||
# When server is powered OFF
|
||||
pcount = 0
|
||||
while state["server_poststate"] in ["PowerOff", "Off"] and pcount < 5:
|
||||
time.sleep(10)
|
||||
state = self.get_server_poststate()
|
||||
if not state["ret"]:
|
||||
return state
|
||||
|
||||
if state["server_poststate"] not in ["PowerOff", "Off"]:
|
||||
break
|
||||
pcount = pcount + 1
|
||||
if state["server_poststate"] in ["PowerOff", "Off"]:
|
||||
return {
|
||||
"ret": False,
|
||||
"changed": False,
|
||||
"msg": "Server is powered OFF"
|
||||
}
|
||||
|
||||
# When server is not rebooting
|
||||
if state["server_poststate"] in ["InPostDiscoveryComplete", "FinishedPost"]:
|
||||
return {
|
||||
"ret": True,
|
||||
"changed": False,
|
||||
"msg": "Server is not rebooting"
|
||||
}
|
||||
|
||||
while state["server_poststate"] not in ["InPostDiscoveryComplete", "FinishedPost"] and count > times:
|
||||
state = self.get_server_poststate()
|
||||
if not state["ret"]:
|
||||
return state
|
||||
|
||||
if state["server_poststate"] in ["InPostDiscoveryComplete", "FinishedPost"]:
|
||||
return {
|
||||
"ret": True,
|
||||
"changed": True,
|
||||
"msg": "Server reboot is completed"
|
||||
}
|
||||
time.sleep(polling_interval)
|
||||
times = times + 1
|
||||
|
||||
return {
|
||||
"ret": False,
|
||||
"changed": False,
|
||||
"msg": "Server Reboot has failed, server state: {state} ".format(state=state)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ def gen_specs(**specs):
|
||||
specs.update({
|
||||
'bind_dn': dict(),
|
||||
'bind_pw': dict(default='', no_log=True),
|
||||
'ca_path': dict(type='path'),
|
||||
'dn': dict(required=True),
|
||||
'referrals_chasing': dict(type='str', default='anonymous', choices=['disabled', 'anonymous']),
|
||||
'server_uri': dict(default='ldapi:///'),
|
||||
@@ -52,6 +53,7 @@ class LdapGeneric(object):
|
||||
self.module = module
|
||||
self.bind_dn = self.module.params['bind_dn']
|
||||
self.bind_pw = self.module.params['bind_pw']
|
||||
self.ca_path = self.module.params['ca_path']
|
||||
self.referrals_chasing = self.module.params['referrals_chasing']
|
||||
self.server_uri = self.module.params['server_uri']
|
||||
self.start_tls = self.module.params['start_tls']
|
||||
@@ -97,6 +99,9 @@ class LdapGeneric(object):
|
||||
if not self.verify_cert:
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||
|
||||
if self.ca_path:
|
||||
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.ca_path)
|
||||
|
||||
connection = ldap.initialize(self.server_uri)
|
||||
|
||||
if self.referrals_chasing == 'disabled':
|
||||
|
||||
@@ -14,8 +14,9 @@ from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.module_utils.urls import open_url, urllib_error
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.basic import json
|
||||
import ansible.module_utils.six.moves.urllib.error as urllib_error
|
||||
|
||||
|
||||
class Response(object):
|
||||
@@ -26,6 +27,7 @@ class Response(object):
|
||||
def __init__(self):
|
||||
self.content = None
|
||||
self.status_code = None
|
||||
self.stderr = None
|
||||
|
||||
def json(self):
|
||||
return json.loads(self.content)
|
||||
@@ -75,6 +77,10 @@ def memset_api_call(api_key, api_method, payload=None):
|
||||
msg = "Memset API returned a {0} response ({1}, {2})." . format(response.status_code, response.json()['error_type'], response.json()['error'])
|
||||
else:
|
||||
msg = "Memset API returned an error ({0}, {1})." . format(response.json()['error_type'], response.json()['error'])
|
||||
except urllib_error.URLError as e:
|
||||
has_failed = True
|
||||
msg = "An URLError occured ({0})." . format(type(e))
|
||||
response.stderr = "{0}" . format(e)
|
||||
|
||||
if msg is None:
|
||||
msg = response.json()
|
||||
|
||||
@@ -79,7 +79,7 @@ def _post_pritunl_organization(
|
||||
api_secret=api_secret,
|
||||
base_url=base_url,
|
||||
method="POST",
|
||||
path="/organization/%s",
|
||||
path="/organization",
|
||||
headers={"Content-Type": "application/json"},
|
||||
data=json.dumps(organization_data),
|
||||
validate_certs=validate_certs,
|
||||
@@ -220,7 +220,7 @@ def post_pritunl_organization(
|
||||
api_secret=api_secret,
|
||||
base_url=base_url,
|
||||
organization_data={"name": organization_name},
|
||||
validate_certs=True,
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
@@ -248,7 +248,7 @@ def post_pritunl_user(
|
||||
base_url=base_url,
|
||||
organization_id=organization_id,
|
||||
user_data=user_data,
|
||||
validate_certs=True,
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
@@ -267,7 +267,7 @@ def post_pritunl_user(
|
||||
organization_id=organization_id,
|
||||
user_data=user_data,
|
||||
user_id=user_id,
|
||||
validate_certs=True,
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
@@ -287,7 +287,7 @@ def delete_pritunl_organization(
|
||||
api_secret=api_secret,
|
||||
base_url=base_url,
|
||||
organization_id=organization_id,
|
||||
validate_certs=True,
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
@@ -307,7 +307,7 @@ def delete_pritunl_user(
|
||||
base_url=base_url,
|
||||
organization_id=organization_id,
|
||||
user_id=user_id,
|
||||
validate_certs=True,
|
||||
validate_certs=validate_certs,
|
||||
)
|
||||
|
||||
if response.getcode() != 200:
|
||||
|
||||
@@ -45,6 +45,8 @@ def render(to_render):
|
||||
"""Converts dictionary to OpenNebula template."""
|
||||
def recurse(to_render):
|
||||
for key, value in sorted(to_render.items()):
|
||||
if value is None:
|
||||
continue
|
||||
if isinstance(value, dict):
|
||||
yield '{0:}=[{1:}]'.format(key, ','.join(recurse(value)))
|
||||
continue
|
||||
@@ -52,6 +54,9 @@ def render(to_render):
|
||||
for item in value:
|
||||
yield '{0:}=[{1:}]'.format(key, ','.join(recurse(item)))
|
||||
continue
|
||||
if isinstance(value, str):
|
||||
yield '{0:}="{1:}"'.format(key, value.replace('\\', '\\\\').replace('"', '\\"'))
|
||||
continue
|
||||
yield '{0:}="{1:}"'.format(key, value)
|
||||
return '\n'.join(recurse(to_render))
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ def are_lists_equal(s, t):
|
||||
if s is None and t is None:
|
||||
return True
|
||||
|
||||
if (s is None and len(t) >= 0) or (t is None and len(s) >= 0) or (len(s) != len(t)):
|
||||
if s is None or t is None or (len(s) != len(t)):
|
||||
return False
|
||||
|
||||
if len(s) == 0:
|
||||
@@ -570,7 +570,7 @@ def are_lists_equal(s, t):
|
||||
s = to_dict(s)
|
||||
t = to_dict(t)
|
||||
|
||||
if type(s[0]) == dict:
|
||||
if isinstance(s[0], dict):
|
||||
# Handle list of dicts. Dictionary returned by the API may have additional keys. For example, a get call on
|
||||
# service gateway has an attribute `services` which is a list of `ServiceIdResponseDetails`. This has a key
|
||||
# `service_name` which is not provided in the list of `services` by a user while making an update call; only
|
||||
@@ -604,9 +604,9 @@ def get_attr_to_update(get_fn, kwargs_get, module, update_attributes):
|
||||
user_provided_attr_value = module.params.get(attr, None)
|
||||
|
||||
unequal_list_attr = (
|
||||
type(resources_attr_value) == list or type(user_provided_attr_value) == list
|
||||
isinstance(resources_attr_value, list) or isinstance(user_provided_attr_value, list)
|
||||
) and not are_lists_equal(user_provided_attr_value, resources_attr_value)
|
||||
unequal_attr = type(resources_attr_value) != list and to_dict(
|
||||
unequal_attr = not isinstance(resources_attr_value, list) and to_dict(
|
||||
resources_attr_value
|
||||
) != to_dict(user_provided_attr_value)
|
||||
if unequal_list_attr or unequal_attr:
|
||||
@@ -936,9 +936,9 @@ def tuplize(d):
|
||||
list_of_tuples = []
|
||||
key_list = sorted(list(d.keys()))
|
||||
for key in key_list:
|
||||
if type(d[key]) == list:
|
||||
if isinstance(d[key], list):
|
||||
# Convert a value which is itself a list of dict to a list of tuples.
|
||||
if d[key] and type(d[key][0]) == dict:
|
||||
if d[key] and isinstance(d[key][0], dict):
|
||||
sub_tuples = []
|
||||
for sub_dict in d[key]:
|
||||
sub_tuples.append(tuplize(sub_dict))
|
||||
@@ -948,7 +948,7 @@ def tuplize(d):
|
||||
list_of_tuples.append((sub_tuples is None, key, sub_tuples))
|
||||
else:
|
||||
list_of_tuples.append((d[key] is None, key, d[key]))
|
||||
elif type(d[key]) == dict:
|
||||
elif isinstance(d[key], dict):
|
||||
tupled_value = tuplize(d[key])
|
||||
list_of_tuples.append((tupled_value is None, key, tupled_value))
|
||||
else:
|
||||
@@ -969,13 +969,13 @@ def sort_dictionary(d):
|
||||
"""
|
||||
sorted_d = {}
|
||||
for key in d:
|
||||
if type(d[key]) == list:
|
||||
if d[key] and type(d[key][0]) == dict:
|
||||
if isinstance(d[key], list):
|
||||
if d[key] and isinstance(d[key][0], dict):
|
||||
sorted_value = sort_list_of_dictionary(d[key])
|
||||
sorted_d[key] = sorted_value
|
||||
else:
|
||||
sorted_d[key] = sorted(d[key])
|
||||
elif type(d[key]) == dict:
|
||||
elif isinstance(d[key], dict):
|
||||
sorted_d[key] = sort_dictionary(d[key])
|
||||
else:
|
||||
sorted_d[key] = d[key]
|
||||
@@ -1026,10 +1026,7 @@ def check_if_user_value_matches_resources_attr(
|
||||
return
|
||||
|
||||
if (
|
||||
resources_value_for_attr is None
|
||||
and len(user_provided_value_for_attr) >= 0
|
||||
or user_provided_value_for_attr is None
|
||||
and len(resources_value_for_attr) >= 0
|
||||
resources_value_for_attr is None or user_provided_value_for_attr is None
|
||||
):
|
||||
res[0] = False
|
||||
return
|
||||
@@ -1044,7 +1041,7 @@ def check_if_user_value_matches_resources_attr(
|
||||
|
||||
if (
|
||||
user_provided_value_for_attr
|
||||
and type(user_provided_value_for_attr[0]) == dict
|
||||
and isinstance(user_provided_value_for_attr[0], dict)
|
||||
):
|
||||
# Process a list of dict
|
||||
sorted_user_provided_value_for_attr = sort_list_of_dictionary(
|
||||
@@ -1547,7 +1544,7 @@ def delete_and_wait(
|
||||
except ServiceError as ex:
|
||||
# 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 type(client) == oci.dns.DnsClient:
|
||||
if isinstance(client, oci.dns.DnsClient):
|
||||
if ex.status == 400 and ex.code == "InvalidParameter":
|
||||
_debug(
|
||||
"Resource {0} with {1} already deleted. So returning changed=False".format(
|
||||
|
||||
@@ -32,12 +32,14 @@ def pipx_runner(module, command, **kwargs):
|
||||
state=fmt.as_map(_state_map),
|
||||
name=fmt.as_list(),
|
||||
name_source=fmt.as_func(fmt.unpack_args(lambda n, s: [s] if s else [n])),
|
||||
install_apps=fmt.as_bool("--include-apps"),
|
||||
install_deps=fmt.as_bool("--include-deps"),
|
||||
inject_packages=fmt.as_list(),
|
||||
force=fmt.as_bool("--force"),
|
||||
include_injected=fmt.as_bool("--include-injected"),
|
||||
index_url=fmt.as_opt_val('--index-url'),
|
||||
python=fmt.as_opt_val('--python'),
|
||||
system_site_packages=fmt.as_bool("--system-site-packages"),
|
||||
_list=fmt.as_fixed(['list', '--include-injected', '--json']),
|
||||
editable=fmt.as_bool("--editable"),
|
||||
pip_args=fmt.as_opt_val('--pip-args'),
|
||||
|
||||
@@ -18,6 +18,7 @@ import traceback
|
||||
PROXMOXER_IMP_ERR = None
|
||||
try:
|
||||
from proxmoxer import ProxmoxAPI
|
||||
from proxmoxer import __version__ as proxmoxer_version
|
||||
HAS_PROXMOXER = True
|
||||
except ImportError:
|
||||
HAS_PROXMOXER = False
|
||||
@@ -79,6 +80,7 @@ class ProxmoxAnsible(object):
|
||||
module.fail_json(msg=missing_required_lib('proxmoxer'), exception=PROXMOXER_IMP_ERR)
|
||||
|
||||
self.module = module
|
||||
self.proxmoxer_version = proxmoxer_version
|
||||
self.proxmox_api = self._connect()
|
||||
# Test token validity
|
||||
try:
|
||||
@@ -98,6 +100,8 @@ class ProxmoxAnsible(object):
|
||||
if api_password:
|
||||
auth_args['password'] = api_password
|
||||
else:
|
||||
if self.proxmoxer_version < LooseVersion('1.1.0'):
|
||||
self.module.fail_json('Using "token_name" and "token_value" require proxmoxer>=1.1.0')
|
||||
auth_args['token_name'] = api_token_id
|
||||
auth_args['token_value'] = api_token_secret
|
||||
|
||||
|
||||
@@ -63,11 +63,7 @@ def puppet_runner(module):
|
||||
return cmd
|
||||
|
||||
def noop_func(v):
|
||||
_noop = cmd_runner_fmt.as_map({
|
||||
True: "--noop",
|
||||
False: "--no-noop",
|
||||
})
|
||||
return _noop(module.check_mode or v)
|
||||
return ["--noop"] if module.check_mode or v else ["--no-noop"]
|
||||
|
||||
_logdest_map = {
|
||||
"syslog": ["--logdest", "syslog"],
|
||||
@@ -96,6 +92,7 @@ def puppet_runner(module):
|
||||
confdir=cmd_runner_fmt.as_opt_val("--confdir"),
|
||||
environment=cmd_runner_fmt.as_opt_val("--environment"),
|
||||
tags=cmd_runner_fmt.as_func(lambda v: ["--tags", ",".join(v)]),
|
||||
skip_tags=cmd_runner_fmt.as_func(lambda v: ["--skip_tags", ",".join(v)]),
|
||||
certname=cmd_runner_fmt.as_opt_eq_val("--certname"),
|
||||
noop=cmd_runner_fmt.as_func(noop_func),
|
||||
use_srv_records=cmd_runner_fmt.as_map({
|
||||
|
||||
@@ -652,7 +652,8 @@ class RedfishUtils(object):
|
||||
properties = ['CacheSummary', 'FirmwareVersion', 'Identifiers',
|
||||
'Location', 'Manufacturer', 'Model', 'Name', 'Id',
|
||||
'PartNumber', 'SerialNumber', 'SpeedGbps', 'Status']
|
||||
key = "StorageControllers"
|
||||
key = "Controllers"
|
||||
deprecated_key = "StorageControllers"
|
||||
|
||||
# Find Storage service
|
||||
response = self.get_request(self.root_uri + systems_uri)
|
||||
@@ -680,7 +681,30 @@ class RedfishUtils(object):
|
||||
data = response['data']
|
||||
|
||||
if key in data:
|
||||
controller_list = data[key]
|
||||
controllers_uri = data[key][u'@odata.id']
|
||||
|
||||
response = self.get_request(self.root_uri + controllers_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
|
||||
if data[u'Members']:
|
||||
for controller_member in data[u'Members']:
|
||||
controller_member_uri = controller_member[u'@odata.id']
|
||||
response = self.get_request(self.root_uri + controller_member_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
|
||||
controller_result = {}
|
||||
for property in properties:
|
||||
if property in data:
|
||||
controller_result[property] = data[property]
|
||||
controller_results.append(controller_result)
|
||||
elif deprecated_key in data:
|
||||
controller_list = data[deprecated_key]
|
||||
for controller in controller_list:
|
||||
controller_result = {}
|
||||
for property in properties:
|
||||
@@ -735,7 +759,25 @@ class RedfishUtils(object):
|
||||
return response
|
||||
data = response['data']
|
||||
controller_name = 'Controller 1'
|
||||
if 'StorageControllers' in data:
|
||||
if 'Controllers' in data:
|
||||
controllers_uri = data['Controllers'][u'@odata.id']
|
||||
|
||||
response = self.get_request(self.root_uri + controllers_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
cdata = response['data']
|
||||
|
||||
if cdata[u'Members']:
|
||||
controller_member_uri = cdata[u'Members'][0][u'@odata.id']
|
||||
|
||||
response = self.get_request(self.root_uri + controller_member_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
cdata = response['data']
|
||||
controller_name = cdata['Name']
|
||||
elif 'StorageControllers' in data:
|
||||
sc = data['StorageControllers']
|
||||
if sc:
|
||||
if 'Name' in sc[0]:
|
||||
@@ -832,14 +874,32 @@ class RedfishUtils(object):
|
||||
if data.get('Members'):
|
||||
for controller in data[u'Members']:
|
||||
controller_list.append(controller[u'@odata.id'])
|
||||
for c in controller_list:
|
||||
for idx, c in enumerate(controller_list):
|
||||
uri = self.root_uri + c
|
||||
response = self.get_request(uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
controller_name = 'Controller 1'
|
||||
if 'StorageControllers' in data:
|
||||
controller_name = 'Controller %s' % str(idx)
|
||||
if 'Controllers' in data:
|
||||
response = self.get_request(self.root_uri + data['Controllers'][u'@odata.id'])
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
c_data = response['data']
|
||||
|
||||
if c_data.get('Members') and c_data['Members']:
|
||||
response = self.get_request(self.root_uri + c_data['Members'][0][u'@odata.id'])
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
member_data = response['data']
|
||||
|
||||
if member_data:
|
||||
if 'Name' in member_data:
|
||||
controller_name = member_data['Name']
|
||||
else:
|
||||
controller_id = member_data.get('Id', '1')
|
||||
controller_name = 'Controller %s' % controller_id
|
||||
elif 'StorageControllers' in data:
|
||||
sc = data['StorageControllers']
|
||||
if sc:
|
||||
if 'Name' in sc[0]:
|
||||
@@ -848,6 +908,7 @@ class RedfishUtils(object):
|
||||
sc_id = sc[0].get('Id', '1')
|
||||
controller_name = 'Controller %s' % sc_id
|
||||
volume_results = []
|
||||
volume_list = []
|
||||
if 'Volumes' in data:
|
||||
# Get a list of all volumes and build respective URIs
|
||||
volumes_uri = data[u'Volumes'][u'@odata.id']
|
||||
@@ -1079,6 +1140,12 @@ class RedfishUtils(object):
|
||||
if property in data:
|
||||
user[property] = data[property]
|
||||
|
||||
# Filter out empty account slots
|
||||
# An empty account slot can be detected if the username is an empty
|
||||
# string and if the account is disabled
|
||||
if user.get('UserName', '') == '' and not user.get('Enabled', False):
|
||||
continue
|
||||
|
||||
users_results.append(user)
|
||||
result["entries"] = users_results
|
||||
return result
|
||||
@@ -3217,3 +3284,35 @@ class RedfishUtils(object):
|
||||
body["SecureBootEnable"] = True
|
||||
|
||||
return self.patch_request(self.root_uri + secure_boot_url, body, check_pyld=True)
|
||||
|
||||
def get_hpe_thermal_config(self):
|
||||
result = {}
|
||||
key = "Thermal"
|
||||
# Go through list
|
||||
for chassis_uri in self.chassis_uri_list:
|
||||
response = self.get_request(self.root_uri + chassis_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
oem = data.get['Oem']
|
||||
hpe = oem.get['Hpe']
|
||||
thermal_config = hpe.get('ThermalConfiguration')
|
||||
result["current_thermal_config"] = thermal_config
|
||||
return result
|
||||
|
||||
def get_hpe_fan_percent_min(self):
|
||||
result = {}
|
||||
key = "Thermal"
|
||||
# Go through list
|
||||
for chassis_uri in self.chassis_uri_list:
|
||||
response = self.get_request(self.root_uri + chassis_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
oem = data.get['Oem']
|
||||
hpe = oem.get['Hpe']
|
||||
fan_percent_min_config = hpe.get('FanPercentMinimum')
|
||||
result["fan_percent_min"] = fan_percent_min_config
|
||||
return result
|
||||
|
||||
@@ -72,7 +72,9 @@ def api_request(module, endpoint, data=None, method="GET"):
|
||||
if info["status"] == 403:
|
||||
module.fail_json(msg="Token authorization failed",
|
||||
execution_info=json.loads(info["body"]))
|
||||
if info["status"] == 409:
|
||||
elif info["status"] == 404:
|
||||
return None, info
|
||||
elif info["status"] == 409:
|
||||
module.fail_json(msg="Job executions limit reached",
|
||||
execution_info=json.loads(info["body"]))
|
||||
elif info["status"] >= 500:
|
||||
@@ -81,12 +83,18 @@ def api_request(module, endpoint, data=None, method="GET"):
|
||||
|
||||
try:
|
||||
content = response.read()
|
||||
json_response = json.loads(content)
|
||||
return json_response, info
|
||||
|
||||
if not content:
|
||||
return None, info
|
||||
else:
|
||||
json_response = json.loads(content)
|
||||
return json_response, info
|
||||
except AttributeError as error:
|
||||
module.fail_json(msg="Rundeck API request error",
|
||||
exception=to_native(error),
|
||||
execution_info=info)
|
||||
module.fail_json(
|
||||
msg="Rundeck API request error",
|
||||
exception=to_native(error),
|
||||
execution_info=info
|
||||
)
|
||||
except ValueError as error:
|
||||
module.fail_json(
|
||||
msg="No valid JSON response",
|
||||
|
||||
@@ -108,7 +108,7 @@ EXAMPLES = r'''
|
||||
device: en1
|
||||
attributes:
|
||||
mtu: 900
|
||||
arp: off
|
||||
arp: 'off'
|
||||
state: available
|
||||
|
||||
- name: Configure IP, netmask and set en1 up.
|
||||
|
||||
@@ -38,8 +38,8 @@ options:
|
||||
type: list
|
||||
elements: str
|
||||
default:
|
||||
- agblksize='4096'
|
||||
- isnapshot='no'
|
||||
- agblksize=4096
|
||||
- isnapshot=no
|
||||
auto_mount:
|
||||
description:
|
||||
- File system is automatically mounted at system restart.
|
||||
@@ -365,7 +365,53 @@ def create_fs(
|
||||
# Creates a LVM file system.
|
||||
crfs_cmd = module.get_bin_path('crfs', True)
|
||||
if not module.check_mode:
|
||||
cmd = [crfs_cmd, "-v", fs_type, "-m", filesystem, vg, device, mount_group, auto_mount, account_subsystem, "-p", permissions, size, "-a", attributes]
|
||||
cmd = [crfs_cmd]
|
||||
|
||||
cmd.append("-v")
|
||||
cmd.append(fs_type)
|
||||
|
||||
if vg:
|
||||
(flag, value) = vg.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
if device:
|
||||
(flag, value) = device.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
cmd.append("-m")
|
||||
cmd.append(filesystem)
|
||||
|
||||
if mount_group:
|
||||
(flag, value) = mount_group.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
if auto_mount:
|
||||
(flag, value) = auto_mount.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
if account_subsystem:
|
||||
(flag, value) = account_subsystem.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
cmd.append("-p")
|
||||
cmd.append(permissions)
|
||||
|
||||
if size:
|
||||
(flag, value) = size.split()
|
||||
cmd.append(flag)
|
||||
cmd.append(value)
|
||||
|
||||
if attributes:
|
||||
splitted_attributes = attributes.split()
|
||||
cmd.append("-a")
|
||||
for value in splitted_attributes:
|
||||
cmd.append(value)
|
||||
|
||||
rc, crfs_out, err = module.run_command(cmd)
|
||||
|
||||
if rc == 10:
|
||||
@@ -461,7 +507,7 @@ def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
account_subsystem=dict(type='bool', default=False),
|
||||
attributes=dict(type='list', elements='str', default=["agblksize='4096'", "isnapshot='no'"]),
|
||||
attributes=dict(type='list', elements='str', default=["agblksize=4096", "isnapshot=no"]),
|
||||
auto_mount=dict(type='bool', default=True),
|
||||
device=dict(type='str'),
|
||||
filesystem=dict(type='str', required=True),
|
||||
|
||||
@@ -154,7 +154,7 @@ def _get_ctl_binary(module):
|
||||
if ctl_binary is not None:
|
||||
return ctl_binary
|
||||
|
||||
module.fail_json(msg="Neither of apache2ctl nor apachctl found. At least one apache control binary is necessary.")
|
||||
module.fail_json(msg="Neither of apache2ctl nor apachectl found. At least one apache control binary is necessary.")
|
||||
|
||||
|
||||
def _module_is_enabled(module):
|
||||
|
||||
@@ -27,8 +27,7 @@ attributes:
|
||||
options:
|
||||
package:
|
||||
description:
|
||||
- list of packages to install, upgrade or remove.
|
||||
required: true
|
||||
- List of packages to install, upgrade, or remove.
|
||||
aliases: [ name, pkg ]
|
||||
type: list
|
||||
elements: str
|
||||
@@ -40,9 +39,30 @@ options:
|
||||
type: str
|
||||
update_cache:
|
||||
description:
|
||||
- update the package database first C(apt-get update).
|
||||
- Run the equivalent of C(apt-get update) before the operation. Can be run as part of the package installation or as a separate step.
|
||||
- Default is not to update the cache.
|
||||
type: bool
|
||||
default: false
|
||||
clean:
|
||||
description:
|
||||
- Run the equivalent of C(apt-get clean) to clear out the local repository of retrieved package files. It removes everything but
|
||||
the lock file from C(/var/cache/apt/archives/) and C(/var/cache/apt/archives/partial/).
|
||||
- Can be run as part of the package installation (clean runs before install) or as a separate step.
|
||||
type: bool
|
||||
default: false
|
||||
version_added: 6.5.0
|
||||
dist_upgrade:
|
||||
description:
|
||||
- If true performs an C(apt-get dist-upgrade) to upgrade system.
|
||||
type: bool
|
||||
default: false
|
||||
version_added: 6.5.0
|
||||
update_kernel:
|
||||
description:
|
||||
- If true performs an C(update-kernel) to upgrade kernel packages.
|
||||
type: bool
|
||||
default: false
|
||||
version_added: 6.5.0
|
||||
author:
|
||||
- Evgenii Terechkov (@evgkrsk)
|
||||
'''
|
||||
@@ -76,6 +96,16 @@ EXAMPLES = '''
|
||||
name: bar
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Run the equivalent of "apt-get clean" as a separate step
|
||||
community.general.apt_rpm:
|
||||
clean: true
|
||||
|
||||
- name: Perform cache update and complete system upgrade (includes kernel)
|
||||
community.general.apt_rpm:
|
||||
update_cache: true
|
||||
dist_upgrade: true
|
||||
update_kernel: true
|
||||
'''
|
||||
|
||||
import os
|
||||
@@ -84,6 +114,8 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
APT_PATH = "/usr/bin/apt-get"
|
||||
RPM_PATH = "/usr/bin/rpm"
|
||||
APT_GET_ZERO = "\n0 upgraded, 0 newly installed"
|
||||
UPDATE_KERNEL_ZERO = "\nTry to install new kernel "
|
||||
|
||||
|
||||
def query_package(module, name):
|
||||
@@ -104,14 +136,39 @@ def query_package_provides(module, name):
|
||||
|
||||
|
||||
def update_package_db(module):
|
||||
rc, out, err = module.run_command("%s update" % APT_PATH)
|
||||
rc, update_out, err = module.run_command([APT_PATH, "update"], check_rc=True, environ_update={"LANG": "C"})
|
||||
return (False, update_out)
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="could not update package db: %s" % err)
|
||||
|
||||
def dir_size(module, path):
|
||||
total_size = 0
|
||||
for path, dirs, files in os.walk(path):
|
||||
for f in files:
|
||||
total_size += os.path.getsize(os.path.join(path, f))
|
||||
return total_size
|
||||
|
||||
|
||||
def clean(module):
|
||||
t = dir_size(module, "/var/cache/apt/archives")
|
||||
rc, out, err = module.run_command([APT_PATH, "clean"], check_rc=True)
|
||||
return (t != dir_size(module, "/var/cache/apt/archives"), out)
|
||||
|
||||
|
||||
def dist_upgrade(module):
|
||||
rc, out, err = module.run_command([APT_PATH, "-y", "dist-upgrade"], check_rc=True, environ_update={"LANG": "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"})
|
||||
return (UPDATE_KERNEL_ZERO not in out, out)
|
||||
|
||||
|
||||
def remove_packages(module, packages):
|
||||
|
||||
if packages is None:
|
||||
return (False, "Empty package list")
|
||||
|
||||
remove_c = 0
|
||||
# Using a for loop in case of error, we can report the package that failed
|
||||
for package in packages:
|
||||
@@ -119,7 +176,7 @@ def remove_packages(module, packages):
|
||||
if not query_package(module, package):
|
||||
continue
|
||||
|
||||
rc, out, err = module.run_command("%s -y remove %s" % (APT_PATH, package))
|
||||
rc, out, err = module.run_command("%s -y remove %s" % (APT_PATH, package), environ_update={"LANG": "C"})
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(msg="failed to remove %s: %s" % (package, err))
|
||||
@@ -127,13 +184,16 @@ def remove_packages(module, packages):
|
||||
remove_c += 1
|
||||
|
||||
if remove_c > 0:
|
||||
module.exit_json(changed=True, msg="removed %s package(s)" % remove_c)
|
||||
return (True, "removed %s package(s)" % remove_c)
|
||||
|
||||
module.exit_json(changed=False, msg="package(s) already absent")
|
||||
return (False, "package(s) already absent")
|
||||
|
||||
|
||||
def install_packages(module, pkgspec):
|
||||
|
||||
if pkgspec is None:
|
||||
return (False, "Empty package list")
|
||||
|
||||
packages = ""
|
||||
for package in pkgspec:
|
||||
if not query_package_provides(module, package):
|
||||
@@ -141,7 +201,7 @@ def install_packages(module, pkgspec):
|
||||
|
||||
if len(packages) != 0:
|
||||
|
||||
rc, out, err = module.run_command("%s -y install %s" % (APT_PATH, packages))
|
||||
rc, out, err = module.run_command("%s -y install %s" % (APT_PATH, packages), environ_update={"LANG": "C"})
|
||||
|
||||
installed = True
|
||||
for packages in pkgspec:
|
||||
@@ -152,9 +212,9 @@ def install_packages(module, pkgspec):
|
||||
if rc or not installed:
|
||||
module.fail_json(msg="'apt-get -y install %s' failed: %s" % (packages, err))
|
||||
else:
|
||||
module.exit_json(changed=True, msg="%s present(s)" % packages)
|
||||
return (True, "%s present(s)" % packages)
|
||||
else:
|
||||
module.exit_json(changed=False)
|
||||
return (False, "Nothing to install")
|
||||
|
||||
|
||||
def main():
|
||||
@@ -162,7 +222,10 @@ def main():
|
||||
argument_spec=dict(
|
||||
state=dict(type='str', default='present', choices=['absent', 'installed', 'present', 'removed']),
|
||||
update_cache=dict(type='bool', default=False),
|
||||
package=dict(type='list', elements='str', required=True, aliases=['name', 'pkg']),
|
||||
clean=dict(type='bool', default=False),
|
||||
dist_upgrade=dict(type='bool', default=False),
|
||||
update_kernel=dict(type='bool', default=False),
|
||||
package=dict(type='list', elements='str', aliases=['name', 'pkg']),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -170,17 +233,39 @@ def main():
|
||||
module.fail_json(msg="cannot find /usr/bin/apt-get and/or /usr/bin/rpm")
|
||||
|
||||
p = module.params
|
||||
modified = False
|
||||
output = ""
|
||||
|
||||
if p['update_cache']:
|
||||
update_package_db(module)
|
||||
|
||||
if p['clean']:
|
||||
(m, out) = clean(module)
|
||||
modified = modified or m
|
||||
|
||||
if p['dist_upgrade']:
|
||||
(m, out) = dist_upgrade(module)
|
||||
modified = modified or m
|
||||
output += out
|
||||
|
||||
if p['update_kernel']:
|
||||
(m, out) = update_kernel(module)
|
||||
modified = modified or m
|
||||
output += out
|
||||
|
||||
packages = p['package']
|
||||
|
||||
if p['state'] in ['installed', 'present']:
|
||||
install_packages(module, packages)
|
||||
(m, out) = install_packages(module, packages)
|
||||
modified = modified or m
|
||||
output += out
|
||||
|
||||
elif p['state'] in ['absent', 'removed']:
|
||||
remove_packages(module, packages)
|
||||
if p['state'] in ['absent', 'removed']:
|
||||
(m, out) = remove_packages(module, packages)
|
||||
modified = modified or m
|
||||
output += out
|
||||
|
||||
# Return total modification status and output of all commands
|
||||
module.exit_json(changed=modified, msg=output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -198,6 +198,10 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
||||
from ansible.module_utils import six
|
||||
|
||||
try: # python 3.2+
|
||||
from zipfile import BadZipFile # type: ignore[attr-defined]
|
||||
except ImportError: # older python
|
||||
from zipfile import BadZipfile as BadZipFile
|
||||
|
||||
LZMA_IMP_ERR = None
|
||||
if six.PY3:
|
||||
@@ -534,7 +538,7 @@ class ZipArchive(Archive):
|
||||
archive = zipfile.ZipFile(_to_native_ascii(path), 'r')
|
||||
checksums = set((info.filename, info.CRC) for info in archive.infolist())
|
||||
archive.close()
|
||||
except zipfile.BadZipfile:
|
||||
except BadZipFile:
|
||||
checksums = set()
|
||||
return checksums
|
||||
|
||||
@@ -604,7 +608,13 @@ class TarArchive(Archive):
|
||||
# The python implementations of gzip, bz2, and lzma do not support restoring compressed files
|
||||
# to their original names so only file checksum is returned
|
||||
f = self._open_compressed_file(_to_native_ascii(path), 'r')
|
||||
checksums = set([(b'', crc32(f.read()))])
|
||||
checksum = 0
|
||||
while True:
|
||||
chunk = f.read(16 * 1024 * 1024)
|
||||
if not chunk:
|
||||
break
|
||||
checksum = crc32(chunk, checksum)
|
||||
checksums = set([(b'', checksum)])
|
||||
f.close()
|
||||
except Exception:
|
||||
checksums = set()
|
||||
|
||||
@@ -15,7 +15,7 @@ module: awall
|
||||
short_description: Manage awall policies
|
||||
author: Ted Trask (@tdtrask) <ttrask01@yahoo.com>
|
||||
description:
|
||||
- This modules allows for enable/disable/activate of I(awall) policies.
|
||||
- This modules allows for enable/disable/activate of C(awall) policies.
|
||||
- Alpine Wall (I(awall)) generates a firewall configuration from the enabled policy files
|
||||
and activates the configuration on the system.
|
||||
extends_documentation_fragment:
|
||||
@@ -41,8 +41,11 @@ options:
|
||||
description:
|
||||
- Activate the new firewall rules.
|
||||
- Can be run with other steps or on its own.
|
||||
- Idempotency is affected if I(activate=true), as the module will always report a changed state.
|
||||
type: bool
|
||||
default: false
|
||||
notes:
|
||||
- At least one of I(name) and I(activate) is required.
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
109
plugins/modules/btrfs_info.py
Normal file
109
plugins/modules/btrfs_info.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2022, Gregory Furlong <gnfzdz@fzdz.io>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: btrfs_info
|
||||
short_description: Query btrfs filesystem info
|
||||
version_added: "6.6.0"
|
||||
description: Query status of available btrfs filesystems, including uuid, label, subvolumes and mountpoints.
|
||||
|
||||
author:
|
||||
- Gregory Furlong (@gnfzdz)
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
- name: Query information about mounted btrfs filesystems
|
||||
community.general.btrfs_info:
|
||||
register: my_btrfs_info
|
||||
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
||||
filesystems:
|
||||
description: Summaries of the current state for all btrfs filesystems found on the target host.
|
||||
type: list
|
||||
elements: dict
|
||||
returned: success
|
||||
contains:
|
||||
uuid:
|
||||
description: A unique identifier assigned to the filesystem.
|
||||
type: str
|
||||
sample: 96c9c605-1454-49b8-a63a-15e2584c208e
|
||||
label:
|
||||
description: An optional label assigned to the filesystem.
|
||||
type: str
|
||||
sample: Tank
|
||||
devices:
|
||||
description: A list of devices assigned to the filesystem.
|
||||
type: list
|
||||
sample:
|
||||
- /dev/sda1
|
||||
- /dev/sdb1
|
||||
default_subvolume:
|
||||
description: The id of the filesystem's default subvolume.
|
||||
type: int
|
||||
sample: 5
|
||||
subvolumes:
|
||||
description: A list of dicts containing metadata for all of the filesystem's subvolumes.
|
||||
type: list
|
||||
elements: dict
|
||||
contains:
|
||||
id:
|
||||
description: An identifier assigned to the subvolume, unique within the containing filesystem.
|
||||
type: int
|
||||
sample: 256
|
||||
mountpoints:
|
||||
description: Paths where the subvolume is mounted on the targeted host.
|
||||
type: list
|
||||
sample: ['/home']
|
||||
parent:
|
||||
description: The identifier of this subvolume's parent.
|
||||
type: int
|
||||
sample: 5
|
||||
path:
|
||||
description: The full path of the subvolume relative to the btrfs fileystem's root.
|
||||
type: str
|
||||
sample: /@home
|
||||
|
||||
'''
|
||||
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.btrfs import BtrfsFilesystemsProvider
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def run_module():
|
||||
module_args = dict()
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
provider = BtrfsFilesystemsProvider(module)
|
||||
filesystems = [x.get_summary() for x in provider.get_filesystems()]
|
||||
result = {
|
||||
"filesystems": filesystems,
|
||||
}
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
682
plugins/modules/btrfs_subvolume.py
Normal file
682
plugins/modules/btrfs_subvolume.py
Normal file
@@ -0,0 +1,682 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2022, Gregory Furlong <gnfzdz@fzdz.io>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: btrfs_subvolume
|
||||
short_description: Manage btrfs subvolumes
|
||||
version_added: "6.6.0"
|
||||
|
||||
description: Creates, updates and deletes btrfs subvolumes and snapshots.
|
||||
|
||||
options:
|
||||
automount:
|
||||
description:
|
||||
- Allow the module to temporarily mount the targeted btrfs filesystem in order to validate the current state and make any required changes.
|
||||
type: bool
|
||||
default: false
|
||||
default:
|
||||
description:
|
||||
- Make the subvolume specified by I(name) the filesystem's default subvolume.
|
||||
type: bool
|
||||
default: false
|
||||
filesystem_device:
|
||||
description:
|
||||
- A block device contained within the btrfs filesystem to be targeted.
|
||||
- Useful when multiple btrfs filesystems are present to specify which filesystem should be targeted.
|
||||
type: path
|
||||
filesystem_label:
|
||||
description:
|
||||
- A descriptive label assigned to the btrfs filesystem to be targeted.
|
||||
- Useful when multiple btrfs filesystems are present to specify which filesystem should be targeted.
|
||||
type: str
|
||||
filesystem_uuid:
|
||||
description:
|
||||
- A unique identifier assigned to the btrfs filesystem to be targeted.
|
||||
- Useful when multiple btrfs filesystems are present to specify which filesystem should be targeted.
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Name of the subvolume/snapshot to be targeted.
|
||||
required: true
|
||||
type: str
|
||||
recursive:
|
||||
description:
|
||||
- When true, indicates that parent/child subvolumes should be created/removedas necessary
|
||||
to complete the operation (for I(state=present) and I(state=absent) respectively).
|
||||
type: bool
|
||||
default: false
|
||||
snapshot_source:
|
||||
description:
|
||||
- Identifies the source subvolume for the created snapshot.
|
||||
- Infers that the created subvolume is a snapshot.
|
||||
type: str
|
||||
snapshot_conflict:
|
||||
description:
|
||||
- Policy defining behavior when a subvolume already exists at the path of the requested snapshot.
|
||||
- C(skip) - Create a snapshot only if a subvolume does not yet exist at the target location, otherwise indicate that no change is required.
|
||||
Warning, this option does not yet verify that the target subvolume was generated from a snapshot of the requested source.
|
||||
- C(clobber) - If a subvolume already exists at the requested location, delete it first.
|
||||
This option is not idempotent and will result in a new snapshot being generated on every execution.
|
||||
- C(error) - If a subvolume already exists at the requested location, return an error.
|
||||
This option is not idempotent and will result in an error on replay of the module.
|
||||
type: str
|
||||
choices: [ skip, clobber, error ]
|
||||
default: skip
|
||||
state:
|
||||
description:
|
||||
- Indicates the current state of the targeted subvolume.
|
||||
type: str
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
|
||||
notes:
|
||||
- If any or all of the options I(filesystem_device), I(filesystem_label) or I(filesystem_uuid) parameters are provided, there is expected
|
||||
to be a matching btrfs filesystem. If none are provided and only a single btrfs filesystem exists or only a single
|
||||
btrfs filesystem is mounted, that filesystem will be used; otherwise, the module will take no action and return an error.
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
|
||||
attributes:
|
||||
check_mode:
|
||||
support: partial
|
||||
details:
|
||||
- In some scenarios it may erroneously report intermediate subvolumes being created.
|
||||
After mounting, if a directory like file is found where the subvolume would have been created, the operation is skipped.
|
||||
diff_mode:
|
||||
support: none
|
||||
|
||||
author:
|
||||
- Gregory Furlong (@gnfzdz)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
|
||||
- name: Create a @home subvolume under the root subvolume
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@home
|
||||
device: /dev/vda2
|
||||
|
||||
- name: Remove the @home subvolume if it exists
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@home
|
||||
state: absent
|
||||
device: /dev/vda2
|
||||
|
||||
- name: Create a snapshot of the root subvolume named @
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@
|
||||
snapshot_source: /
|
||||
device: /dev/vda2
|
||||
|
||||
- name: Create a snapshot of the root subvolume and make it the new default subvolume
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@
|
||||
snapshot_source: /
|
||||
default: Yes
|
||||
device: /dev/vda2
|
||||
|
||||
- name: Create a snapshot of the /@ subvolume and recursively creating intermediate subvolumes as required
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@snapshots/@2022_06_09
|
||||
snapshot_source: /@
|
||||
recursive: True
|
||||
device: /dev/vda2
|
||||
|
||||
- name: Remove the /@ subvolume and recursively delete child subvolumes as required
|
||||
community.general.btrfs_subvolume:
|
||||
name: /@snapshots/@2022_06_09
|
||||
snapshot_source: /@
|
||||
recursive: True
|
||||
device: /dev/vda2
|
||||
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
||||
filesystem:
|
||||
description:
|
||||
- A summary of the final state of the targeted btrfs filesystem.
|
||||
type: dict
|
||||
returned: success
|
||||
contains:
|
||||
uuid:
|
||||
description: A unique identifier assigned to the filesystem.
|
||||
returned: success
|
||||
type: str
|
||||
sample: 96c9c605-1454-49b8-a63a-15e2584c208e
|
||||
label:
|
||||
description: An optional label assigned to the filesystem.
|
||||
returned: success
|
||||
type: str
|
||||
sample: Tank
|
||||
devices:
|
||||
description: A list of devices assigned to the filesystem.
|
||||
returned: success
|
||||
type: list
|
||||
sample:
|
||||
- /dev/sda1
|
||||
- /dev/sdb1
|
||||
default_subvolume:
|
||||
description: The ID of the filesystem's default subvolume.
|
||||
returned: success and if filesystem is mounted
|
||||
type: int
|
||||
sample: 5
|
||||
subvolumes:
|
||||
description: A list of dicts containing metadata for all of the filesystem's subvolumes.
|
||||
returned: success and if filesystem is mounted
|
||||
type: list
|
||||
elements: dict
|
||||
contains:
|
||||
id:
|
||||
description: An identifier assigned to the subvolume, unique within the containing filesystem.
|
||||
type: int
|
||||
sample: 256
|
||||
mountpoints:
|
||||
description: Paths where the subvolume is mounted on the targeted host.
|
||||
type: list
|
||||
sample: ['/home']
|
||||
parent:
|
||||
description: The identifier of this subvolume's parent.
|
||||
type: int
|
||||
sample: 5
|
||||
path:
|
||||
description: The full path of the subvolume relative to the btrfs fileystem's root.
|
||||
type: str
|
||||
sample: /@home
|
||||
|
||||
modifications:
|
||||
description:
|
||||
- A list where each element describes a change made to the target btrfs filesystem.
|
||||
type: list
|
||||
returned: Success
|
||||
elements: str
|
||||
|
||||
target_subvolume_id:
|
||||
description:
|
||||
- The ID of the subvolume specified with the I(name) parameter, either pre-existing or created as part of module execution.
|
||||
type: int
|
||||
sample: 257
|
||||
returned: Success and subvolume exists after module execution
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.btrfs import BtrfsFilesystemsProvider, BtrfsCommands, BtrfsModuleException
|
||||
from ansible_collections.community.general.plugins.module_utils.btrfs import normalize_subvolume_path
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
|
||||
class BtrfsSubvolumeModule(object):
|
||||
|
||||
__BTRFS_ROOT_SUBVOLUME = '/'
|
||||
__BTRFS_ROOT_SUBVOLUME_ID = 5
|
||||
__BTRFS_SUBVOLUME_INODE_NUMBER = 256
|
||||
|
||||
__CREATE_SUBVOLUME_OPERATION = 'create'
|
||||
__CREATE_SNAPSHOT_OPERATION = 'snapshot'
|
||||
__DELETE_SUBVOLUME_OPERATION = 'delete'
|
||||
__SET_DEFAULT_SUBVOLUME_OPERATION = 'set-default'
|
||||
|
||||
__UNKNOWN_SUBVOLUME_ID = '?'
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.__btrfs_api = BtrfsCommands(module)
|
||||
self.__provider = BtrfsFilesystemsProvider(module)
|
||||
|
||||
# module parameters
|
||||
name = self.module.params['name']
|
||||
self.__name = normalize_subvolume_path(name) if name is not None else None
|
||||
self.__state = self.module.params['state']
|
||||
|
||||
self.__automount = self.module.params['automount']
|
||||
self.__default = self.module.params['default']
|
||||
self.__filesystem_device = self.module.params['filesystem_device']
|
||||
self.__filesystem_label = self.module.params['filesystem_label']
|
||||
self.__filesystem_uuid = self.module.params['filesystem_uuid']
|
||||
self.__recursive = self.module.params['recursive']
|
||||
self.__snapshot_conflict = self.module.params['snapshot_conflict']
|
||||
snapshot_source = self.module.params['snapshot_source']
|
||||
self.__snapshot_source = normalize_subvolume_path(snapshot_source) if snapshot_source is not None else None
|
||||
|
||||
# execution state
|
||||
self.__filesystem = None
|
||||
self.__required_mounts = []
|
||||
self.__unit_of_work = []
|
||||
self.__completed_work = []
|
||||
self.__temporary_mounts = dict()
|
||||
|
||||
def run(self):
|
||||
error = None
|
||||
try:
|
||||
self.__load_filesystem()
|
||||
self.__prepare_unit_of_work()
|
||||
|
||||
if not self.module.check_mode:
|
||||
# check required mounts & mount
|
||||
if len(self.__unit_of_work) > 0:
|
||||
self.__execute_unit_of_work()
|
||||
self.__filesystem.refresh()
|
||||
else:
|
||||
# check required mounts
|
||||
self.__completed_work.extend(self.__unit_of_work)
|
||||
except Exception as e:
|
||||
error = e
|
||||
finally:
|
||||
self.__cleanup_mounts()
|
||||
if self.__filesystem is not None:
|
||||
self.__filesystem.refresh_mountpoints()
|
||||
|
||||
return (error, self.get_results())
|
||||
|
||||
# Identify the targeted filesystem and obtain the current state
|
||||
def __load_filesystem(self):
|
||||
if self.__has_filesystem_criteria():
|
||||
filesystem = self.__find_matching_filesytem()
|
||||
else:
|
||||
filesystem = self.__find_default_filesystem()
|
||||
|
||||
# The filesystem must be mounted to obtain the current state (subvolumes, default, etc)
|
||||
if not filesystem.is_mounted():
|
||||
if not self.__automount:
|
||||
raise BtrfsModuleException(
|
||||
"Target filesystem uuid=%s is not currently mounted and automount=False."
|
||||
"Mount explicitly before module execution or pass automount=True" % filesystem.uuid)
|
||||
elif self.module.check_mode:
|
||||
# TODO is failing the module an appropriate outcome in this scenario?
|
||||
raise BtrfsModuleException(
|
||||
"Target filesystem uuid=%s is not currently mounted. Unable to validate the current"
|
||||
"state while running with check_mode=True" % filesystem.uuid)
|
||||
else:
|
||||
self.__mount_subvolume_id_to_tempdir(filesystem, self.__BTRFS_ROOT_SUBVOLUME_ID)
|
||||
filesystem.refresh()
|
||||
self.__filesystem = filesystem
|
||||
|
||||
def __has_filesystem_criteria(self):
|
||||
return self.__filesystem_uuid is not None or self.__filesystem_label is not None or self.__filesystem_device is not None
|
||||
|
||||
def __find_matching_filesytem(self):
|
||||
criteria = {
|
||||
'uuid': self.__filesystem_uuid,
|
||||
'label': self.__filesystem_label,
|
||||
'device': self.__filesystem_device,
|
||||
}
|
||||
return self.__provider.get_matching_filesystem(criteria)
|
||||
|
||||
def __find_default_filesystem(self):
|
||||
filesystems = self.__provider.get_filesystems()
|
||||
filesystem = None
|
||||
|
||||
if len(filesystems) == 1:
|
||||
filesystem = filesystems[0]
|
||||
else:
|
||||
mounted_filesystems = [x for x in filesystems if x.is_mounted()]
|
||||
if len(mounted_filesystems) == 1:
|
||||
filesystem = mounted_filesystems[0]
|
||||
|
||||
if filesystem is not None:
|
||||
return filesystem
|
||||
else:
|
||||
raise BtrfsModuleException(
|
||||
"Failed to automatically identify targeted filesystem. "
|
||||
"No explicit device indicated and found %d available filesystems." % len(filesystems)
|
||||
)
|
||||
|
||||
# Prepare unit of work
|
||||
def __prepare_unit_of_work(self):
|
||||
if self.__state == "present":
|
||||
if self.__snapshot_source is None:
|
||||
self.__prepare_subvolume_present()
|
||||
else:
|
||||
self.__prepare_snapshot_present()
|
||||
|
||||
if self.__default:
|
||||
self.__prepare_set_default()
|
||||
elif self.__state == "absent":
|
||||
self.__prepare_subvolume_absent()
|
||||
|
||||
def __prepare_subvolume_present(self):
|
||||
subvolume = self.__filesystem.get_subvolume_by_name(self.__name)
|
||||
if subvolume is None:
|
||||
self.__prepare_before_create_subvolume(self.__name)
|
||||
self.__stage_create_subvolume(self.__name)
|
||||
|
||||
def __prepare_before_create_subvolume(self, subvolume_name):
|
||||
closest_parent = self.__filesystem.get_nearest_subvolume(subvolume_name)
|
||||
self.__stage_required_mount(closest_parent)
|
||||
if self.__recursive:
|
||||
self.__prepare_create_intermediates(closest_parent, subvolume_name)
|
||||
|
||||
def __prepare_create_intermediates(self, closest_subvolume, subvolume_name):
|
||||
relative_path = closest_subvolume.get_child_relative_path(self.__name)
|
||||
missing_subvolumes = [x for x in relative_path.split(os.path.sep) if len(x) > 0]
|
||||
if len(missing_subvolumes) > 1:
|
||||
current = closest_subvolume.path
|
||||
for s in missing_subvolumes[:-1]:
|
||||
separator = os.path.sep if current[-1] != os.path.sep else ""
|
||||
current = current + separator + s
|
||||
self.__stage_create_subvolume(current, True)
|
||||
|
||||
def __prepare_snapshot_present(self):
|
||||
source_subvolume = self.__filesystem.get_subvolume_by_name(self.__snapshot_source)
|
||||
subvolume = self.__filesystem.get_subvolume_by_name(self.__name)
|
||||
subvolume_exists = subvolume is not None
|
||||
|
||||
if subvolume_exists:
|
||||
if self.__snapshot_conflict == "skip":
|
||||
# No change required
|
||||
return
|
||||
elif self.__snapshot_conflict == "error":
|
||||
raise BtrfsModuleException("Target subvolume=%s already exists and snapshot_conflict='error'" % self.__name)
|
||||
|
||||
if source_subvolume is None:
|
||||
raise BtrfsModuleException("Source subvolume %s does not exist" % self.__snapshot_source)
|
||||
elif subvolume is not None and source_subvolume.id == subvolume.id:
|
||||
raise BtrfsModuleException("Snapshot source and target are the same.")
|
||||
else:
|
||||
self.__stage_required_mount(source_subvolume)
|
||||
|
||||
if subvolume_exists and self.__snapshot_conflict == "clobber":
|
||||
self.__prepare_delete_subvolume_tree(subvolume)
|
||||
elif not subvolume_exists:
|
||||
self.__prepare_before_create_subvolume(self.__name)
|
||||
|
||||
self.__stage_create_snapshot(source_subvolume, self.__name)
|
||||
|
||||
def __prepare_subvolume_absent(self):
|
||||
subvolume = self.__filesystem.get_subvolume_by_name(self.__name)
|
||||
if subvolume is not None:
|
||||
self.__prepare_delete_subvolume_tree(subvolume)
|
||||
|
||||
def __prepare_delete_subvolume_tree(self, subvolume):
|
||||
if subvolume.is_filesystem_root():
|
||||
raise BtrfsModuleException("Can not delete the filesystem's root subvolume")
|
||||
if not self.__recursive and len(subvolume.get_child_subvolumes()) > 0:
|
||||
raise BtrfsModuleException("Subvolume targeted for deletion %s has children and recursive=False."
|
||||
"Either explicitly delete the child subvolumes first or pass "
|
||||
"parameter recursive=True." % subvolume.path)
|
||||
|
||||
self.__stage_required_mount(subvolume.get_parent_subvolume())
|
||||
queue = self.__prepare_recursive_delete_order(subvolume) if self.__recursive else [subvolume]
|
||||
# prepare unit of work
|
||||
for s in queue:
|
||||
if s.is_mounted():
|
||||
# TODO potentially unmount the subvolume if automount=True ?
|
||||
raise BtrfsModuleException("Can not delete mounted subvolume=%s" % s.path)
|
||||
if s.is_filesystem_default():
|
||||
self.__stage_set_default_subvolume(self.__BTRFS_ROOT_SUBVOLUME, self.__BTRFS_ROOT_SUBVOLUME_ID)
|
||||
self.__stage_delete_subvolume(s)
|
||||
|
||||
def __prepare_recursive_delete_order(self, subvolume):
|
||||
"""Return the subvolume and all descendents as a list, ordered so that descendents always occur before their ancestors"""
|
||||
pending = [subvolume]
|
||||
ordered = []
|
||||
while len(pending) > 0:
|
||||
next = pending.pop()
|
||||
ordered.append(next)
|
||||
pending.extend(next.get_child_subvolumes())
|
||||
ordered.reverse() # reverse to ensure children are deleted before their parent
|
||||
return ordered
|
||||
|
||||
def __prepare_set_default(self):
|
||||
subvolume = self.__filesystem.get_subvolume_by_name(self.__name)
|
||||
subvolume_id = subvolume.id if subvolume is not None else None
|
||||
|
||||
if self.__filesystem.default_subvolid != subvolume_id:
|
||||
self.__stage_set_default_subvolume(self.__name, subvolume_id)
|
||||
|
||||
# Stage operations to the unit of work
|
||||
def __stage_required_mount(self, subvolume):
|
||||
if subvolume.get_mounted_path() is None:
|
||||
if self.__automount:
|
||||
self.__required_mounts.append(subvolume)
|
||||
else:
|
||||
raise BtrfsModuleException("The requested changes will require the subvolume '%s' to be mounted, but automount=False" % subvolume.path)
|
||||
|
||||
def __stage_create_subvolume(self, subvolume_path, intermediate=False):
|
||||
"""
|
||||
Add required creation of an intermediate subvolume to the unit of work
|
||||
If intermediate is true, the action will be skipped if a directory like file is found at target
|
||||
after mounting a parent subvolume
|
||||
"""
|
||||
self.__unit_of_work.append({
|
||||
'action': self.__CREATE_SUBVOLUME_OPERATION,
|
||||
'target': subvolume_path,
|
||||
'intermediate': intermediate,
|
||||
})
|
||||
|
||||
def __stage_create_snapshot(self, source_subvolume, target_subvolume_path):
|
||||
"""Add creation of a snapshot from source to target to the unit of work"""
|
||||
self.__unit_of_work.append({
|
||||
'action': self.__CREATE_SNAPSHOT_OPERATION,
|
||||
'source': source_subvolume.path,
|
||||
'source_id': source_subvolume.id,
|
||||
'target': target_subvolume_path,
|
||||
})
|
||||
|
||||
def __stage_delete_subvolume(self, subvolume):
|
||||
"""Add deletion of the target subvolume to the unit of work"""
|
||||
self.__unit_of_work.append({
|
||||
'action': self.__DELETE_SUBVOLUME_OPERATION,
|
||||
'target': subvolume.path,
|
||||
'target_id': subvolume.id,
|
||||
})
|
||||
|
||||
def __stage_set_default_subvolume(self, subvolume_path, subvolume_id=None):
|
||||
"""Add update of the filesystem's default subvolume to the unit of work"""
|
||||
self.__unit_of_work.append({
|
||||
'action': self.__SET_DEFAULT_SUBVOLUME_OPERATION,
|
||||
'target': subvolume_path,
|
||||
'target_id': subvolume_id,
|
||||
})
|
||||
|
||||
# Execute the unit of work
|
||||
def __execute_unit_of_work(self):
|
||||
self.__check_required_mounts()
|
||||
for op in self.__unit_of_work:
|
||||
if op['action'] == self.__CREATE_SUBVOLUME_OPERATION:
|
||||
self.__execute_create_subvolume(op)
|
||||
elif op['action'] == self.__CREATE_SNAPSHOT_OPERATION:
|
||||
self.__execute_create_snapshot(op)
|
||||
elif op['action'] == self.__DELETE_SUBVOLUME_OPERATION:
|
||||
self.__execute_delete_subvolume(op)
|
||||
elif op['action'] == self.__SET_DEFAULT_SUBVOLUME_OPERATION:
|
||||
self.__execute_set_default_subvolume(op)
|
||||
else:
|
||||
raise ValueError("Unknown operation type '%s'" % op['action'])
|
||||
|
||||
def __execute_create_subvolume(self, operation):
|
||||
target_mounted_path = self.__filesystem.get_mountpath_as_child(operation['target'])
|
||||
if not self.__is_existing_directory_like(target_mounted_path):
|
||||
self.__btrfs_api.subvolume_create(target_mounted_path)
|
||||
self.__completed_work.append(operation)
|
||||
|
||||
def __execute_create_snapshot(self, operation):
|
||||
source_subvolume = self.__filesystem.get_subvolume_by_name(operation['source'])
|
||||
source_mounted_path = source_subvolume.get_mounted_path()
|
||||
target_mounted_path = self.__filesystem.get_mountpath_as_child(operation['target'])
|
||||
|
||||
self.__btrfs_api.subvolume_snapshot(source_mounted_path, target_mounted_path)
|
||||
self.__completed_work.append(operation)
|
||||
|
||||
def __execute_delete_subvolume(self, operation):
|
||||
target_mounted_path = self.__filesystem.get_mountpath_as_child(operation['target'])
|
||||
self.__btrfs_api.subvolume_delete(target_mounted_path)
|
||||
self.__completed_work.append(operation)
|
||||
|
||||
def __execute_set_default_subvolume(self, operation):
|
||||
target = operation['target']
|
||||
target_id = operation['target_id']
|
||||
|
||||
if target_id is None:
|
||||
target_subvolume = self.__filesystem.get_subvolume_by_name(target)
|
||||
|
||||
if target_subvolume is None:
|
||||
self.__filesystem.refresh() # the target may have been created earlier in module execution
|
||||
target_subvolume = self.__filesystem.get_subvolume_by_name(target)
|
||||
|
||||
if target_subvolume is None:
|
||||
raise BtrfsModuleException("Failed to find existing subvolume '%s'" % target)
|
||||
else:
|
||||
target_id = target_subvolume.id
|
||||
|
||||
self.__btrfs_api.subvolume_set_default(self.__filesystem.get_any_mountpoint(), target_id)
|
||||
self.__completed_work.append(operation)
|
||||
|
||||
def __is_existing_directory_like(self, path):
|
||||
return os.path.exists(path) and (
|
||||
os.path.isdir(path) or
|
||||
os.stat(path).st_ino == self.__BTRFS_SUBVOLUME_INODE_NUMBER
|
||||
)
|
||||
|
||||
def __check_required_mounts(self):
|
||||
filtered = self.__filter_child_subvolumes(self.__required_mounts)
|
||||
if len(filtered) > 0:
|
||||
for subvolume in filtered:
|
||||
self.__mount_subvolume_id_to_tempdir(self.__filesystem, subvolume.id)
|
||||
self.__filesystem.refresh_mountpoints()
|
||||
|
||||
def __filter_child_subvolumes(self, subvolumes):
|
||||
"""Filter the provided list of subvolumes to remove any that are a child of another item in the list"""
|
||||
filtered = []
|
||||
last = None
|
||||
ordered = sorted(subvolumes, key=lambda x: x.path)
|
||||
for next in ordered:
|
||||
if last is None or not next.path[0:len(last)] == last:
|
||||
filtered.append(next)
|
||||
last = next.path
|
||||
return filtered
|
||||
|
||||
# Create/cleanup temporary mountpoints
|
||||
def __mount_subvolume_id_to_tempdir(self, filesystem, subvolid):
|
||||
# this check should be redundant
|
||||
if self.module.check_mode or not self.__automount:
|
||||
raise BtrfsModuleException("Unable to temporarily mount required subvolumes"
|
||||
"with automount=%s and check_mode=%s" % (self.__automount, self.module.check_mode))
|
||||
|
||||
cache_key = "%s:%d" % (filesystem.uuid, subvolid)
|
||||
# The subvolume was already mounted, so return the current path
|
||||
if cache_key in self.__temporary_mounts:
|
||||
return self.__temporary_mounts[cache_key]
|
||||
|
||||
device = filesystem.devices[0]
|
||||
mountpoint = tempfile.mkdtemp(dir="/tmp")
|
||||
self.__temporary_mounts[cache_key] = mountpoint
|
||||
|
||||
mount = self.module.get_bin_path("mount", required=True)
|
||||
command = "%s -o noatime,subvolid=%d %s %s " % (mount,
|
||||
subvolid,
|
||||
device,
|
||||
mountpoint)
|
||||
result = self.module.run_command(command, check_rc=True)
|
||||
|
||||
return mountpoint
|
||||
|
||||
def __cleanup_mounts(self):
|
||||
for key in self.__temporary_mounts.keys():
|
||||
self.__cleanup_mount(self.__temporary_mounts[key])
|
||||
|
||||
def __cleanup_mount(self, mountpoint):
|
||||
umount = self.module.get_bin_path("umount", required=True)
|
||||
result = self.module.run_command("%s %s" % (umount, mountpoint))
|
||||
if result[0] == 0:
|
||||
rmdir = self.module.get_bin_path("rmdir", required=True)
|
||||
self.module.run_command("%s %s" % (rmdir, mountpoint))
|
||||
|
||||
# Format and return results
|
||||
def get_results(self):
|
||||
target = self.__filesystem.get_subvolume_by_name(self.__name)
|
||||
return dict(
|
||||
changed=len(self.__completed_work) > 0,
|
||||
filesystem=self.__filesystem.get_summary(),
|
||||
modifications=self.__get_formatted_modifications(),
|
||||
target_subvolume_id=(target.id if target is not None else None)
|
||||
)
|
||||
|
||||
def __get_formatted_modifications(self):
|
||||
return [self.__format_operation_result(op) for op in self.__completed_work]
|
||||
|
||||
def __format_operation_result(self, operation):
|
||||
action_type = operation['action']
|
||||
if action_type == self.__CREATE_SUBVOLUME_OPERATION:
|
||||
return self.__format_create_subvolume_result(operation)
|
||||
elif action_type == self.__CREATE_SNAPSHOT_OPERATION:
|
||||
return self.__format_create_snapshot_result(operation)
|
||||
elif action_type == self.__DELETE_SUBVOLUME_OPERATION:
|
||||
return self.__format_delete_subvolume_result(operation)
|
||||
elif action_type == self.__SET_DEFAULT_SUBVOLUME_OPERATION:
|
||||
return self.__format_set_default_subvolume_result(operation)
|
||||
else:
|
||||
raise ValueError("Unknown operation type '%s'" % operation['action'])
|
||||
|
||||
def __format_create_subvolume_result(self, operation):
|
||||
target = operation['target']
|
||||
target_subvolume = self.__filesystem.get_subvolume_by_name(target)
|
||||
target_id = target_subvolume.id if target_subvolume is not None else self.__UNKNOWN_SUBVOLUME_ID
|
||||
return "Created subvolume '%s' (%s)" % (target, target_id)
|
||||
|
||||
def __format_create_snapshot_result(self, operation):
|
||||
source = operation['source']
|
||||
source_id = operation['source_id']
|
||||
|
||||
target = operation['target']
|
||||
target_subvolume = self.__filesystem.get_subvolume_by_name(target)
|
||||
target_id = target_subvolume.id if target_subvolume is not None else self.__UNKNOWN_SUBVOLUME_ID
|
||||
return "Created snapshot '%s' (%s) from '%s' (%s)" % (target, target_id, source, source_id)
|
||||
|
||||
def __format_delete_subvolume_result(self, operation):
|
||||
target = operation['target']
|
||||
target_id = operation['target_id']
|
||||
return "Deleted subvolume '%s' (%s)" % (target, target_id)
|
||||
|
||||
def __format_set_default_subvolume_result(self, operation):
|
||||
target = operation['target']
|
||||
if 'target_id' in operation:
|
||||
target_id = operation['target_id']
|
||||
else:
|
||||
target_subvolume = self.__filesystem.get_subvolume_by_name(target)
|
||||
target_id = target_subvolume.id if target_subvolume is not None else self.__UNKNOWN_SUBVOLUME_ID
|
||||
return "Updated default subvolume to '%s' (%s)" % (target, target_id)
|
||||
|
||||
|
||||
def run_module():
|
||||
module_args = dict(
|
||||
automount=dict(type='bool', required=False, default=False),
|
||||
default=dict(type='bool', required=False, default=False),
|
||||
filesystem_device=dict(type='path', required=False),
|
||||
filesystem_label=dict(type='str', required=False),
|
||||
filesystem_uuid=dict(type='str', required=False),
|
||||
name=dict(type='str', required=True),
|
||||
recursive=dict(type='bool', default=False),
|
||||
state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
|
||||
snapshot_source=dict(type='str', required=False),
|
||||
snapshot_conflict=dict(type='str', required=False, default='skip', choices=['skip', 'clobber', 'error'])
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
subvolume = BtrfsSubvolumeModule(module)
|
||||
error, result = subvolume.run()
|
||||
if error is not None:
|
||||
module.fail_json(str(error), **result)
|
||||
else:
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -170,10 +170,15 @@ def get_available_options(module, command='install'):
|
||||
return command_help_json['definition']['options']
|
||||
|
||||
|
||||
def composer_command(module, command, arguments="", options=None, global_command=False):
|
||||
def composer_command(module, command, arguments="", options=None):
|
||||
if options is None:
|
||||
options = []
|
||||
|
||||
global_command = module.params['global_command']
|
||||
|
||||
if not global_command:
|
||||
options.extend(['--working-dir', "'%s'" % module.params['working_dir']])
|
||||
|
||||
if module.params['executable'] is None:
|
||||
php_path = module.get_bin_path("php", True, ["/usr/local/bin"])
|
||||
else:
|
||||
@@ -217,7 +222,6 @@ def main():
|
||||
module.fail_json(msg="Use the 'arguments' param for passing arguments with the 'command'")
|
||||
|
||||
arguments = module.params['arguments']
|
||||
global_command = module.params['global_command']
|
||||
available_options = get_available_options(module=module, command=command)
|
||||
|
||||
options = []
|
||||
@@ -234,9 +238,6 @@ def main():
|
||||
option = "--%s" % option
|
||||
options.append(option)
|
||||
|
||||
if not global_command:
|
||||
options.extend(['--working-dir', "'%s'" % module.params['working_dir']])
|
||||
|
||||
option_params = {
|
||||
'prefer_source': 'prefer-source',
|
||||
'prefer_dist': 'prefer-dist',
|
||||
@@ -260,7 +261,7 @@ def main():
|
||||
else:
|
||||
module.exit_json(skipped=True, msg="command '%s' does not support check mode, skipping" % command)
|
||||
|
||||
rc, out, err = composer_command(module, command, arguments, options, global_command)
|
||||
rc, out, err = composer_command(module, command, arguments, options)
|
||||
|
||||
if rc != 0:
|
||||
output = parse_out(err)
|
||||
|
||||
@@ -183,7 +183,7 @@ class CPANMinus(ModuleHelper):
|
||||
if v.name and v.from_path:
|
||||
self.do_raise("Parameters 'name' and 'from_path' are mutually exclusive when 'mode=new'")
|
||||
|
||||
self.command = self.module.get_bin_path(v.executable if v.executable else self.command)
|
||||
self.command = self.get_bin_path(v.executable if v.executable else self.command)
|
||||
self.vars.set("binary", self.command)
|
||||
|
||||
def _is_package_installed(self, name, locallib, version):
|
||||
|
||||
@@ -16,7 +16,7 @@ short_description: Manages Datadog downtimes
|
||||
version_added: 2.0.0
|
||||
description:
|
||||
- Manages downtimes within Datadog.
|
||||
- Options as described on U(https://docs.datadoghq.com/api/v1/downtimes/s).
|
||||
- Options as described on U(https://docs.datadoghq.com/api/v1/downtimes/).
|
||||
author:
|
||||
- Datadog (@Datadog)
|
||||
requirements:
|
||||
@@ -248,7 +248,8 @@ def build_downtime(module):
|
||||
downtime.timezone = module.params["timezone"]
|
||||
if module.params["rrule"]:
|
||||
downtime.recurrence = DowntimeRecurrence(
|
||||
rrule=module.params["rrule"]
|
||||
rrule=module.params["rrule"],
|
||||
type="rrule",
|
||||
)
|
||||
return downtime
|
||||
|
||||
|
||||
@@ -21,11 +21,23 @@ description:
|
||||
- Since C(dconf) requires a running D-Bus session to change values, the module
|
||||
will try to detect an existing session and reuse it, or run the tool via
|
||||
C(dbus-run-session).
|
||||
requirements:
|
||||
- Optionally the C(gi.repository) Python library (usually included in the OS
|
||||
on hosts which have C(dconf)); this will 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 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,
|
||||
that is, Ansible may think that a value is being changed when it is not.
|
||||
This fallback will be removed in a future version of this module, at which
|
||||
point the module will stop working on hosts without C(gi.repository).
|
||||
- Detection of existing, running D-Bus session, required to change settings
|
||||
via C(dconf), is not 100% reliable due to implementation details of D-Bus
|
||||
daemon itself. This might lead to running applications not picking-up
|
||||
@@ -37,8 +49,8 @@ notes:
|
||||
I(value="'myvalue'") - with single quotes as part of the Ansible parameter
|
||||
value.
|
||||
- When using loops in combination with a value like
|
||||
:code:`"[('xkb', 'us'), ('xkb', 'se')]"`, you need to be aware of possible
|
||||
type conversions. Applying a filter :code:`"{{ item.value | string }}"`
|
||||
"[('xkb', 'us'), ('xkb', 'se')]", you need to be aware of possible
|
||||
type conversions. Applying a filter C({{ item.value | string }})
|
||||
to the parameter variable can avoid potential conversion problems.
|
||||
- The easiest way to figure out exact syntax/value you need to provide for a
|
||||
key is by making the configuration change in application affected by the
|
||||
@@ -58,13 +70,18 @@ options:
|
||||
description:
|
||||
- A dconf key to modify or read from the dconf database.
|
||||
value:
|
||||
type: str
|
||||
type: raw
|
||||
required: false
|
||||
description:
|
||||
- Value to set for the specified dconf key. Value should be specified in
|
||||
GVariant format. Due to complexity of this format, it is best to have a
|
||||
look at existing values in the dconf database.
|
||||
- Required for I(state=present).
|
||||
- Although the type is specified as "raw", it should typically be
|
||||
specified as a string. However, boolean values in particular are
|
||||
handled properly even when specified as booleans rather than strings
|
||||
(in fact, handling booleans properly is why the type of this parameter
|
||||
is "raw").
|
||||
state:
|
||||
type: str
|
||||
required: false
|
||||
@@ -126,17 +143,27 @@ EXAMPLES = r"""
|
||||
|
||||
|
||||
import os
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.respawn import (
|
||||
has_respawned,
|
||||
probe_interpreters_for_module,
|
||||
respawn_module,
|
||||
)
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible_collections.community.general.plugins.module_utils import deps
|
||||
|
||||
glib_module_name = 'gi.repository.GLib'
|
||||
|
||||
PSUTIL_IMP_ERR = None
|
||||
try:
|
||||
import psutil
|
||||
HAS_PSUTIL = True
|
||||
from gi.repository.GLib import Variant, GError
|
||||
except ImportError:
|
||||
PSUTIL_IMP_ERR = traceback.format_exc()
|
||||
HAS_PSUTIL = False
|
||||
Variant = None
|
||||
GError = AttributeError
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
with deps.declare("psutil"):
|
||||
import psutil
|
||||
|
||||
|
||||
class DBusWrapper(object):
|
||||
@@ -258,6 +285,29 @@ class DconfPreference(object):
|
||||
# Check if dconf binary exists
|
||||
self.dconf_bin = self.module.get_bin_path('dconf', required=True)
|
||||
|
||||
@staticmethod
|
||||
def variants_are_equal(canonical_value, user_value):
|
||||
"""Compare two string GVariant representations for equality.
|
||||
|
||||
Assumes `canonical_value` is "canonical" in the sense that the type of
|
||||
the variant is specified explicitly if it cannot be inferred; this is
|
||||
true for textual representations of variants generated by the `dconf`
|
||||
command. The type of `canonical_value` is used to parse `user_value`,
|
||||
so the latter does not need to be explicitly typed.
|
||||
|
||||
Returns True if the two values are equal.
|
||||
"""
|
||||
if canonical_value is None:
|
||||
# It's unset in dconf database, so anything the user is trying to
|
||||
# set is a change.
|
||||
return False
|
||||
try:
|
||||
variant1 = Variant.parse(None, canonical_value)
|
||||
variant2 = Variant.parse(variant1.get_type(), user_value)
|
||||
return variant1 == variant2
|
||||
except GError:
|
||||
return canonical_value == user_value
|
||||
|
||||
def read(self, key):
|
||||
"""
|
||||
Retrieves current value associated with the dconf key.
|
||||
@@ -298,7 +348,7 @@ class DconfPreference(object):
|
||||
"""
|
||||
# If no change is needed (or won't be done due to check_mode), notify
|
||||
# caller straight away.
|
||||
if value == self.read(key):
|
||||
if self.variants_are_equal(self.read(key), value):
|
||||
return False
|
||||
elif self.check_mode:
|
||||
return True
|
||||
@@ -312,7 +362,7 @@ class DconfPreference(object):
|
||||
rc, out, err = dbus_wrapper.run_command(command)
|
||||
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg='dconf failed while write the value with error: %s' % err,
|
||||
self.module.fail_json(msg='dconf failed while writing key %s, value %s with error: %s' % (key, value, err),
|
||||
out=out,
|
||||
err=err)
|
||||
|
||||
@@ -364,17 +414,62 @@ def main():
|
||||
argument_spec=dict(
|
||||
state=dict(default='present', choices=['present', 'absent', 'read']),
|
||||
key=dict(required=True, type='str', no_log=False),
|
||||
value=dict(required=False, default=None, type='str'),
|
||||
# Converted to str below after special handling of bool.
|
||||
value=dict(required=False, default=None, type='raw'),
|
||||
),
|
||||
supports_check_mode=True
|
||||
supports_check_mode=True,
|
||||
required_if=[
|
||||
('state', 'present', ['value']),
|
||||
],
|
||||
)
|
||||
|
||||
if not HAS_PSUTIL:
|
||||
module.fail_json(msg=missing_required_lib("psutil"), exception=PSUTIL_IMP_ERR)
|
||||
if Variant is None:
|
||||
# This interpreter can't see the GLib module. To try to fix that, we'll
|
||||
# look in common locations for system-owned interpreters that can see
|
||||
# it; if we find one, we'll respawn under it. Otherwise we'll proceed
|
||||
# with degraded performance, without the ability to parse GVariants.
|
||||
# Later (in a different PR) we'll actually deprecate this degraded
|
||||
# performance level and fail with an error if the library can't be
|
||||
# found.
|
||||
|
||||
# If present state was specified, value must be provided.
|
||||
if module.params['state'] == 'present' and module.params['value'] is None:
|
||||
module.fail_json(msg='State "present" requires "value" to be set.')
|
||||
if has_respawned():
|
||||
# This shouldn't be possible; short-circuit early if it happens.
|
||||
module.fail_json(
|
||||
msg="%s must be installed and visible from %s." %
|
||||
(glib_module_name, sys.executable))
|
||||
|
||||
interpreters = ['/usr/bin/python3', '/usr/bin/python2',
|
||||
'/usr/bin/python']
|
||||
|
||||
interpreter = probe_interpreters_for_module(
|
||||
interpreters, glib_module_name)
|
||||
|
||||
if interpreter:
|
||||
# Found the Python bindings; respawn this module under the
|
||||
# interpreter where we found them.
|
||||
respawn_module(interpreter)
|
||||
# This is the end of the line for this process, it will exit here
|
||||
# once the respawned module has completed.
|
||||
|
||||
# Try to be forgiving about the user specifying a boolean as the value, or
|
||||
# more accurately about the fact that YAML and Ansible are quite insistent
|
||||
# about converting strings that look like booleans into booleans. Convert
|
||||
# the boolean into a string of the type dconf will understand. Any type for
|
||||
# the value other than boolean is just converted into a string directly.
|
||||
if module.params['value'] is not None:
|
||||
if isinstance(module.params['value'], bool):
|
||||
module.params['value'] = 'true' if module.params['value'] else 'false'
|
||||
else:
|
||||
module.params['value'] = to_native(
|
||||
module.params['value'], errors='surrogate_or_strict')
|
||||
|
||||
if Variant is None:
|
||||
module.warn(
|
||||
'WARNING: The gi.repository Python library is not available; '
|
||||
'using string comparison to check value equality. This fallback '
|
||||
'will be deprecated in a future version of community.general.')
|
||||
|
||||
deps.validate(module)
|
||||
|
||||
# Create wrapper instance.
|
||||
dconf = DconfPreference(module, module.check_mode)
|
||||
|
||||
@@ -102,7 +102,7 @@ class EjabberdUser(object):
|
||||
changed. It will return True if the user does not match the supplied
|
||||
credentials and False if it does not
|
||||
"""
|
||||
return self.run_command('check_password', [self.user, self.host, self.pwd])
|
||||
return bool(self.run_command('check_password', [self.user, self.host, self.pwd])[0])
|
||||
|
||||
@property
|
||||
def exists(self):
|
||||
@@ -110,7 +110,7 @@ class EjabberdUser(object):
|
||||
host specified. If the user exists True is returned, otherwise False
|
||||
is returned
|
||||
"""
|
||||
return self.run_command('check_account', [self.user, self.host])
|
||||
return not bool(self.run_command('check_account', [self.user, self.host])[0])
|
||||
|
||||
def log(self, entry):
|
||||
""" This method will log information to the local syslog facility """
|
||||
@@ -122,7 +122,7 @@ class EjabberdUser(object):
|
||||
""" This method will run the any command specified and return the
|
||||
returns using the Ansible common module
|
||||
"""
|
||||
cmd = [self.module.get_bin_path('ejabberdctl'), cmd] + options
|
||||
cmd = [self.module.get_bin_path('ejabberdctl', required=True), cmd] + options
|
||||
self.log('command: %s' % " ".join(cmd))
|
||||
return self.module.run_command(cmd)
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ def uninstall_flat(module, binary, names, method):
|
||||
|
||||
def flatpak_exists(module, binary, names, method):
|
||||
"""Check if the flatpaks are installed."""
|
||||
command = [binary, "list", "--{0}".format(method), "--app"]
|
||||
command = [binary, "list", "--{0}".format(method)]
|
||||
output = _flatpak_command(module, False, command)
|
||||
installed = []
|
||||
not_installed = []
|
||||
|
||||
@@ -227,7 +227,7 @@ class GithubDeployKey(object):
|
||||
yield self.module.from_json(resp.read())
|
||||
|
||||
links = {}
|
||||
for x, y in findall(r'<([^>]+)>;\s*rel="(\w+)"', info["link"]):
|
||||
for x, y in findall(r'<([^>]+)>;\s*rel="(\w+)"', info.get("link", '')):
|
||||
links[y] = x
|
||||
|
||||
url = links.get('next')
|
||||
|
||||
@@ -82,8 +82,14 @@ EXAMPLES = '''
|
||||
name: Access Key for Some Machine
|
||||
token: '{{ github_access_token }}'
|
||||
pubkey: '{{ ssh_pub_key.stdout }}'
|
||||
'''
|
||||
|
||||
# Alternatively, a single task can be used reading a key from a file on the controller
|
||||
- name: Authorize key with GitHub
|
||||
community.general.github_key:
|
||||
name: Access Key for Some Machine
|
||||
token: '{{ github_access_token }}'
|
||||
pubkey: "{{ lookup('ansible.builtin.file', '/home/foo/.ssh/id_rsa.pub') }}"
|
||||
'''
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
@@ -255,7 +255,10 @@ class GitLabGroup(object):
|
||||
return True
|
||||
|
||||
try:
|
||||
group = self._gitlab.groups.create(arguments)
|
||||
# Filter out None values
|
||||
filtered = dict((arg_key, arg_value) for arg_key, arg_value in arguments.items() if arg_value is not None)
|
||||
|
||||
group = self._gitlab.groups.create(filtered)
|
||||
except (gitlab.exceptions.GitlabCreateError) as e:
|
||||
self._module.fail_json(msg="Failed to create group: %s " % to_native(e))
|
||||
|
||||
|
||||
@@ -276,11 +276,11 @@ def main():
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
access_level_int = {
|
||||
'guest': gitlab.GUEST_ACCESS,
|
||||
'reporter': gitlab.REPORTER_ACCESS,
|
||||
'developer': gitlab.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.MAINTAINER_ACCESS,
|
||||
'owner': gitlab.OWNER_ACCESS,
|
||||
'guest': gitlab.const.GUEST_ACCESS,
|
||||
'reporter': gitlab.const.REPORTER_ACCESS,
|
||||
'developer': gitlab.const.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.const.MAINTAINER_ACCESS,
|
||||
'owner': gitlab.const.OWNER_ACCESS,
|
||||
}
|
||||
|
||||
gitlab_group = module.params['gitlab_group']
|
||||
|
||||
@@ -251,6 +251,13 @@ options:
|
||||
type: str
|
||||
choices: ["private", "disabled", "enabled"]
|
||||
version_added: "6.4.0"
|
||||
topics:
|
||||
description:
|
||||
- A topic or list of topics to be assigned to a project.
|
||||
- It is compatible with old GitLab server releases (versions before 14, correspond to C(tag_list)).
|
||||
type: list
|
||||
elements: str
|
||||
version_added: "6.6.0"
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -334,6 +341,8 @@ from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_group, find_project, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
)
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
|
||||
class GitLabProject(object):
|
||||
def __init__(self, module, gitlab_instance):
|
||||
@@ -376,6 +385,14 @@ class GitLabProject(object):
|
||||
'monitor_access_level': options['monitor_access_level'],
|
||||
'security_and_compliance_access_level': options['security_and_compliance_access_level'],
|
||||
}
|
||||
|
||||
# topics was introduced on gitlab >=14 and replace tag_list. We get current gitlab version
|
||||
# and check if less than 14. If yes we use tag_list instead topics
|
||||
if LooseVersion(self._gitlab.version()[0]) < LooseVersion("14"):
|
||||
project_options['tag_list'] = options['topics']
|
||||
else:
|
||||
project_options['topics'] = options['topics']
|
||||
|
||||
# Because we have already call userExists in main()
|
||||
if self.project_object is None:
|
||||
project_options.update({
|
||||
@@ -514,6 +531,7 @@ def main():
|
||||
infrastructure_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
monitor_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
security_and_compliance_access_level=dict(type='str', choices=['private', 'disabled', 'enabled']),
|
||||
topics=dict(type='list', elements='str'),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
@@ -570,6 +588,7 @@ def main():
|
||||
infrastructure_access_level = module.params['infrastructure_access_level']
|
||||
monitor_access_level = module.params['monitor_access_level']
|
||||
security_and_compliance_access_level = module.params['security_and_compliance_access_level']
|
||||
topics = module.params['topics']
|
||||
|
||||
if default_branch and not initialize_with_readme:
|
||||
module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
|
||||
@@ -648,6 +667,7 @@ def main():
|
||||
"infrastructure_access_level": infrastructure_access_level,
|
||||
"monitor_access_level": monitor_access_level,
|
||||
"security_and_compliance_access_level": security_and_compliance_access_level,
|
||||
"topics": topics,
|
||||
}):
|
||||
|
||||
module.exit_json(changed=True, msg="Successfully created or updated the project %s" % project_name, project=gitlab_project.project_object._attrs)
|
||||
|
||||
@@ -282,10 +282,10 @@ def main():
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
access_level_int = {
|
||||
'guest': gitlab.GUEST_ACCESS,
|
||||
'reporter': gitlab.REPORTER_ACCESS,
|
||||
'developer': gitlab.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.MAINTAINER_ACCESS,
|
||||
'guest': gitlab.const.GUEST_ACCESS,
|
||||
'reporter': gitlab.const.REPORTER_ACCESS,
|
||||
'developer': gitlab.const.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.const.MAINTAINER_ACCESS,
|
||||
}
|
||||
|
||||
gitlab_project = module.params['project']
|
||||
|
||||
@@ -94,9 +94,9 @@ class GitlabProtectedBranch(object):
|
||||
self._module = module
|
||||
self.project = self.get_project(project)
|
||||
self.ACCESS_LEVEL = {
|
||||
'nobody': gitlab.NO_ACCESS,
|
||||
'developer': gitlab.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.MAINTAINER_ACCESS
|
||||
'nobody': gitlab.const.NO_ACCESS,
|
||||
'developer': gitlab.const.DEVELOPER_ACCESS,
|
||||
'maintainer': gitlab.const.MAINTAINER_ACCESS
|
||||
}
|
||||
|
||||
def get_project(self, project_name):
|
||||
|
||||
@@ -44,10 +44,17 @@ attributes:
|
||||
support: none
|
||||
|
||||
options:
|
||||
group:
|
||||
description:
|
||||
- ID or full path of the group in the form group/subgroup.
|
||||
- Mutually exclusive with I(owned) and I(project).
|
||||
type: str
|
||||
version_added: '6.5.0'
|
||||
project:
|
||||
description:
|
||||
- ID or full path of the project in the form of group/name.
|
||||
- Mutually exclusive with I(owned) since community.general 4.5.0.
|
||||
- Mutually exclusive with I(group).
|
||||
type: str
|
||||
version_added: '3.7.0'
|
||||
description:
|
||||
@@ -73,6 +80,7 @@ options:
|
||||
description:
|
||||
- Searches only runners available to the user when searching for existing, when false admin token required.
|
||||
- Mutually exclusive with I(project) since community.general 4.5.0.
|
||||
- Mutually exclusive with I(group).
|
||||
default: false
|
||||
type: bool
|
||||
version_added: 2.0.0
|
||||
@@ -209,21 +217,23 @@ except NameError:
|
||||
|
||||
|
||||
class GitLabRunner(object):
|
||||
def __init__(self, module, gitlab_instance, project=None):
|
||||
def __init__(self, module, gitlab_instance, group=None, project=None):
|
||||
self._module = module
|
||||
self._gitlab = gitlab_instance
|
||||
self.runner_object = None
|
||||
|
||||
# Whether to operate on GitLab-instance-wide or project-wide runners
|
||||
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/60774
|
||||
# for group runner token access
|
||||
if project:
|
||||
self._runners_endpoint = project.runners.list
|
||||
elif group:
|
||||
self._runners_endpoint = group.runners.list
|
||||
elif module.params['owned']:
|
||||
self._runners_endpoint = gitlab_instance.runners.list
|
||||
else:
|
||||
self._runners_endpoint = gitlab_instance.runners.all
|
||||
|
||||
self.runner_object = None
|
||||
|
||||
def create_or_update_runner(self, description, options):
|
||||
changed = False
|
||||
|
||||
@@ -234,9 +244,8 @@ class GitLabRunner(object):
|
||||
'maximum_timeout': options['maximum_timeout'],
|
||||
'tag_list': options['tag_list'],
|
||||
}
|
||||
if arguments['access_level'] is not None:
|
||||
if options.get('access_level') is not None:
|
||||
arguments['access_level'] = options['access_level']
|
||||
|
||||
# Because we have already call userExists in main()
|
||||
if self.runner_object is None:
|
||||
arguments['description'] = description
|
||||
@@ -251,7 +260,7 @@ class GitLabRunner(object):
|
||||
access_level_on_creation = False
|
||||
|
||||
if not access_level_on_creation:
|
||||
del arguments['access_level']
|
||||
arguments.pop('access_level', None)
|
||||
|
||||
runner = self.create_runner(arguments)
|
||||
changed = True
|
||||
@@ -361,6 +370,7 @@ def main():
|
||||
maximum_timeout=dict(type='int', default=3600),
|
||||
registration_token=dict(type='str', no_log=True),
|
||||
project=dict(type='str'),
|
||||
group=dict(type='str'),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
))
|
||||
|
||||
@@ -373,6 +383,8 @@ def main():
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
['project', 'owned'],
|
||||
['group', 'owned'],
|
||||
['project', 'group'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
@@ -397,6 +409,7 @@ def main():
|
||||
maximum_timeout = module.params['maximum_timeout']
|
||||
registration_token = module.params['registration_token']
|
||||
project = module.params['project']
|
||||
group = module.params['group']
|
||||
|
||||
if access_level is None:
|
||||
message = "The option 'access_level' is unspecified, so 'ref_protected' is assumed. "\
|
||||
@@ -409,13 +422,20 @@ def main():
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
gitlab_project = None
|
||||
gitlab_group = None
|
||||
|
||||
if project:
|
||||
try:
|
||||
gitlab_project = gitlab_instance.projects.get(project)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
module.fail_json(msg='No such a project %s' % project, exception=to_native(e))
|
||||
elif group:
|
||||
try:
|
||||
gitlab_group = gitlab_instance.groups.get(group)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
module.fail_json(msg='No such a group %s' % group, exception=to_native(e))
|
||||
|
||||
gitlab_runner = GitLabRunner(module, gitlab_instance, gitlab_project)
|
||||
gitlab_runner = GitLabRunner(module, gitlab_instance, gitlab_group, gitlab_project)
|
||||
runner_exists = gitlab_runner.exists_runner(runner_description)
|
||||
|
||||
if state == 'absent':
|
||||
|
||||
@@ -244,12 +244,12 @@ class GitLabUser(object):
|
||||
self._gitlab = gitlab_instance
|
||||
self.user_object = None
|
||||
self.ACCESS_LEVEL = {
|
||||
'guest': gitlab.GUEST_ACCESS,
|
||||
'reporter': gitlab.REPORTER_ACCESS,
|
||||
'developer': gitlab.DEVELOPER_ACCESS,
|
||||
'master': gitlab.MAINTAINER_ACCESS,
|
||||
'maintainer': gitlab.MAINTAINER_ACCESS,
|
||||
'owner': gitlab.OWNER_ACCESS,
|
||||
'guest': gitlab.const.GUEST_ACCESS,
|
||||
'reporter': gitlab.const.REPORTER_ACCESS,
|
||||
'developer': gitlab.const.DEVELOPER_ACCESS,
|
||||
'master': gitlab.const.MAINTAINER_ACCESS,
|
||||
'maintainer': gitlab.const.MAINTAINER_ACCESS,
|
||||
'owner': gitlab.const.OWNER_ACCESS,
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
@@ -78,8 +78,9 @@ options:
|
||||
greedy:
|
||||
description:
|
||||
- Upgrade casks that auto update.
|
||||
- Passes --greedy to brew cask outdated when checking
|
||||
if an installed cask has a newer version available.
|
||||
- Passes C(--greedy) to C(brew outdated --cask) when checking
|
||||
if an installed cask has a newer version available,
|
||||
or to C(brew upgrade --cask) when upgrading all casks.
|
||||
type: bool
|
||||
default: false
|
||||
'''
|
||||
@@ -128,6 +129,11 @@ EXAMPLES = '''
|
||||
community.general.homebrew_cask:
|
||||
upgrade_all: true
|
||||
|
||||
- name: Upgrade all casks with greedy option
|
||||
community.general.homebrew_cask:
|
||||
upgrade_all: true
|
||||
greedy: true
|
||||
|
||||
- name: Upgrade given cask with force option
|
||||
community.general.homebrew_cask:
|
||||
name: alfred
|
||||
@@ -581,6 +587,9 @@ class HomebrewCask(object):
|
||||
else:
|
||||
cmd = [self.brew_path, 'cask', 'upgrade']
|
||||
|
||||
if self.greedy:
|
||||
cmd = cmd + ['--greedy']
|
||||
|
||||
rc, out, err = '', '', ''
|
||||
|
||||
if self.sudo_password:
|
||||
|
||||
@@ -256,9 +256,9 @@ def main():
|
||||
state = module.params["state"]
|
||||
name = module.params["name"]
|
||||
zone = module.params["zone"]
|
||||
template = [name]
|
||||
template = []
|
||||
if module.params["template"]:
|
||||
template.append(module.params["template"])
|
||||
template = [module.params["template"]]
|
||||
check_command = module.params["check_command"]
|
||||
ip = module.params["ip"]
|
||||
display_name = module.params["display_name"]
|
||||
@@ -273,20 +273,18 @@ def main():
|
||||
module.fail_json(msg="unable to connect to Icinga. Exception message: %s" % (e))
|
||||
|
||||
data = {
|
||||
'templates': template,
|
||||
'attrs': {
|
||||
'address': ip,
|
||||
'display_name': display_name,
|
||||
'check_command': check_command,
|
||||
'zone': zone,
|
||||
'vars': {
|
||||
'made_by': "ansible",
|
||||
},
|
||||
'templates': template,
|
||||
'vars.made_by': "ansible"
|
||||
}
|
||||
}
|
||||
|
||||
if variables:
|
||||
data['attrs']['vars'].update(variables)
|
||||
for key, value in variables.items():
|
||||
data['attrs']['vars.' + key] = value
|
||||
|
||||
changed = False
|
||||
if icinga.exists(name):
|
||||
@@ -308,7 +306,7 @@ def main():
|
||||
module.exit_json(changed=False, name=name, data=data)
|
||||
|
||||
# Template attribute is not allowed in modification
|
||||
del data['attrs']['templates']
|
||||
del data['templates']
|
||||
|
||||
ret = icinga.modify(name, data)
|
||||
|
||||
|
||||
@@ -85,6 +85,14 @@ msg:
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Action was successful"
|
||||
return_values:
|
||||
description: Dictionary containing command-specific response data from the action.
|
||||
returned: on success
|
||||
type: dict
|
||||
version_added: 6.6.0
|
||||
sample: {
|
||||
"job_id": "/redfish/v1/Managers/iDRAC.Embedded.1/Jobs/JID_471269252011"
|
||||
}
|
||||
'''
|
||||
|
||||
import re
|
||||
@@ -128,10 +136,9 @@ class IdracRedfishUtils(RedfishUtils):
|
||||
return response
|
||||
|
||||
response_output = response['resp'].__dict__
|
||||
job_id = response_output["headers"]["Location"]
|
||||
job_id = re.search("JID_.+", job_id).group()
|
||||
# Currently not passing job_id back to user but patch is coming
|
||||
return {'ret': True, 'msg': "Config job %s created" % job_id}
|
||||
job_id_full = response_output["headers"]["Location"]
|
||||
job_id = re.search("JID_.+", job_id_full).group()
|
||||
return {'ret': True, 'msg': "Config job %s created" % job_id, 'job_id': job_id_full}
|
||||
|
||||
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
@@ -143,6 +150,7 @@ CATEGORY_COMMANDS_ALL = {
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
return_values = {}
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True),
|
||||
@@ -199,7 +207,20 @@ def main():
|
||||
|
||||
if category == "Systems":
|
||||
# execute only if we find a System resource
|
||||
# NOTE: Currently overriding the usage of 'data_modification' due to
|
||||
# how 'resource_id' is processed. In the case of CreateBiosConfigJob,
|
||||
# we interact with BOTH systems and managers, so you currently cannot
|
||||
# specify a single 'resource_id' to make both '_find_systems_resource'
|
||||
# and '_find_managers_resource' return success. Since
|
||||
# CreateBiosConfigJob doesn't use the matched 'resource_id' for a
|
||||
# system regardless of what's specified, disabling the 'resource_id'
|
||||
# inspection for the next call allows a specific manager to be
|
||||
# specified with 'resource_id'. If we ever need to expand the input
|
||||
# to inspect a specific system and manager in parallel, this will need
|
||||
# updates.
|
||||
rf_utils.data_modification = False
|
||||
result = rf_utils._find_systems_resource()
|
||||
rf_utils.data_modification = True
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
|
||||
@@ -210,11 +231,13 @@ def main():
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
result = rf_utils.create_bios_config_job()
|
||||
if 'job_id' in result:
|
||||
return_values['job_id'] = result['job_id']
|
||||
|
||||
# Return data back or fail with proper message
|
||||
if result['ret'] is True:
|
||||
del result['ret']
|
||||
module.exit_json(changed=True, msg='Action was successful')
|
||||
module.exit_json(changed=True, msg='Action was successful', return_values=return_values)
|
||||
else:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
|
||||
|
||||
175
plugins/modules/ilo_redfish_command.py
Normal file
175
plugins/modules/ilo_redfish_command.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ilo_redfish_command
|
||||
short_description: Manages Out-Of-Band controllers using Redfish APIs
|
||||
version_added: 6.6.0
|
||||
description:
|
||||
- Builds Redfish URIs locally and sends them to remote OOB controllers to
|
||||
perform an action.
|
||||
attributes:
|
||||
check_mode:
|
||||
support: none
|
||||
diff_mode:
|
||||
support: none
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
options:
|
||||
category:
|
||||
required: true
|
||||
description:
|
||||
- Category to execute on OOB controller.
|
||||
type: str
|
||||
choices: ['Systems']
|
||||
command:
|
||||
required: true
|
||||
description:
|
||||
- List of commands to execute on OOB controller.
|
||||
type: list
|
||||
elements: str
|
||||
baseuri:
|
||||
required: true
|
||||
description:
|
||||
- Base URI of OOB controller.
|
||||
type: str
|
||||
username:
|
||||
required: false
|
||||
description:
|
||||
- Username for authenticating to iLO.
|
||||
type: str
|
||||
password:
|
||||
required: false
|
||||
description:
|
||||
- Password for authenticating to iLO.
|
||||
type: str
|
||||
auth_token:
|
||||
required: false
|
||||
description:
|
||||
- Security token for authenticating to iLO.
|
||||
type: str
|
||||
timeout:
|
||||
required: false
|
||||
description:
|
||||
- Timeout in seconds for HTTP requests to iLO.
|
||||
default: 60
|
||||
type: int
|
||||
author:
|
||||
- Varni H P (@varini-hp)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Wait for iLO Reboot Completion
|
||||
community.general.ilo_redfish_command:
|
||||
category: Systems
|
||||
command: WaitforiLORebootCompletion
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
ilo_redfish_command:
|
||||
description: Returns the status of the operation performed on the iLO.
|
||||
type: dict
|
||||
contains:
|
||||
WaitforiLORebootCompletion:
|
||||
description: Returns the output msg and whether the function executed successfully.
|
||||
type: dict
|
||||
contains:
|
||||
ret:
|
||||
description: Return True/False based on whether the operation was performed succesfully.
|
||||
type: bool
|
||||
msg:
|
||||
description: Status of the operation performed on the iLO.
|
||||
type: str
|
||||
returned: always
|
||||
'''
|
||||
|
||||
# More will be added as module features are expanded
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
"Systems": ["WaitforiLORebootCompletion"]
|
||||
}
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True, choices=list(CATEGORY_COMMANDS_ALL.keys())),
|
||||
command=dict(required=True, type='list', elements='str'),
|
||||
baseuri=dict(required=True),
|
||||
timeout=dict(type="int", default=60),
|
||||
username=dict(),
|
||||
password=dict(no_log=True),
|
||||
auth_token=dict(no_log=True)
|
||||
),
|
||||
required_together=[
|
||||
('username', 'password'),
|
||||
],
|
||||
required_one_of=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
mutually_exclusive=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
supports_check_mode=False
|
||||
)
|
||||
|
||||
category = module.params['category']
|
||||
command_list = module.params['command']
|
||||
|
||||
# admin credentials used for authentication
|
||||
creds = {'user': module.params['username'],
|
||||
'pswd': module.params['password'],
|
||||
'token': module.params['auth_token']}
|
||||
|
||||
timeout = module.params['timeout']
|
||||
|
||||
# Build root URI
|
||||
root_uri = "https://" + module.params['baseuri']
|
||||
rf_utils = iLORedfishUtils(creds, root_uri, timeout, module)
|
||||
|
||||
# Check that Category is valid
|
||||
if category not in CATEGORY_COMMANDS_ALL:
|
||||
module.fail_json(msg=to_native(
|
||||
"Invalid Category '%s'. Valid Categories = %s" % (category, list(CATEGORY_COMMANDS_ALL.keys()))))
|
||||
|
||||
# Check that all commands are valid
|
||||
for cmd in command_list:
|
||||
# Fail if even one command given is invalid
|
||||
if cmd not in CATEGORY_COMMANDS_ALL[category]:
|
||||
module.fail_json(
|
||||
msg=to_native("Invalid Command '%s'. Valid Commands = %s" % (cmd, CATEGORY_COMMANDS_ALL[category])))
|
||||
|
||||
if category == "Systems":
|
||||
# execute only if we find a System resource
|
||||
|
||||
result = rf_utils._find_systems_resource()
|
||||
if result['ret'] is False:
|
||||
module.fail_json(msg=to_native(result['msg']))
|
||||
|
||||
for command in command_list:
|
||||
if command == "WaitforiLORebootCompletion":
|
||||
result[command] = rf_utils.wait_for_ilo_reboot_completion()
|
||||
|
||||
# Return data back or fail with proper message
|
||||
if not result[command]['ret']:
|
||||
module.fail_json(msg=result)
|
||||
|
||||
changed = result[command].get('changed', False)
|
||||
module.exit_json(ilo_redfish_command=result, changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -174,8 +174,14 @@ def drop_user(module, client, user_name):
|
||||
def set_user_grants(module, client, user_name, grants):
|
||||
changed = False
|
||||
|
||||
current_grants = []
|
||||
try:
|
||||
current_grants = client.get_list_privileges(user_name)
|
||||
except influx.exceptions.InfluxDBClientError as e:
|
||||
if not module.check_mode or 'user not found' not in e.content:
|
||||
module.fail_json(msg=e.content)
|
||||
|
||||
try:
|
||||
parsed_grants = []
|
||||
# Fix privileges wording
|
||||
for i, v in enumerate(current_grants):
|
||||
|
||||
@@ -42,10 +42,9 @@ options:
|
||||
description:
|
||||
- Section name in INI file. This is added if I(state=present) automatically when
|
||||
a single value is being set.
|
||||
- If left empty or set to C(null), the I(option) will be placed before the first I(section).
|
||||
- If left empty, being omitted, or being set to C(null), the I(option) will be placed before the first I(section).
|
||||
- Using C(null) is also required if the config format does not support sections.
|
||||
type: str
|
||||
required: true
|
||||
option:
|
||||
description:
|
||||
- If set (required for changing a I(value)), this is the name of the option.
|
||||
@@ -317,14 +316,14 @@ def do_ini(module, filename, section=None, option=None, values=None,
|
||||
# override option with no value to option with value if not allow_no_value
|
||||
if len(values) > 0:
|
||||
for index, line in enumerate(section_lines):
|
||||
if not changed_lines[index] and match_active_opt(option, line):
|
||||
if not changed_lines[index] and match_opt(option, line):
|
||||
newline = assignment_format % (option, values.pop(0))
|
||||
(changed, msg) = update_section_line(changed, section_lines, index, changed_lines, newline, msg)
|
||||
if len(values) == 0:
|
||||
break
|
||||
# remove all remaining option occurrences from the rest of the section
|
||||
for index in range(len(section_lines) - 1, 0, -1):
|
||||
if not changed_lines[index] and match_active_opt(option, section_lines[index]):
|
||||
if not changed_lines[index] and match_opt(option, section_lines[index]):
|
||||
del section_lines[index]
|
||||
del changed_lines[index]
|
||||
changed = True
|
||||
@@ -430,7 +429,7 @@ def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
path=dict(type='path', required=True, aliases=['dest']),
|
||||
section=dict(type='str', required=True),
|
||||
section=dict(type='str'),
|
||||
option=dict(type='str'),
|
||||
value=dict(type='str'),
|
||||
values=dict(type='list', elements='str'),
|
||||
|
||||
@@ -156,20 +156,22 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_bytes
|
||||
|
||||
|
||||
def line_dict(line):
|
||||
def lineDict(line):
|
||||
return {'line': line, 'line_type': 'unknown'}
|
||||
|
||||
|
||||
def make_option_dict(line, iface, option, value, address_family):
|
||||
def optionDict(line, iface, option, value, address_family):
|
||||
return {'line': line, 'iface': iface, 'option': option, 'value': value, 'line_type': 'option', 'address_family': address_family}
|
||||
|
||||
|
||||
def get_option_value(line):
|
||||
patt = re.compile(r'^\s+(?P<option>\S+)\s+(?P<value>\S?.*\S)\s*$')
|
||||
match = patt.match(line)
|
||||
if not match:
|
||||
return None, None
|
||||
return match.group("option"), match.group("value")
|
||||
def getValueFromLine(s):
|
||||
spaceRe = re.compile(r'\s+')
|
||||
m = list(spaceRe.finditer(s))[-1]
|
||||
valueEnd = m.start()
|
||||
option = s.split()[0]
|
||||
optionStart = s.find(option)
|
||||
optionLen = len(option)
|
||||
return s[optionLen + optionStart:].strip()
|
||||
|
||||
|
||||
def read_interfaces_file(module, filename):
|
||||
@@ -177,27 +179,32 @@ def read_interfaces_file(module, filename):
|
||||
return read_interfaces_lines(module, f)
|
||||
|
||||
|
||||
def _is_line_processing_none(first_word):
|
||||
return first_word in ("source", "source-dir", "source-directory", "auto", "no-auto-down", "no-scripts") or first_word.startswith("auto-")
|
||||
|
||||
|
||||
def read_interfaces_lines(module, line_strings):
|
||||
lines = []
|
||||
ifaces = {}
|
||||
iface_name = None
|
||||
address_family = None
|
||||
currif = {}
|
||||
currently_processing = None
|
||||
for i, line in enumerate(line_strings):
|
||||
i = 0
|
||||
for line in line_strings:
|
||||
i += 1
|
||||
words = line.split()
|
||||
if not words or words[0].startswith("#"):
|
||||
lines.append(line_dict(line))
|
||||
if len(words) < 1:
|
||||
lines.append(lineDict(line))
|
||||
continue
|
||||
if words[0][0] == "#":
|
||||
lines.append(lineDict(line))
|
||||
continue
|
||||
if words[0] == "mapping":
|
||||
lines.append(line_dict(line))
|
||||
# currmap = calloc(1, sizeof *currmap);
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "MAPPING"
|
||||
elif _is_line_processing_none(words[0]):
|
||||
lines.append(line_dict(line))
|
||||
elif words[0] == "source":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0] == "source-dir":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0] == "source-directory":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0] == "iface":
|
||||
currif = {
|
||||
@@ -220,25 +227,57 @@ def read_interfaces_lines(module, line_strings):
|
||||
ifaces[iface_name] = currif
|
||||
lines.append({'line': line, 'iface': iface_name, 'line_type': 'iface', 'params': currif, 'address_family': address_family})
|
||||
currently_processing = "IFACE"
|
||||
elif words[0] == "auto":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0].startswith("allow-"):
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0] == "no-auto-down":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
elif words[0] == "no-scripts":
|
||||
lines.append(lineDict(line))
|
||||
currently_processing = "NONE"
|
||||
else:
|
||||
if currently_processing == "IFACE":
|
||||
option_name, value = get_option_value(line)
|
||||
# TODO: if option_name in currif.options
|
||||
lines.append(make_option_dict(line, iface_name, option_name, value, address_family))
|
||||
option_name = words[0]
|
||||
value = getValueFromLine(line)
|
||||
lines.append(optionDict(line, iface_name, option_name, value, address_family))
|
||||
if option_name in ["pre-up", "up", "down", "post-up"]:
|
||||
currif[option_name].append(value)
|
||||
else:
|
||||
currif[option_name] = value
|
||||
elif currently_processing == "MAPPING":
|
||||
lines.append(line_dict(line))
|
||||
lines.append(lineDict(line))
|
||||
elif currently_processing == "NONE":
|
||||
lines.append(line_dict(line))
|
||||
lines.append(lineDict(line))
|
||||
else:
|
||||
module.fail_json(msg="misplaced option %s in line %d" % (line, i + 1))
|
||||
|
||||
module.fail_json(msg="misplaced option %s in line %d" % (line, i))
|
||||
return None, None
|
||||
return lines, ifaces
|
||||
|
||||
|
||||
def get_interface_options(iface_lines):
|
||||
return [i for i in iface_lines if i['line_type'] == 'option']
|
||||
|
||||
|
||||
def get_target_options(iface_options, option):
|
||||
return [i for i in iface_options if i['option'] == option]
|
||||
|
||||
|
||||
def update_existing_option_line(target_option, value):
|
||||
old_line = target_option['line']
|
||||
old_value = target_option['value']
|
||||
prefix_start = old_line.find(target_option["option"])
|
||||
optionLen = len(target_option["option"])
|
||||
old_value_position = re.search(r"\s+".join(map(re.escape, old_value.split())), old_line[prefix_start + optionLen:])
|
||||
start = old_value_position.start() + prefix_start + optionLen
|
||||
end = old_value_position.end() + prefix_start + optionLen
|
||||
line = old_line[:start] + value + old_line[end:]
|
||||
return line
|
||||
|
||||
|
||||
def set_interface_option(module, lines, iface, option, raw_value, state, address_family=None):
|
||||
value = str(raw_value)
|
||||
changed = False
|
||||
@@ -248,41 +287,35 @@ def set_interface_option(module, lines, iface, option, raw_value, state, address
|
||||
iface_lines = [item for item in iface_lines
|
||||
if "address_family" in item and item["address_family"] == address_family]
|
||||
|
||||
if not iface_lines:
|
||||
if len(iface_lines) < 1:
|
||||
# interface not found
|
||||
module.fail_json(msg="Error: interface %s not found" % iface)
|
||||
return changed, None
|
||||
|
||||
iface_options = [il for il in iface_lines if il['line_type'] == 'option']
|
||||
target_options = [io for io in iface_options if io['option'] == option]
|
||||
iface_options = get_interface_options(iface_lines)
|
||||
target_options = get_target_options(iface_options, option)
|
||||
|
||||
if state == "present":
|
||||
if not target_options:
|
||||
if len(target_options) < 1:
|
||||
changed = True
|
||||
# add new option
|
||||
last_line_dict = iface_lines[-1]
|
||||
return add_option_after_line(option, value, iface, lines, last_line_dict, iface_options, address_family)
|
||||
|
||||
if option in ["pre-up", "up", "down", "post-up"] and all(ito['value'] != value for ito in target_options):
|
||||
return add_option_after_line(option, value, iface, lines, target_options[-1], iface_options, address_family)
|
||||
|
||||
# if more than one option found edit the last one
|
||||
if target_options[-1]['value'] != value:
|
||||
changed = True
|
||||
target_option = target_options[-1]
|
||||
old_line = target_option['line']
|
||||
old_value = target_option['value']
|
||||
address_family = target_option['address_family']
|
||||
prefix_start = old_line.find(option)
|
||||
option_len = len(option)
|
||||
old_value_position = re.search(r"\s+".join(map(re.escape, old_value.split())), old_line[prefix_start + option_len:])
|
||||
start = old_value_position.start() + prefix_start + option_len
|
||||
end = old_value_position.end() + prefix_start + option_len
|
||||
line = old_line[:start] + value + old_line[end:]
|
||||
index = len(lines) - lines[::-1].index(target_option) - 1
|
||||
lines[index] = make_option_dict(line, iface, option, value, address_family)
|
||||
return changed, lines
|
||||
|
||||
if state == "absent":
|
||||
if target_options:
|
||||
changed, lines = addOptionAfterLine(option, value, iface, lines, last_line_dict, iface_options, address_family)
|
||||
else:
|
||||
if option in ["pre-up", "up", "down", "post-up"]:
|
||||
if len(list(filter(lambda i: i['value'] == value, target_options))) < 1:
|
||||
changed, lines = addOptionAfterLine(option, value, iface, lines, target_options[-1], iface_options, address_family)
|
||||
else:
|
||||
# if more than one option found edit the last one
|
||||
if target_options[-1]['value'] != value:
|
||||
changed = True
|
||||
target_option = target_options[-1]
|
||||
line = update_existing_option_line(target_option, value)
|
||||
address_family = target_option['address_family']
|
||||
index = len(lines) - lines[::-1].index(target_option) - 1
|
||||
lines[index] = optionDict(line, iface, option, value, address_family)
|
||||
elif state == "absent":
|
||||
if len(target_options) >= 1:
|
||||
if option in ["pre-up", "up", "down", "post-up"] and value is not None and value != "None":
|
||||
for target_option in [ito for ito in target_options if ito['value'] == value]:
|
||||
changed = True
|
||||
@@ -291,11 +324,13 @@ def set_interface_option(module, lines, iface, option, raw_value, state, address
|
||||
changed = True
|
||||
for target_option in target_options:
|
||||
lines = [ln for ln in lines if ln != target_option]
|
||||
else:
|
||||
module.fail_json(msg="Error: unsupported state %s, has to be either present or absent" % state)
|
||||
|
||||
return changed, lines
|
||||
|
||||
|
||||
def add_option_after_line(option, value, iface, lines, last_line_dict, iface_options, address_family):
|
||||
def addOptionAfterLine(option, value, iface, lines, last_line_dict, iface_options, address_family):
|
||||
# Changing method of interface is not an addition
|
||||
if option == 'method':
|
||||
changed = False
|
||||
@@ -311,18 +346,19 @@ def add_option_after_line(option, value, iface, lines, last_line_dict, iface_opt
|
||||
suffix_start = last_line.rfind(last_line.split()[-1]) + len(last_line.split()[-1])
|
||||
prefix = last_line[:prefix_start]
|
||||
|
||||
if not iface_options:
|
||||
if len(iface_options) < 1:
|
||||
# interface has no options, ident
|
||||
prefix += " "
|
||||
|
||||
line = prefix + "%s %s" % (option, value) + last_line[suffix_start:]
|
||||
option_dict = make_option_dict(line, iface, option, value, address_family)
|
||||
option_dict = optionDict(line, iface, option, value, address_family)
|
||||
index = len(lines) - lines[::-1].index(last_line_dict)
|
||||
lines.insert(index, option_dict)
|
||||
return True, lines
|
||||
|
||||
|
||||
def write_changes(module, lines, dest):
|
||||
|
||||
tmpfd, tmpfile = tempfile.mkstemp()
|
||||
with os.fdopen(tmpfd, 'wb') as f:
|
||||
f.write(to_bytes(''.join(lines), errors='surrogate_or_strict'))
|
||||
|
||||
@@ -59,7 +59,7 @@ options:
|
||||
record_values:
|
||||
description:
|
||||
- Manage DNS record name with this value.
|
||||
- Mutually exclusive with I(record_values), and exactly one of I(record_value) and I(record_values) has to be specified.
|
||||
- Mutually exclusive with I(record_value), and exactly one of I(record_value) and I(record_values) has to be specified.
|
||||
- In the case of 'A' or 'AAAA' record types, this will be the IP address.
|
||||
- In the case of 'A6' record type, this will be the A6 Record data.
|
||||
- In the case of 'CNAME' record type, this will be the hostname.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user